--- a/Makefile Sat Jun 13 20:14:22 2015 +0900
+++ b/Makefile Mon Jun 15 13:31:22 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 Mon Jun 15 13:31:22 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 Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/buildrpm Mon Jun 15 13:31:22 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
--- a/contrib/check-code.py Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/check-code.py Mon Jun 15 13:31:22 2015 -0500
@@ -217,14 +217,6 @@
(r'(\w|\)),\w', "missing whitespace after ,"),
(r'(\w|\))[+/*\-<>]\w', "missing whitespace in expression"),
(r'^\s+(\w|\.)+=\w[^,()\n]*$', "missing whitespace in assignment"),
- (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)(\1except.*?:\n'
- r'((?:\n|\1\s.*\n)+?))+\1finally:',
- 'no try/except/finally in Python 2.4'),
- (r'(?<!def)(\s+|^|\()next\(.+\)',
- 'no next(foo) in Python 2.4 and 2.5, use foo.next() instead'),
- (r'(\s+)try:\n((?:\n|\1\s.*\n)*?)\1\s*yield\b.*?'
- r'((?:\n|\1\s.*\n)+?)\1finally:',
- 'no yield inside try/finally in Python 2.4'),
(r'.{81}', "line too long"),
(r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
(r'[^\n]\Z', "no trailing newline"),
@@ -237,8 +229,9 @@
"linebreak after :"),
(r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
(r'class\s[^( \n]+\(\):',
- "class foo() not available in Python 2.4, use class foo(object)"),
- (r'\b(%s)\(' % '|'.join(keyword.kwlist),
+ "class foo() creates old style object, use class foo(object)"),
+ (r'\b(%s)\(' % '|'.join(k for k in keyword.kwlist
+ if k not in ('print', 'exec')),
"Python keyword is not a function"),
(r',]', "unneeded trailing ',' in list"),
# (r'class\s[A-Z][^\(]*\((?!Exception)',
@@ -246,14 +239,7 @@
# (r'in range\(', "use xrange"),
# (r'^\s*print\s+', "avoid using print in core and extensions"),
(r'[\x80-\xff]', "non-ASCII character literal"),
- (r'("\')\.format\(', "str.format() not available in Python 2.4"),
- (r'^\s*with\s+', "with not available in Python 2.4"),
- (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
- (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
- (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
- (r'(?<!def)\s+(any|all|format)\(',
- "any/all/format not available in Python 2.4", 'no-py24'),
- (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
+ (r'("\')\.format\(', "str.format() has no bytes counterpart, use %"),
(r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
"gratuitous whitespace after Python keyword"),
(r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
@@ -280,8 +266,6 @@
'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
(r'opener\([^)]*\).read\(',
"use opener.read() instead"),
- (r'BaseException', 'not in Python 2.4, use Exception'),
- (r'os\.path\.relpath', 'os.path.relpath is not in Python 2.5'),
(r'opener\([^)]*\).write\(',
"use opener.write() instead"),
(r'[\s\(](open|file)\([^)]*\)\.read\(',
--- a/contrib/check-commit Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/check-commit Mon Jun 15 13:31:22 2015 -0500
@@ -27,9 +27,9 @@
(r"^# .*\n[A-Z][a-z]\S+", "don't capitalize summary lines"),
(r"^# .*\n[^\n]*: *[A-Z][a-z]\S+", "don't capitalize summary lines"),
(r"^# .*\n.*\.\s+$", "don't add trailing period on summary line"),
- (r"^# .*\n.{78,}", "summary line too long"),
+ (r"^# .*\n.{78,}", "summary line too long (limit is 78)"),
(r"^\+\n \n", "adds double empty line"),
- (r"\+\s+def [a-z]+_[a-z]", "adds a function with foo_bar naming"),
+ (r"^\+[ \t]+def [a-z]+_[a-z]", "adds a function with foo_bar naming"),
]
node = os.environ.get("HG_NODE")
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/debian/control Mon Jun 15 13:31:22 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 Mon Jun 15 13:31:22 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 Mon Jun 15 13:31:22 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 Mon Jun 15 13:31:22 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 Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/dockerrpm Mon Jun 15 13:31:22 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 $*
--- a/contrib/hg-ssh Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/hg-ssh Mon Jun 15 13:31:22 2015 -0500
@@ -64,7 +64,7 @@
if readonly:
cmd += [
'--config',
- 'hooks.prechangegroup.hg-ssh=python:__main__.rejectpush',
+ 'hooks.pretxnopen.hg-ssh=python:__main__.rejectpush',
'--config',
'hooks.prepushkey.hg-ssh=python:__main__.rejectpush'
]
--- a/contrib/import-checker.py Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/import-checker.py Mon Jun 15 13:31:22 2015 -0500
@@ -26,6 +26,72 @@
return '.'.join(p for p in parts if p != 'pure')
return '.'.join(parts)
+def fromlocalfunc(modulename, localmods):
+ """Get a function to examine which locally defined module the
+ target source imports via a specified name.
+
+ `modulename` is an `dotted_name_of_path()`-ed source file path,
+ which may have `.__init__` at the end of it, of the target source.
+
+ `localmods` is a dict (or set), of which key is an absolute
+ `dotted_name_of_path()`-ed source file path of locally defined (=
+ Mercurial specific) modules.
+
+ This function assumes that module names not existing in
+ `localmods` are ones of Python standard libarary.
+
+ This function returns the function, which takes `name` argument,
+ and returns `(absname, dottedpath, hassubmod)` tuple if `name`
+ matches against locally defined module. Otherwise, it returns
+ False.
+
+ It is assumed that `name` doesn't have `.__init__`.
+
+ `absname` is an absolute module name of specified `name`
+ (e.g. "hgext.convert"). This can be used to compose prefix for sub
+ modules or so.
+
+ `dottedpath` is a `dotted_name_of_path()`-ed source file path
+ (e.g. "hgext.convert.__init__") of `name`. This is used to look
+ module up in `localmods` again.
+
+ `hassubmod` is whether it may have sub modules under it (for
+ convenient, even though this is also equivalent to "absname !=
+ dottednpath")
+
+ >>> localmods = {'foo.__init__': True, 'foo.foo1': True,
+ ... 'foo.bar.__init__': True, 'foo.bar.bar1': True,
+ ... 'baz.__init__': True, 'baz.baz1': True }
+ >>> fromlocal = fromlocalfunc('foo.xxx', localmods)
+ >>> # relative
+ >>> fromlocal('foo1')
+ ('foo.foo1', 'foo.foo1', False)
+ >>> fromlocal('bar')
+ ('foo.bar', 'foo.bar.__init__', True)
+ >>> fromlocal('bar.bar1')
+ ('foo.bar.bar1', 'foo.bar.bar1', False)
+ >>> # absolute
+ >>> fromlocal('baz')
+ ('baz', 'baz.__init__', True)
+ >>> fromlocal('baz.baz1')
+ ('baz.baz1', 'baz.baz1', False)
+ >>> # unknown = maybe standard library
+ >>> fromlocal('os')
+ False
+ """
+ prefix = '.'.join(modulename.split('.')[:-1])
+ if prefix:
+ prefix += '.'
+ def fromlocal(name):
+ # check relative name at first
+ for n in prefix + name, name:
+ if n in localmods:
+ return (n, n, False)
+ dottedpath = n + '.__init__'
+ if dottedpath in localmods:
+ return (n, dottedpath, True)
+ return False
+ return fromlocal
def list_stdlib_modules():
"""List the modules present in the stdlib.
@@ -104,38 +170,94 @@
stdlib_modules = set(list_stdlib_modules())
-def imported_modules(source, ignore_nested=False):
+def imported_modules(source, modulename, localmods, ignore_nested=False):
"""Given the source of a file as a string, yield the names
imported by that file.
Args:
source: The python source to examine as a string.
+ modulename: of specified python source (may have `__init__`)
+ localmods: dict of locally defined module names (may have `__init__`)
ignore_nested: If true, import statements that do not start in
column zero will be ignored.
Returns:
- A list of module names imported by the given source.
+ A list of absolute module names imported by the given source.
+ >>> modulename = 'foo.xxx'
+ >>> localmods = {'foo.__init__': True,
+ ... 'foo.foo1': True, 'foo.foo2': True,
+ ... 'foo.bar.__init__': True, 'foo.bar.bar1': True,
+ ... 'baz.__init__': True, 'baz.baz1': True }
+ >>> # standard library (= not locally defined ones)
+ >>> sorted(imported_modules(
+ ... 'from stdlib1 import foo, bar; import stdlib2',
+ ... modulename, localmods))
+ []
+ >>> # relative importing
>>> sorted(imported_modules(
- ... 'import foo ; from baz import bar; import foo.qux'))
- ['baz.bar', 'foo', 'foo.qux']
+ ... 'import foo1; from bar import bar1',
+ ... modulename, localmods))
+ ['foo.bar.__init__', 'foo.bar.bar1', 'foo.foo1']
+ >>> sorted(imported_modules(
+ ... 'from bar.bar1 import name1, name2, name3',
+ ... modulename, localmods))
+ ['foo.bar.bar1']
+ >>> # absolute importing
+ >>> sorted(imported_modules(
+ ... 'from baz import baz1, name1',
+ ... modulename, localmods))
+ ['baz.__init__', 'baz.baz1']
+ >>> # mixed importing, even though it shouldn't be recommended
+ >>> sorted(imported_modules(
+ ... 'import stdlib, foo1, baz',
+ ... modulename, localmods))
+ ['baz.__init__', 'foo.foo1']
+ >>> # ignore_nested
>>> sorted(imported_modules(
... '''import foo
... def wat():
... import bar
- ... ''', ignore_nested=True))
- ['foo']
+ ... ''', modulename, localmods))
+ ['foo.__init__', 'foo.bar.__init__']
+ >>> sorted(imported_modules(
+ ... '''import foo
+ ... def wat():
+ ... import bar
+ ... ''', modulename, localmods, ignore_nested=True))
+ ['foo.__init__']
"""
+ fromlocal = fromlocalfunc(modulename, localmods)
for node in ast.walk(ast.parse(source)):
if ignore_nested and getattr(node, 'col_offset', 0) > 0:
continue
if isinstance(node, ast.Import):
for n in node.names:
- yield n.name
+ found = fromlocal(n.name)
+ if not found:
+ # this should import standard library
+ continue
+ yield found[1]
elif isinstance(node, ast.ImportFrom):
- prefix = node.module + '.'
+ found = fromlocal(node.module)
+ if not found:
+ # this should import standard library
+ continue
+
+ absname, dottedpath, hassubmod = found
+ yield dottedpath
+ if not hassubmod:
+ # examination of "node.names" should be redundant
+ # e.g.: from mercurial.node import nullid, nullrev
+ continue
+
+ prefix = absname + '.'
for n in node.names:
- yield prefix + n.name
+ found = fromlocal(prefix + n.name)
+ if not found:
+ # this should be a function or a property of "node.module"
+ continue
+ yield found[1]
def verify_stdlib_on_own_line(source):
"""Given some python source, verify that stdlib imports are done
@@ -171,8 +293,6 @@
while visit:
path = visit.pop(0)
for i in sorted(imports.get(path[-1], [])):
- if i not in stdlib_modules and not i.startswith('mercurial.'):
- i = mod.rsplit('.', 1)[0] + '.' + i
if len(path) < shortest.get(i, 1000):
shortest[i] = len(path)
if i in path:
@@ -194,10 +314,12 @@
def find_cycles(imports):
"""Find cycles in an already-loaded import graph.
- >>> imports = {'top.foo': ['bar', 'os.path', 'qux'],
- ... 'top.bar': ['baz', 'sys'],
- ... 'top.baz': ['foo'],
- ... 'top.qux': ['foo']}
+ All module names recorded in `imports` should be absolute one.
+
+ >>> imports = {'top.foo': ['top.bar', 'os.path', 'top.qux'],
+ ... 'top.bar': ['top.baz', 'sys'],
+ ... 'top.baz': ['top.foo'],
+ ... 'top.qux': ['top.foo']}
>>> print '\\n'.join(sorted(find_cycles(imports)))
top.bar -> top.baz -> top.foo -> top.bar
top.foo -> top.qux -> top.foo
@@ -215,17 +337,23 @@
return len(c), c
def main(argv):
- if len(argv) < 2:
- print 'Usage: %s file [file] [file] ...'
+ if len(argv) < 2 or (argv[1] == '-' and len(argv) > 2):
+ print 'Usage: %s {-|file [file] [file] ...}'
return 1
+ if argv[1] == '-':
+ argv = argv[:1]
+ argv.extend(l.rstrip() for l in sys.stdin.readlines())
+ localmods = {}
used_imports = {}
any_errors = False
for source_path in argv[1:]:
+ modname = dotted_name_of_path(source_path, trimpure=True)
+ localmods[modname] = source_path
+ for modname, source_path in sorted(localmods.iteritems()):
f = open(source_path)
- modname = dotted_name_of_path(source_path, trimpure=True)
src = f.read()
used_imports[modname] = sorted(
- imported_modules(src, ignore_nested=True))
+ imported_modules(src, modname, localmods, ignore_nested=True))
for error in verify_stdlib_on_own_line(src):
any_errors = True
print source_path, error
--- a/contrib/mercurial.spec Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/mercurial.spec Mon Jun 15 13:31:22 2015 -0500
@@ -37,8 +37,8 @@
%if "%{?withpython}"
BuildRequires: readline-devel, openssl-devel, ncurses-devel, zlib-devel, bzip2-devel
%else
-BuildRequires: python >= 2.4, python-devel, python-docutils >= 0.5
-Requires: python >= 2.4
+BuildRequires: python >= 2.6, python-devel, python-docutils >= 0.5
+Requires: python >= 2.6
%endif
# The hgk extension uses the wish tcl interpreter, but we don't enforce it
#Requires: tk
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/contrib/packagelib.sh Mon Jun 15 13:31:22 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/perf.py Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/perf.py Mon Jun 15 13:31:22 2015 -0500
@@ -6,6 +6,8 @@
import time, os, sys
import functools
+formatteropts = commands.formatteropts
+
cmdtable = {}
command = cmdutil.command(cmdtable)
@@ -60,9 +62,9 @@
fm.write('count', ' (best of %d)', count)
fm.plain('\n')
-@command('perfwalk')
-def perfwalk(ui, repo, *pats):
- timer, fm = gettimer(ui)
+@command('perfwalk', formatteropts)
+def perfwalk(ui, repo, *pats, **opts):
+ timer, fm = gettimer(ui, opts)
try:
m = scmutil.match(repo[None], pats, {})
timer(lambda: len(list(repo.dirstate.walk(m, [], True, False))))
@@ -74,27 +76,27 @@
timer(lambda: len(list(cmdutil.walk(repo, pats, {}))))
fm.end()
-@command('perfannotate')
-def perfannotate(ui, repo, f):
- timer, fm = gettimer(ui)
+@command('perfannotate', formatteropts)
+def perfannotate(ui, repo, f, **opts):
+ timer, fm = gettimer(ui, opts)
fc = repo['.'][f]
timer(lambda: len(fc.annotate(True)))
fm.end()
@command('perfstatus',
[('u', 'unknown', False,
- 'ask status to look for unknown files')])
+ 'ask status to look for unknown files')] + formatteropts)
def perfstatus(ui, repo, **opts):
#m = match.always(repo.root, repo.getcwd())
#timer(lambda: sum(map(len, repo.dirstate.status(m, [], False, False,
# False))))
- timer, fm = gettimer(ui)
- timer(lambda: sum(map(len, repo.status(**opts))))
+ timer, fm = gettimer(ui, **opts)
+ timer(lambda: sum(map(len, repo.status(unknown=opts['unknown']))))
fm.end()
-@command('perfaddremove')
-def perfaddremove(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfaddremove', formatteropts)
+def perfaddremove(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
try:
oldquiet = repo.ui.quiet
repo.ui.quiet = True
@@ -113,9 +115,9 @@
cl._nodecache = {nullid: nullrev}
cl._nodepos = None
-@command('perfheads')
-def perfheads(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfheads', formatteropts)
+def perfheads(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
cl = repo.changelog
def d():
len(cl.headrevs())
@@ -123,11 +125,11 @@
timer(d)
fm.end()
-@command('perftags')
-def perftags(ui, repo):
+@command('perftags', formatteropts)
+def perftags(ui, repo, **opts):
import mercurial.changelog
import mercurial.manifest
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
def t():
repo.changelog = mercurial.changelog.changelog(repo.svfs)
repo.manifest = mercurial.manifest.manifest(repo.svfs)
@@ -136,9 +138,9 @@
timer(t)
fm.end()
-@command('perfancestors')
-def perfancestors(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfancestors', formatteropts)
+def perfancestors(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
heads = repo.changelog.headrevs()
def d():
for a in repo.changelog.ancestors(heads):
@@ -146,9 +148,9 @@
timer(d)
fm.end()
-@command('perfancestorset')
-def perfancestorset(ui, repo, revset):
- timer, fm = gettimer(ui)
+@command('perfancestorset', formatteropts)
+def perfancestorset(ui, repo, revset, **opts):
+ timer, fm = gettimer(ui, opts)
revs = repo.revs(revset)
heads = repo.changelog.headrevs()
def d():
@@ -158,9 +160,9 @@
timer(d)
fm.end()
-@command('perfdirs')
-def perfdirs(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfdirs', formatteropts)
+def perfdirs(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
dirstate = repo.dirstate
'a' in dirstate
def d():
@@ -169,9 +171,9 @@
timer(d)
fm.end()
-@command('perfdirstate')
-def perfdirstate(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfdirstate', formatteropts)
+def perfdirstate(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
"a" in repo.dirstate
def d():
repo.dirstate.invalidate()
@@ -179,9 +181,9 @@
timer(d)
fm.end()
-@command('perfdirstatedirs')
-def perfdirstatedirs(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfdirstatedirs', formatteropts)
+def perfdirstatedirs(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
"a" in repo.dirstate
def d():
"a" in repo.dirstate._dirs
@@ -189,9 +191,9 @@
timer(d)
fm.end()
-@command('perffilefoldmap')
-def perffilefoldmap(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfdirstatefoldmap', formatteropts)
+def perffilefoldmap(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
dirstate = repo.dirstate
'a' in dirstate
def d():
@@ -200,9 +202,9 @@
timer(d)
fm.end()
-@command('perfdirfoldmap')
-def perfdirfoldmap(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfdirfoldmap', formatteropts)
+def perfdirfoldmap(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
dirstate = repo.dirstate
'a' in dirstate
def d():
@@ -212,9 +214,9 @@
timer(d)
fm.end()
-@command('perfdirstatewrite')
-def perfdirstatewrite(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfdirstatewrite', formatteropts)
+def perfdirstatewrite(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
ds = repo.dirstate
"a" in ds
def d():
@@ -224,9 +226,9 @@
fm.end()
@command('perfmergecalculate',
- [('r', 'rev', '.', 'rev to merge against')])
-def perfmergecalculate(ui, repo, rev):
- timer, fm = gettimer(ui)
+ [('r', 'rev', '.', 'rev to merge against')] + formatteropts)
+def perfmergecalculate(ui, repo, rev, **opts):
+ timer, fm = gettimer(ui, opts)
wctx = repo[None]
rctx = scmutil.revsingle(repo, rev, rev)
ancestor = wctx.ancestor(rctx)
@@ -242,8 +244,8 @@
fm.end()
@command('perfpathcopies', [], "REV REV")
-def perfpathcopies(ui, repo, rev1, rev2):
- timer, fm = gettimer(ui)
+def perfpathcopies(ui, repo, rev1, rev2, **opts):
+ timer, fm = gettimer(ui, opts)
ctx1 = scmutil.revsingle(repo, rev1, rev1)
ctx2 = scmutil.revsingle(repo, rev2, rev2)
def d():
@@ -252,8 +254,8 @@
fm.end()
@command('perfmanifest', [], 'REV')
-def perfmanifest(ui, repo, rev):
- timer, fm = gettimer(ui)
+def perfmanifest(ui, repo, rev, **opts):
+ timer, fm = gettimer(ui, opts)
ctx = scmutil.revsingle(repo, rev, rev)
t = ctx.manifestnode()
def d():
@@ -263,9 +265,9 @@
timer(d)
fm.end()
-@command('perfchangeset')
-def perfchangeset(ui, repo, rev):
- timer, fm = gettimer(ui)
+@command('perfchangeset', formatteropts)
+def perfchangeset(ui, repo, rev, **opts):
+ timer, fm = gettimer(ui, opts)
n = repo[rev].node()
def d():
repo.changelog.read(n)
@@ -273,10 +275,10 @@
timer(d)
fm.end()
-@command('perfindex')
-def perfindex(ui, repo):
+@command('perfindex', formatteropts)
+def perfindex(ui, repo, **opts):
import mercurial.revlog
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
n = repo["tip"].node()
def d():
@@ -285,18 +287,18 @@
timer(d)
fm.end()
-@command('perfstartup')
-def perfstartup(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfstartup', formatteropts)
+def perfstartup(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
cmd = sys.argv[0]
def d():
os.system("HGRCPATH= %s version -q > /dev/null" % cmd)
timer(d)
fm.end()
-@command('perfparents')
-def perfparents(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfparents', formatteropts)
+def perfparents(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
nl = [repo.changelog.node(i) for i in xrange(1000)]
def d():
for n in nl:
@@ -304,41 +306,45 @@
timer(d)
fm.end()
-@command('perfctxfiles')
-def perfparents(ui, repo, x):
+@command('perfctxfiles', formatteropts)
+def perfparents(ui, repo, x, **opts):
x = int(x)
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
def d():
len(repo[x].files())
timer(d)
fm.end()
-@command('perfrawfiles')
-def perfparents(ui, repo, x):
+@command('perfrawfiles', formatteropts)
+def perfparents(ui, repo, x, **opts):
x = int(x)
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
cl = repo.changelog
def d():
len(cl.read(x)[3])
timer(d)
fm.end()
-@command('perflookup')
-def perflookup(ui, repo, rev):
- timer, fm = gettimer(ui)
+@command('perflookup', formatteropts)
+def perflookup(ui, repo, rev, **opts):
+ timer, fm = gettimer(ui, opts)
+
+@command('perflookup', formatteropts)
+def perflookup(ui, repo, rev, **opts):
+ timer, fm = gettimer(ui, opts)
timer(lambda: len(repo.lookup(rev)))
fm.end()
-@command('perfrevrange')
-def perfrevrange(ui, repo, *specs):
- timer, fm = gettimer(ui)
+@command('perfrevrange', formatteropts)
+def perfrevrange(ui, repo, *specs, **opts):
+ timer, fm = gettimer(ui, opts)
revrange = scmutil.revrange
timer(lambda: len(revrange(repo, specs)))
fm.end()
-@command('perfnodelookup')
-def perfnodelookup(ui, repo, rev):
- timer, fm = gettimer(ui)
+@command('perfnodelookup', formatteropts)
+def perfnodelookup(ui, repo, rev, **opts):
+ timer, fm = gettimer(ui, opts)
import mercurial.revlog
mercurial.revlog._prereadsize = 2**24 # disable lazy parser in old hg
n = repo[rev].node()
@@ -350,22 +356,22 @@
fm.end()
@command('perflog',
- [('', 'rename', False, 'ask log to follow renames')])
+ [('', 'rename', False, 'ask log to follow renames')] + formatteropts)
def perflog(ui, repo, **opts):
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
ui.pushbuffer()
timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
copies=opts.get('rename')))
ui.popbuffer()
fm.end()
-@command('perfmoonwalk')
-def perfmoonwalk(ui, repo):
+@command('perfmoonwalk', formatteropts)
+def perfmoonwalk(ui, repo, **opts):
"""benchmark walking the changelog backwards
This also loads the changelog data for each revision in the changelog.
"""
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
def moonwalk():
for i in xrange(len(repo), -1, -1):
ctx = repo[i]
@@ -373,9 +379,9 @@
timer(moonwalk)
fm.end()
-@command('perftemplating')
-def perftemplating(ui, repo):
- timer, fm = gettimer(ui)
+@command('perftemplating', formatteropts)
+def perftemplating(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
ui.pushbuffer()
timer(lambda: commands.log(ui, repo, rev=[], date='', user='',
template='{date|shortdate} [{rev}:{node|short}]'
@@ -383,24 +389,24 @@
ui.popbuffer()
fm.end()
-@command('perfcca')
-def perfcca(ui, repo):
- timer, fm = gettimer(ui)
+@command('perfcca', formatteropts)
+def perfcca(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
timer(lambda: scmutil.casecollisionauditor(ui, False, repo.dirstate))
fm.end()
-@command('perffncacheload')
-def perffncacheload(ui, repo):
- timer, fm = gettimer(ui)
+@command('perffncacheload', formatteropts)
+def perffncacheload(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
s = repo.store
def d():
s.fncache._load()
timer(d)
fm.end()
-@command('perffncachewrite')
-def perffncachewrite(ui, repo):
- timer, fm = gettimer(ui)
+@command('perffncachewrite', formatteropts)
+def perffncachewrite(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
s = repo.store
s.fncache._load()
def d():
@@ -409,9 +415,9 @@
timer(d)
fm.end()
-@command('perffncacheencode')
-def perffncacheencode(ui, repo):
- timer, fm = gettimer(ui)
+@command('perffncacheencode', formatteropts)
+def perffncacheencode(ui, repo, **opts):
+ timer, fm = gettimer(ui, opts)
s = repo.store
s.fncache._load()
def d():
@@ -420,10 +426,10 @@
timer(d)
fm.end()
-@command('perfdiffwd')
-def perfdiffwd(ui, repo):
+@command('perfdiffwd', formatteropts)
+def perfdiffwd(ui, repo, **opts):
"""Profile diff of working directory changes"""
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
options = {
'w': 'ignore_all_space',
'b': 'ignore_space_change',
@@ -441,10 +447,10 @@
fm.end()
@command('perfrevlog',
- [('d', 'dist', 100, 'distance between the revisions')],
+ [('d', 'dist', 100, 'distance between the revisions')] + formatteropts,
"[INDEXFILE]")
def perfrevlog(ui, repo, file_, **opts):
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
from mercurial import revlog
dist = opts['dist']
def d():
@@ -456,15 +462,15 @@
fm.end()
@command('perfrevset',
- [('C', 'clear', False, 'clear volatile cache between each call.')],
- "REVSET")
-def perfrevset(ui, repo, expr, clear=False):
+ [('C', 'clear', False, 'clear volatile cache between each call.')]
+ + formatteropts, "REVSET")
+def perfrevset(ui, repo, expr, clear=False, **opts):
"""benchmark the execution time of a revset
Use the --clean option if need to evaluate the impact of build volatile
revisions set cache on the revset execution. Volatile cache hold filtered
and obsolete related cache."""
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
def d():
if clear:
repo.invalidatevolatilesets()
@@ -472,12 +478,12 @@
timer(d)
fm.end()
-@command('perfvolatilesets')
-def perfvolatilesets(ui, repo, *names):
+@command('perfvolatilesets', formatteropts)
+def perfvolatilesets(ui, repo, *names, **opts):
"""benchmark the computation of various volatile set
Volatile set computes element related to filtering and obsolescence."""
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
repo = repo.unfiltered()
def getobs(name):
@@ -510,13 +516,13 @@
@command('perfbranchmap',
[('f', 'full', False,
'Includes build time of subset'),
- ])
-def perfbranchmap(ui, repo, full=False):
+ ] + formatteropts)
+def perfbranchmap(ui, repo, full=False, **opts):
"""benchmark the update of a branchmap
This benchmarks the full repo.branchmap() call with read and write disabled
"""
- timer, fm = gettimer(ui)
+ timer, fm = gettimer(ui, opts)
def getbranchmap(filtername):
"""generate a benchmark function for the filtername"""
if filtername is None:
--- a/contrib/revsetbenchmarks.py Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/revsetbenchmarks.py Mon Jun 15 13:31:22 2015 -0500
@@ -4,21 +4,22 @@
# defined by parameter. Checkout one by one and run perfrevset with every
# revset in the list to benchmark its performance.
#
-# - First argument is a revset of mercurial own repo to runs against.
-# - Second argument is the file from which the revset array will be taken
-# If second argument is omitted read it from standard input
-#
# You should run this from the root of your mercurial repository.
#
-# This script also does one run of the current version of mercurial installed
-# to compare performance.
+# call with --help for details
import sys
import os
+import re
+import math
from subprocess import check_call, Popen, CalledProcessError, STDOUT, PIPE
# cannot use argparse, python 2.7 only
from optparse import OptionParser
+DEFAULTVARIANTS = ['plain', 'min', 'max', 'first', 'last',
+ 'reverse', 'reverse+first', 'reverse+last',
+ 'sort', 'sort+first', 'sort+last']
+
def check_output(*args, **kwargs):
kwargs.setdefault('stderr', PIPE)
kwargs.setdefault('stdout', PIPE)
@@ -36,31 +37,160 @@
print >> sys.stderr, 'update to revision %s failed, aborting' % rev
sys.exit(exc.returncode)
+
+def hg(cmd, repo=None):
+ """run a mercurial command
+
+ <cmd> is the list of command + argument,
+ <repo> is an optional repository path to run this command in."""
+ fullcmd = ['./hg']
+ if repo is not None:
+ fullcmd += ['-R', repo]
+ fullcmd += ['--config',
+ 'extensions.perf=' + os.path.join(contribdir, 'perf.py')]
+ fullcmd += cmd
+ return check_output(fullcmd, stderr=STDOUT)
+
def perf(revset, target=None):
"""run benchmark for this very revset"""
try:
- cmd = ['./hg',
- '--config',
- 'extensions.perf='
- + os.path.join(contribdir, 'perf.py'),
- 'perfrevset',
- revset]
- if target is not None:
- cmd.append('-R')
- cmd.append(target)
- output = check_output(cmd, stderr=STDOUT)
- output = output.lstrip('!') # remove useless ! in this context
- return output.strip()
+ output = hg(['perfrevset', revset], repo=target)
+ return parseoutput(output)
except CalledProcessError, exc:
- print >> sys.stderr, 'abort: cannot run revset benchmark'
+ print >> sys.stderr, 'abort: cannot run revset benchmark: %s' % exc.cmd
+ if exc.output is None:
+ print >> sys.stderr, '(no ouput)'
+ else:
+ print >> sys.stderr, exc.output
sys.exit(exc.returncode)
+outputre = re.compile(r'! wall (\d+.\d+) comb (\d+.\d+) user (\d+.\d+) '
+ 'sys (\d+.\d+) \(best of (\d+)\)')
+
+def parseoutput(output):
+ """parse a textual output into a dict
+
+ We cannot just use json because we want to compare with old
+ versions of Mercurial that may not support json output.
+ """
+ match = outputre.search(output)
+ if not match:
+ print >> sys.stderr, 'abort: invalid output:'
+ print >> sys.stderr, output
+ sys.exit(1)
+ return {'comb': float(match.group(2)),
+ 'count': int(match.group(5)),
+ 'sys': float(match.group(3)),
+ 'user': float(match.group(4)),
+ 'wall': float(match.group(1)),
+ }
+
def printrevision(rev):
"""print data about a revision"""
- sys.stdout.write("Revision: ")
+ sys.stdout.write("Revision ")
sys.stdout.flush()
check_call(['hg', 'log', '--rev', str(rev), '--template',
- '{desc|firstline}\n'])
+ '{if(tags, " ({tags})")} '
+ '{rev}:{node|short}: {desc|firstline}\n'])
+
+def idxwidth(nbidx):
+ """return the max width of number used for index
+
+ This is similar to log10(nbidx), but we use custom code here
+ because we start with zero and we'd rather not deal with all the
+ extra rounding business that log10 would imply.
+ """
+ nbidx -= 1 # starts at 0
+ idxwidth = 0
+ while nbidx:
+ idxwidth += 1
+ nbidx //= 10
+ if not idxwidth:
+ idxwidth = 1
+ return idxwidth
+
+def getfactor(main, other, field, sensitivity=0.05):
+ """return the relative factor between values for 'field' in main and other
+
+ Return None if the factor is insignicant (less than <sensitivity>
+ variation)."""
+ factor = 1
+ if main is not None:
+ factor = other[field] / main[field]
+ low, high = 1 - sensitivity, 1 + sensitivity
+ if (low < factor < high):
+ return None
+ return factor
+
+def formatfactor(factor):
+ """format a factor into a 4 char string
+
+ 22%
+ 156%
+ x2.4
+ x23
+ x789
+ x1e4
+ x5x7
+
+ """
+ if factor is None:
+ return ' '
+ elif factor < 2:
+ return '%3i%%' % (factor * 100)
+ elif factor < 10:
+ return 'x%3.1f' % factor
+ elif factor < 1000:
+ return '%4s' % ('x%i' % factor)
+ else:
+ order = int(math.log(factor)) + 1
+ while 1 < math.log(factor):
+ factor //= 0
+ return 'x%ix%i' % (factor, order)
+
+def formattiming(value):
+ """format a value to strictly 8 char, dropping some precision if needed"""
+ if value < 10**7:
+ return ('%.6f' % value)[:8]
+ else:
+ # value is HUGE very unlikely to happen (4+ month run)
+ return '%i' % value
+
+_marker = object()
+def printresult(variants, idx, data, maxidx, verbose=False, reference=_marker):
+ """print a line of result to stdout"""
+ mask = '%%0%ii) %%s' % idxwidth(maxidx)
+ out = []
+ for var in variants:
+ out.append(formattiming(data[var]['wall']))
+ if reference is not _marker:
+ factor = None
+ if reference is not None:
+ factor = getfactor(reference[var], data[var], 'wall')
+ out.append(formatfactor(factor))
+ if verbose:
+ out.append(formattiming(data[var]['comb']))
+ out.append(formattiming(data[var]['user']))
+ out.append(formattiming(data[var]['sys']))
+ out.append('%6d' % data[var]['count'])
+ print mask % (idx, ' '.join(out))
+
+def printheader(variants, maxidx, verbose=False, relative=False):
+ header = [' ' * (idxwidth(maxidx) + 1)]
+ for var in variants:
+ if not var:
+ var = 'iter'
+ if 8 < len(var):
+ var = var[:3] + '..' + var[-3:]
+ header.append('%-8s' % var)
+ if relative:
+ header.append(' ')
+ if verbose:
+ header.append('%-8s' % 'comb')
+ header.append('%-8s' % 'user')
+ header.append('%-8s' % 'sys')
+ header.append('%6s' % 'count')
+ print ' '.join(header)
def getrevs(spec):
"""get the list of rev matched by a revset"""
@@ -72,6 +202,14 @@
return [r for r in out.split() if r]
+def applyvariants(revset, variant):
+ if variant == 'plain':
+ return revset
+ for var in variant.split('+'):
+ revset = '%s(%s)' % (var, revset)
+ return revset
+
+
parser = OptionParser(usage="usage: %prog [options] <revs>")
parser.add_option("-f", "--file",
help="read revset from FILE (stdin if omitted)",
@@ -79,17 +217,24 @@
parser.add_option("-R", "--repo",
help="run benchmark on REPO", metavar="REPO")
+parser.add_option("-v", "--verbose",
+ action='store_true',
+ help="display all timing data (not just best total time)")
+
+parser.add_option("", "--variants",
+ default=','.join(DEFAULTVARIANTS),
+ help="comma separated list of variant to test "
+ "(eg: plain,min,sorted) (plain = no modification)")
+
(options, args) = parser.parse_args()
-if len(sys.argv) < 2:
+if not args:
parser.print_help()
sys.exit(255)
# the directory where both this script and the perf.py extension live.
contribdir = os.path.dirname(__file__)
-target_rev = args[0]
-
revsetsfile = sys.stdin
if options.file:
revsetsfile = open(options.file)
@@ -105,8 +250,11 @@
print "----------------------------"
print
+revs = []
+for a in args:
+ revs.extend(getrevs(a))
-revs = getrevs(target_rev)
+variants = options.variants.split(',')
results = []
for r in revs:
@@ -116,10 +264,16 @@
update(r)
res = []
results.append(res)
+ printheader(variants, len(revsets), verbose=options.verbose)
for idx, rset in enumerate(revsets):
- data = perf(rset, target=options.repo)
- res.append(data)
- print "%i)" % idx, data
+ varres = {}
+ for var in variants:
+ varrset = applyvariants(rset, var)
+ data = perf(varrset, target=options.repo)
+ varres[var] = data
+ res.append(varres)
+ printresult(variants, idx, varres, len(revsets),
+ verbose=options.verbose)
sys.stdout.flush()
print "----------------------------"
@@ -130,7 +284,7 @@
================
"""
-print 'Revision:', revs
+print 'Revision:'
for idx, rev in enumerate(revs):
sys.stdout.write('%i) ' % idx)
sys.stdout.flush()
@@ -142,6 +296,10 @@
for ridx, rset in enumerate(revsets):
print "revset #%i: %s" % (ridx, rset)
+ printheader(variants, len(results), verbose=options.verbose, relative=True)
+ ref = None
for idx, data in enumerate(results):
- print '%i) %s' % (idx, data[ridx])
+ printresult(variants, idx, data[ridx], len(results),
+ verbose=options.verbose, reference=ref)
+ ref = data[ridx]
print
--- a/contrib/revsetbenchmarks.txt Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/revsetbenchmarks.txt Mon Jun 15 13:31:22 2015 -0500
@@ -10,19 +10,16 @@
author(lmoscovicz) or author(mpm)
author(mpm) or author(lmoscovicz)
tip:0
-max(tip:0)
-min(0:tip)
0::
-min(0::)
# 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()
draft()
:10000 and draft()
-max(::(tip~20) - obsolete())
roots((0:tip)::)
(not public() - obsolete())
(_intlist('20000\x0020001')) and merge()
--- a/contrib/synthrepo.py Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/synthrepo.py Mon Jun 15 13:31:22 2015 -0500
@@ -41,6 +41,10 @@
from mercurial.i18n import _
from mercurial.node import nullrev, nullid, short
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
cmdtable = {}
--- a/contrib/wix/dist.wxs Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/wix/dist.wxs Mon Jun 15 13:31:22 2015 -0500
@@ -7,24 +7,28 @@
<Fragment>
<DirectoryRef Id="INSTALLDIR" FileSource="$(var.SourceDir)">
<Component Id="distOutput" Guid="$(var.dist.guid)" Win64='$(var.IsX64)'>
- <File Name="library.zip" KeyPath="yes" />
- <File Name="mercurial.base85.pyd" />
- <File Name="mercurial.bdiff.pyd" />
- <File Name="mercurial.diffhelpers.pyd" />
- <File Name="mercurial.mpatch.pyd" />
- <File Name="mercurial.osutil.pyd" />
- <File Name="mercurial.parsers.pyd" />
- <File Name="pyexpat.pyd" />
- <File Name="python27.dll" />
- <File Name="bz2.pyd" />
- <File Name="select.pyd" />
- <File Name="unicodedata.pyd" />
- <File Name="_ctypes.pyd" />
- <File Name="_elementtree.pyd" />
- <File Name="_hashlib.pyd" />
- <File Name="_socket.pyd" />
- <File Name="_ssl.pyd" />
+ <File Name="python27.dll" KeyPath="yes" />
</Component>
+ <Directory Id="libdir" Name="lib" FileSource="$(var.SourceDir)/lib">
+ <Component Id="libOutput" Guid="$(var.lib.guid)" Win64='$(var.IsX64)'>
+ <File Name="library.zip" KeyPath="yes" />
+ <File Name="mercurial.base85.pyd" />
+ <File Name="mercurial.bdiff.pyd" />
+ <File Name="mercurial.diffhelpers.pyd" />
+ <File Name="mercurial.mpatch.pyd" />
+ <File Name="mercurial.osutil.pyd" />
+ <File Name="mercurial.parsers.pyd" />
+ <File Name="pyexpat.pyd" />
+ <File Name="bz2.pyd" />
+ <File Name="select.pyd" />
+ <File Name="unicodedata.pyd" />
+ <File Name="_ctypes.pyd" />
+ <File Name="_elementtree.pyd" />
+ <File Name="_hashlib.pyd" />
+ <File Name="_socket.pyd" />
+ <File Name="_ssl.pyd" />
+ </Component>
+ </Directory>
</DirectoryRef>
</Fragment>
--- a/contrib/wix/guids.wxi Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/wix/guids.wxi Mon Jun 15 13:31:22 2015 -0500
@@ -9,7 +9,8 @@
<?define contrib.vim.guid = {BB04903A-652D-4C4F-9590-2BD07A2304F2} ?>
<!-- dist.wxs -->
- <?define dist.guid = {C3B634A4-1B05-4A40-94A9-38EE853CF693} ?>
+ <?define dist.guid = {CE405FE6-CD1E-4873-9C9A-7683AE5A3D90} ?>
+ <?define lib.guid = {91D53B14-E924-432A-ACA2-65F9B3F7C56A} ?>
<!-- doc.wxs -->
<?define doc.hg.1.html.guid = {AAAA3FDA-EDC5-4220-B59D-D342722358A2} ?>
@@ -28,6 +29,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/mercurial.wxs Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/wix/mercurial.wxs Mon Jun 15 13:31:22 2015 -0500
@@ -118,6 +118,7 @@
Level='1' Absent='disallow' >
<ComponentRef Id='MainExecutable' />
<ComponentRef Id='distOutput' />
+ <ComponentRef Id='libOutput' />
<ComponentRef Id='ProgramMenuDir' />
<ComponentRef Id='ReadMe' />
<ComponentRef Id='COPYING' />
--- a/contrib/wix/templates.wxs Sat Jun 13 20:14:22 2015 +0900
+++ b/contrib/wix/templates.wxs Mon Jun 15 13:31:22 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/acl.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/acl.py Mon Jun 15 13:31:22 2015 -0500
@@ -195,6 +195,10 @@
from mercurial import util, match
import getpass, urllib
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
def _getusers(ui, group):
--- a/hgext/blackbox.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/blackbox.py Mon Jun 15 13:31:22 2015 -0500
@@ -35,6 +35,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
lastblackbox = None
--- a/hgext/bugzilla.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/bugzilla.py Mon Jun 15 13:31:22 2015 -0500
@@ -279,9 +279,13 @@
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
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
class bzaccess(object):
@@ -876,8 +880,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/censor.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/censor.py Mon Jun 15 13:31:22 2015 -0500
@@ -31,6 +31,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
@command('censor',
--- a/hgext/children.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/children.py Mon Jun 15 13:31:22 2015 -0500
@@ -20,6 +20,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
@command('children',
--- a/hgext/churn.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/churn.py Mon Jun 15 13:31:22 2015 -0500
@@ -9,17 +9,20 @@
'''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
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
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/color.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/color.py Mon Jun 15 13:31:22 2015 -0500
@@ -84,7 +84,7 @@
resolve.unresolved = red bold
resolve.resolved = green bold
- bookmarks.current = green
+ bookmarks.active = green
branches.active = none
branches.closed = black bold
@@ -162,6 +162,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
# start and stop parameters for effects
@@ -309,7 +313,7 @@
'grep.filename': 'magenta',
'grep.user': 'magenta',
'grep.date': 'magenta',
- 'bookmarks.current': 'green',
+ 'bookmarks.active': 'green',
'branches.active': 'none',
'branches.closed': 'black bold',
'branches.current': 'green',
@@ -527,6 +531,7 @@
return orig(gitsub, commands, env, stream, cwd)
extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
extensions.wrapfunction(subrepo.gitsubrepo, '_gitnodir', colorgit)
+ templatelabel.__doc__ = templater.funcs['label'].__doc__
templater.funcs['label'] = templatelabel
def extsetup(ui):
--- a/hgext/convert/__init__.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/convert/__init__.py Mon Jun 15 13:31:22 2015 -0500
@@ -15,6 +15,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
# Commands definition was moved elsewhere to ease demandload job.
@@ -324,6 +328,23 @@
Mercurial Destination
#####################
+ The Mercurial destination will recognize Mercurial subrepositories in the
+ destination directory, and update the .hgsubstate file automatically if the
+ destination subrepositories contain the <dest>/<sub>/.hg/shamap file.
+ Converting a repository with subrepositories requires converting a single
+ repository at a time, from the bottom up.
+
+ .. container:: verbose
+
+ An example showing how to convert a repository with subrepositories::
+
+ # so convert knows the type when it sees a non empty destination
+ $ hg init converted
+
+ $ hg convert orig/sub1 converted/sub1
+ $ hg convert orig/sub2 converted/sub2
+ $ hg convert orig converted
+
The following options are supported:
:convert.hg.clonebranches: dispatch source branches in separate
--- a/hgext/convert/common.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/convert/common.py Mon Jun 15 13:31:22 2015 -0500
@@ -7,7 +7,7 @@
import base64, errno, subprocess, os, datetime, re
import cPickle as pickle
-from mercurial import util
+from mercurial import phases, util
from mercurial.i18n import _
propertycache = util.propertycache
@@ -44,7 +44,7 @@
class commit(object):
def __init__(self, author, date, desc, parents, branch=None, rev=None,
- extra={}, sortkey=None):
+ extra={}, sortkey=None, saverev=True, phase=phases.draft):
self.author = author or 'unknown'
self.date = date or '0 0'
self.desc = desc
@@ -53,6 +53,8 @@
self.rev = rev
self.extra = extra
self.sortkey = sortkey
+ self.saverev = saverev
+ self.phase = phase
class converter_source(object):
"""Conversion source interface"""
--- a/hgext/convert/filemap.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/convert/filemap.py Mon Jun 15 13:31:22 2015 -0500
@@ -332,7 +332,7 @@
mp1 = self.parentmap[p1]
if mp1 == SKIPREV or mp1 in knownparents:
continue
- isancestor = util.any(p2 for p2 in parents
+ isancestor = any(p2 for p2 in parents
if p1 != p2 and mp1 != self.parentmap[p2]
and mp1 in self.wantedancestors[p2])
if not isancestor and not hasbranchparent and len(parents) > 1:
--- a/hgext/convert/hg.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/convert/hg.py Mon Jun 15 13:31:22 2015 -0500
@@ -22,8 +22,9 @@
from mercurial.i18n import _
from mercurial.node import bin, hex, nullid
from mercurial import hg, util, context, bookmarks, error, scmutil, exchange
+from mercurial import phases
-from common import NoRepo, commit, converter_source, converter_sink
+from common import NoRepo, commit, converter_source, converter_sink, mapfile
import re
sha1re = re.compile(r'\b[0-9a-f]{12,40}\b')
@@ -59,6 +60,7 @@
self.lock = None
self.wlock = None
self.filemapmode = False
+ self.subrevmaps = {}
def before(self):
self.ui.debug('run hg sink pre-conversion action\n')
@@ -135,6 +137,45 @@
fp.write('%s %s\n' % (revid, s[1]))
return fp.getvalue()
+ def _rewritesubstate(self, source, data):
+ fp = cStringIO.StringIO()
+ for line in data.splitlines():
+ s = line.split(' ', 1)
+ if len(s) != 2:
+ continue
+
+ revid = s[0]
+ subpath = s[1]
+ if revid != hex(nullid):
+ revmap = self.subrevmaps.get(subpath)
+ if revmap is None:
+ revmap = mapfile(self.ui,
+ self.repo.wjoin(subpath, '.hg/shamap'))
+ self.subrevmaps[subpath] = revmap
+
+ # It is reasonable that one or more of the subrepos don't
+ # need to be converted, in which case they can be cloned
+ # into place instead of converted. Therefore, only warn
+ # once.
+ msg = _('no ".hgsubstate" updates will be made for "%s"\n')
+ if len(revmap) == 0:
+ sub = self.repo.wvfs.reljoin(subpath, '.hg')
+
+ if self.repo.wvfs.exists(sub):
+ self.ui.warn(msg % subpath)
+
+ newid = revmap.get(revid)
+ if not newid:
+ if len(revmap) > 0:
+ self.ui.warn(_("%s is missing from %s/.hg/shamap\n") %
+ (revid, subpath))
+ else:
+ revid = newid
+
+ fp.write('%s %s\n' % (revid, subpath))
+
+ return fp.getvalue()
+
def putcommit(self, files, copies, parents, commit, source, revmap, full,
cleanp2):
files = dict(files)
@@ -152,6 +193,8 @@
return None
if f == '.hgtags':
data = self._rewritetags(source, revmap, data)
+ if f == '.hgsubstate':
+ data = self._rewritesubstate(source, data)
return context.memfilectx(self.repo, f, data, 'l' in mode,
'x' in mode, copies.get(f))
@@ -201,7 +244,7 @@
if self.branchnames and commit.branch:
extra['branch'] = commit.branch
- if commit.rev:
+ if commit.rev and commit.saverev:
extra['convert_revision'] = commit.rev
while parents:
@@ -216,7 +259,29 @@
fileset.update(self.repo[p2])
ctx = context.memctx(self.repo, (p1, p2), text, fileset,
getfilectx, commit.author, commit.date, extra)
- self.repo.commitctx(ctx)
+
+ # We won't know if the conversion changes the node until after the
+ # commit, so copy the source's phase for now.
+ self.repo.ui.setconfig('phases', 'new-commit',
+ phases.phasenames[commit.phase], 'convert')
+
+ tr = self.repo.transaction("convert")
+
+ try:
+ node = hex(self.repo.commitctx(ctx))
+
+ # If the node value has changed, but the phase is lower than
+ # draft, set it back to draft since it hasn't been exposed
+ # anywhere.
+ if commit.rev != node:
+ ctx = self.repo[node]
+ if ctx.phase() < phases.draft:
+ phases.retractboundary(self.repo, tr, phases.draft,
+ [ctx.node()])
+ tr.close()
+ finally:
+ tr.release()
+
text = "(octopus merge fixup)\n"
p2 = hex(self.repo.changelog.tip())
@@ -431,15 +496,14 @@
def getcommit(self, rev):
ctx = self.changectx(rev)
parents = [p.hex() for p in self.parents(ctx)]
- if self.saverev:
- crev = rev
- else:
- crev = None
+ crev = rev
+
return commit(author=ctx.user(),
date=util.datestr(ctx.date(), '%Y-%m-%d %H:%M:%S %1%2'),
desc=ctx.description(), rev=crev, parents=parents,
branch=ctx.branch(), extra=ctx.extra(),
- sortkey=ctx.rev())
+ sortkey=ctx.rev(), saverev=self.saverev,
+ phase=ctx.phase())
def gettags(self):
# This will get written to .hgtags, filter non global tags out.
--- a/hgext/eol.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/eol.py Mon Jun 15 13:31:22 2015 -0500
@@ -95,6 +95,10 @@
from mercurial import util, config, extensions, match, error
import re, os
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
# Matches a lone LF, i.e., one that is not part of CRLF.
--- a/hgext/extdiff.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/extdiff.py Mon Jun 15 13:31:22 2015 -0500
@@ -67,6 +67,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
def snapshot(ui, repo, files, node, tmproot):
--- a/hgext/factotum.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/factotum.py Mon Jun 15 13:31:22 2015 -0500
@@ -67,21 +67,20 @@
while True:
fd = os.open('%s/rpc' % _mountpoint, os.O_RDWR)
try:
- try:
- os.write(fd, 'start %s' % params)
- l = os.read(fd, ERRMAX).split()
- if l[0] == 'ok':
- os.write(fd, 'read')
- status, user, passwd = os.read(fd, ERRMAX).split(None, 2)
- if status == 'ok':
- if passwd.startswith("'"):
- if passwd.endswith("'"):
- passwd = passwd[1:-1].replace("''", "'")
- else:
- raise util.Abort(_('malformed password string'))
- return (user, passwd)
- except (OSError, IOError):
- raise util.Abort(_('factotum not responding'))
+ os.write(fd, 'start %s' % params)
+ l = os.read(fd, ERRMAX).split()
+ if l[0] == 'ok':
+ os.write(fd, 'read')
+ status, user, passwd = os.read(fd, ERRMAX).split(None, 2)
+ if status == 'ok':
+ if passwd.startswith("'"):
+ if passwd.endswith("'"):
+ passwd = passwd[1:-1].replace("''", "'")
+ else:
+ raise util.Abort(_('malformed password string'))
+ return (user, passwd)
+ except (OSError, IOError):
+ raise util.Abort(_('factotum not responding'))
finally:
os.close(fd)
getkey(self, params)
--- a/hgext/fetch.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/fetch.py Mon Jun 15 13:31:22 2015 -0500
@@ -15,6 +15,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
@command('fetch',
--- a/hgext/gpg.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/gpg.py Mon Jun 15 13:31:22 2015 -0500
@@ -12,6 +12,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
class gpg(object):
@@ -255,7 +259,7 @@
if not opts["force"]:
msigs = match.exact(repo.root, '', ['.hgsigs'])
- if util.any(repo.status(match=msigs, unknown=True, ignored=True)):
+ if any(repo.status(match=msigs, unknown=True, ignored=True)):
raise util.Abort(_("working copy of .hgsigs is changed "),
hint=_("please commit .hgsigs manually"))
--- a/hgext/graphlog.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/graphlog.py Mon Jun 15 13:31:22 2015 -0500
@@ -20,6 +20,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
@command('glog',
--- a/hgext/hgcia.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/hgcia.py Mon Jun 15 13:31:22 2015 -0500
@@ -43,11 +43,15 @@
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
from xml.sax import saxutils
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
socket_timeout = 30 # seconds
@@ -206,7 +210,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/hgk.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/hgk.py Mon Jun 15 13:31:22 2015 -0500
@@ -41,6 +41,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
@command('debug-diff-tree',
--- a/hgext/highlight/__init__.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/highlight/__init__.py Mon Jun 15 13:31:22 2015 -0500
@@ -24,6 +24,10 @@
import highlight
from mercurial.hgweb import webcommands, webutil, common
from mercurial import extensions, encoding
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
def filerevision_highlight(orig, web, tmpl, fctx):
--- a/hgext/histedit.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/histedit.py Mon Jun 15 13:31:22 2015 -0500
@@ -181,6 +181,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
# i18n: command names and abbreviations must remain untranslated
@@ -381,7 +385,7 @@
- Add a 'histedit_source' entry in extra.
- Note that fold have its own separated logic because its handling is a bit
+ Note that fold has its own separated logic because its handling is a bit
different and not easily factored out of the fold method.
"""
phasemin = src.phase()
@@ -429,6 +433,10 @@
ctxs = list(repo.set('%d::%d', first, last))
if not ctxs:
return None
+ for c in ctxs:
+ if not c.mutable():
+ raise util.Abort(
+ _("cannot fold into public change %s") % node.short(c.node()))
base = first.parents()[0]
# commit a new version of the old changeset, including the update
@@ -707,15 +715,15 @@
if force and not outg:
raise util.Abort(_('--force only allowed with --outgoing'))
if cont:
- if util.any((outg, abort, revs, freeargs, rules, editplan)):
+ if any((outg, abort, revs, freeargs, rules, editplan)):
raise util.Abort(_('no arguments allowed with --continue'))
goal = 'continue'
elif abort:
- if util.any((outg, revs, freeargs, rules, editplan)):
+ if any((outg, revs, freeargs, rules, editplan)):
raise util.Abort(_('no arguments allowed with --abort'))
goal = 'abort'
elif editplan:
- if util.any((outg, revs, freeargs)):
+ if any((outg, revs, freeargs)):
raise util.Abort(_('only --commands argument allowed with '
'--edit-plan'))
goal = 'edit-plan'
@@ -924,7 +932,8 @@
raise util.Abort(_('cannot edit history that contains merges'))
root = ctxs[0] # list is already sorted by repo.set
if not root.mutable():
- raise util.Abort(_('cannot edit immutable changeset: %s') % root)
+ raise util.Abort(_('cannot edit public changeset: %s') % root,
+ hint=_('see "hg help phases" for details'))
return [c.node() for c in ctxs]
def makedesc(repo, action, rev):
--- a/hgext/keyword.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/keyword.py Mon Jun 15 13:31:22 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 _
@@ -91,6 +91,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
# hg commands that do not act on keywords
@@ -191,8 +195,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 +460,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/__init__.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/largefiles/__init__.py Mon Jun 15 13:31:22 2015 -0500
@@ -112,6 +112,10 @@
import reposetup
import uisetup as uisetupmod
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
reposetup = reposetup.reposetup
--- a/hgext/largefiles/lfcommands.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/largefiles/lfcommands.py Mon Jun 15 13:31:22 2015 -0500
@@ -16,6 +16,9 @@
from mercurial.i18n import _
from mercurial.lock import release
+from hgext.convert import convcmd
+from hgext.convert import filemap
+
import lfutil
import basestore
@@ -70,12 +73,6 @@
success = False
dstwlock = dstlock = None
try:
- # Lock destination to prevent modification while it is converted to.
- # Don't need to lock src because we are just reading from its history
- # which can't change.
- dstwlock = rdst.wlock()
- dstlock = rdst.lock()
-
# Get a list of all changesets in the source. The easy way to do this
# is to simply walk the changelog, using changelog.nodesbetween().
# Take a look at mercurial/revlog.py:639 for more details.
@@ -84,6 +81,12 @@
rsrc.heads())[0])
revmap = {node.nullid: node.nullid}
if tolfile:
+ # Lock destination to prevent modification while it is converted to.
+ # Don't need to lock src because we are just reading from its
+ # history which can't change.
+ dstwlock = rdst.wlock()
+ dstlock = rdst.lock()
+
lfiles = set()
normalfiles = set()
if not pats:
@@ -118,74 +121,60 @@
rdst.requirements.add('largefiles')
rdst._writerequirements()
else:
- for ctx in ctxs:
- ui.progress(_('converting revisions'), ctx.rev(),
- unit=_('revision'), total=rsrc['tip'].rev())
- _addchangeset(ui, rsrc, rdst, ctx, revmap)
+ class lfsource(filemap.filemap_source):
+ def __init__(self, ui, source):
+ super(lfsource, self).__init__(ui, source, None)
+ self.filemapper.rename[lfutil.shortname] = '.'
+
+ def getfile(self, name, rev):
+ realname, realrev = rev
+ f = super(lfsource, self).getfile(name, rev)
+
+ if (not realname.startswith(lfutil.shortnameslash)
+ or f[0] is None):
+ return f
+
+ # Substitute in the largefile data for the hash
+ hash = f[0].strip()
+ path = lfutil.findfile(rsrc, hash)
+
+ if path is None:
+ raise util.Abort(_("missing largefile for \'%s\' in %s")
+ % (realname, realrev))
+ fp = open(path, 'rb')
- ui.progress(_('converting revisions'), None)
+ try:
+ return (fp.read(), f[1])
+ finally:
+ fp.close()
+
+ class converter(convcmd.converter):
+ def __init__(self, ui, source, dest, revmapfile, opts):
+ src = lfsource(ui, source)
+
+ super(converter, self).__init__(ui, src, dest, revmapfile,
+ opts)
+
+ found, missing = downloadlfiles(ui, rsrc)
+ if missing != 0:
+ raise util.Abort(_("all largefiles must be present locally"))
+
+ orig = convcmd.converter
+ convcmd.converter = converter
+
+ try:
+ convcmd.convert(ui, src, dest)
+ finally:
+ convcmd.converter = orig
success = True
finally:
- rdst.dirstate.clear()
- release(dstlock, dstwlock)
+ if tolfile:
+ rdst.dirstate.clear()
+ release(dstlock, dstwlock)
if not success:
# we failed, remove the new directory
shutil.rmtree(rdst.root)
-def _addchangeset(ui, rsrc, rdst, ctx, revmap):
- # Convert src parents to dst parents
- parents = _convertparents(ctx, revmap)
-
- # Generate list of changed files
- files = _getchangedfiles(ctx, parents)
-
- def getfilectx(repo, memctx, f):
- if lfutil.standin(f) in files:
- # if the file isn't in the manifest then it was removed
- # or renamed, raise IOError to indicate this
- try:
- fctx = ctx.filectx(lfutil.standin(f))
- except error.LookupError:
- return None
- renamed = fctx.renamed()
- if renamed:
- renamed = lfutil.splitstandin(renamed[0])
-
- hash = fctx.data().strip()
- path = lfutil.findfile(rsrc, hash)
-
- # If one file is missing, likely all files from this rev are
- if path is None:
- cachelfiles(ui, rsrc, ctx.node())
- path = lfutil.findfile(rsrc, hash)
-
- if path is None:
- raise util.Abort(
- _("missing largefile \'%s\' from revision %s")
- % (f, node.hex(ctx.node())))
-
- data = ''
- fd = None
- try:
- fd = open(path, 'rb')
- data = fd.read()
- finally:
- if fd:
- fd.close()
- return context.memfilectx(repo, f, data, 'l' in fctx.flags(),
- 'x' in fctx.flags(), renamed)
- else:
- return _getnormalcontext(repo, ctx, f, revmap)
-
- dstfiles = []
- for file in files:
- if lfutil.isstandin(file):
- dstfiles.append(lfutil.splitstandin(file))
- else:
- dstfiles.append(file)
- # Commit
- _commitcontext(rdst, parents, ctx, dstfiles, getfilectx, revmap)
-
def _lfconvert_addchangeset(rsrc, rdst, ctx, revmap, lfiles, normalfiles,
matcher, size, lfiletohash):
# Convert src parents to dst parents
@@ -380,9 +369,7 @@
matches the revision ID). With --all, check every changeset in
this repository.'''
if all:
- # Pass a list to the function rather than an iterator because we know a
- # list will work.
- revs = range(len(repo))
+ revs = repo.revs('all()')
else:
revs = ['.']
--- a/hgext/largefiles/lfutil.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/largefiles/lfutil.py Mon Jun 15 13:31:22 2015 -0500
@@ -238,24 +238,28 @@
if path:
link(storepath(repo, hash), path)
-def getstandinmatcher(repo, pats=[], opts={}):
- '''Return a match object that applies pats to the standin directory'''
+def getstandinmatcher(repo, rmatcher=None):
+ '''Return a match object that applies rmatcher to the standin directory'''
standindir = repo.wjoin(shortname)
- if pats:
- pats = [os.path.join(standindir, pat) for pat in pats]
+
+ # no warnings about missing files or directories
+ badfn = lambda f, msg: None
+
+ if rmatcher and not rmatcher.always():
+ pats = [os.path.join(standindir, pat) for pat in rmatcher.files()]
+ match = scmutil.match(repo[None], pats, badfn=badfn)
+ # if pats is empty, it would incorrectly always match, so clear _always
+ match._always = False
else:
# no patterns: relative to repo root
- pats = [standindir]
- # no warnings about missing files or directories
- match = scmutil.match(repo[None], pats, opts)
- match.bad = lambda f, msg: None
+ match = scmutil.match(repo[None], [standindir], badfn=badfn)
return match
def composestandinmatcher(repo, rmatcher):
'''Return a matcher that accepts standins corresponding to the
files accepted by rmatcher. Pass the list of files in the matcher
as the paths specified by the user.'''
- smatcher = getstandinmatcher(repo, rmatcher.files())
+ smatcher = getstandinmatcher(repo, rmatcher)
isstandin = smatcher.matchfn
def composedmatchfn(f):
return isstandin(f) and rmatcher.matchfn(splitstandin(f))
@@ -364,10 +368,10 @@
def islfilesrepo(repo):
if ('largefiles' in repo.requirements and
- util.any(shortnameslash in f[0] for f in repo.store.datafiles())):
+ any(shortnameslash in f[0] for f in repo.store.datafiles())):
return True
- return util.any(openlfdirstate(repo.ui, repo, False))
+ return any(openlfdirstate(repo.ui, repo, False))
class storeprotonotcapable(Exception):
def __init__(self, storetypes):
--- a/hgext/largefiles/overrides.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/largefiles/overrides.py Mon Jun 15 13:31:22 2015 -0500
@@ -27,7 +27,7 @@
m = copy.copy(match)
lfile = lambda f: lfutil.standin(f) in manifest
m._files = filter(lfile, m._files)
- m._fmap = set(m._files)
+ m._fileroots = set(m._files)
m._always = False
origmatchfn = m.matchfn
m.matchfn = lambda f: lfile(f) and origmatchfn(f)
@@ -42,7 +42,7 @@
notlfile = lambda f: not (lfutil.isstandin(f) or lfutil.standin(f) in
manifest or f in excluded)
m._files = filter(notlfile, m._files)
- m._fmap = set(m._files)
+ m._fileroots = set(m._files)
m._always = False
origmatchfn = m.matchfn
m.matchfn = lambda f: notlfile(f) and origmatchfn(f)
@@ -51,8 +51,8 @@
def installnormalfilesmatchfn(manifest):
'''installmatchfn with a matchfn that ignores all largefiles'''
def overridematch(ctx, pats=[], opts={}, globbed=False,
- default='relpath'):
- match = oldmatch(ctx, pats, opts, globbed, default)
+ default='relpath', badfn=None):
+ match = oldmatch(ctx, pats, opts, globbed, default, badfn=badfn)
return composenormalfilematcher(match, manifest)
oldmatch = installmatchfn(overridematch)
@@ -100,10 +100,10 @@
lfmatcher = match_.match(repo.root, '', list(lfpats))
lfnames = []
- m = copy.copy(matcher)
- m.bad = lambda x, y: None
+ m = matcher
+
wctx = repo[None]
- for f in repo.walk(m):
+ for f in repo.walk(match_.badmatch(m, lambda x, y: None)):
exact = m.exact(f)
lfile = lfutil.standin(f) in wctx
nfile = f in wctx
@@ -288,13 +288,14 @@
def overridelog(orig, ui, repo, *pats, **opts):
def overridematchandpats(ctx, pats=[], opts={}, globbed=False,
- default='relpath'):
+ default='relpath', badfn=None):
"""Matcher that merges root directory with .hglf, suitable for log.
It is still possible to match .hglf directly.
For any listed files run log on the standin too.
matchfn tries both the given filename and with .hglf stripped.
"""
- matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default)
+ matchandpats = oldmatchandpats(ctx, pats, opts, globbed, default,
+ badfn=badfn)
m, p = copy.copy(matchandpats)
if m.always():
@@ -358,7 +359,7 @@
and repo.wvfs.isdir(standin):
m._files.append(standin)
- m._fmap = set(m._files)
+ m._fileroots = set(m._files)
m._always = False
origmatchfn = m.matchfn
def lfmatchfn(f):
@@ -377,9 +378,9 @@
# (2) to determine what files to print out diffs for.
# The magic matchandpats override should be used for case (1) but not for
# case (2).
- def overridemakelogfilematcher(repo, pats, opts):
+ def overridemakelogfilematcher(repo, pats, opts, badfn=None):
wctx = repo[None]
- match, pats = oldmatchandpats(wctx, pats, opts)
+ match, pats = oldmatchandpats(wctx, pats, opts, badfn=badfn)
return lambda rev: match
oldmatchandpats = installmatchandpatsfn(overridematchandpats)
@@ -578,14 +579,13 @@
nolfiles = False
installnormalfilesmatchfn(repo[None].manifest())
try:
- try:
- result = orig(ui, repo, pats, opts, rename)
- except util.Abort, e:
- if str(e) != _('no files to copy'):
- raise e
- else:
- nonormalfiles = True
- result = 0
+ result = orig(ui, repo, pats, opts, rename)
+ except util.Abort, e:
+ if str(e) != _('no files to copy'):
+ raise e
+ else:
+ nonormalfiles = True
+ result = 0
finally:
restorematchfn()
@@ -608,86 +608,85 @@
os.makedirs(makestandin(dest))
try:
- try:
- # When we call orig below it creates the standins but we don't add
- # them to the dir state until later so lock during that time.
- wlock = repo.wlock()
+ # When we call orig below it creates the standins but we don't add
+ # them to the dir state until later so lock during that time.
+ wlock = repo.wlock()
- manifest = repo[None].manifest()
- def overridematch(ctx, pats=[], opts={}, globbed=False,
- default='relpath'):
- newpats = []
- # The patterns were previously mangled to add the standin
- # directory; we need to remove that now
- for pat in pats:
- if match_.patkind(pat) is None and lfutil.shortname in pat:
- newpats.append(pat.replace(lfutil.shortname, ''))
- else:
- newpats.append(pat)
- match = oldmatch(ctx, newpats, opts, globbed, default)
- m = copy.copy(match)
- lfile = lambda f: lfutil.standin(f) in manifest
- m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
- m._fmap = set(m._files)
- origmatchfn = m.matchfn
- m.matchfn = lambda f: (lfutil.isstandin(f) and
- (f in manifest) and
- origmatchfn(lfutil.splitstandin(f)) or
- None)
- return m
- oldmatch = installmatchfn(overridematch)
- listpats = []
+ manifest = repo[None].manifest()
+ def overridematch(ctx, pats=[], opts={}, globbed=False,
+ default='relpath', badfn=None):
+ newpats = []
+ # The patterns were previously mangled to add the standin
+ # directory; we need to remove that now
for pat in pats:
- if match_.patkind(pat) is not None:
- listpats.append(pat)
+ if match_.patkind(pat) is None and lfutil.shortname in pat:
+ newpats.append(pat.replace(lfutil.shortname, ''))
else:
- listpats.append(makestandin(pat))
+ newpats.append(pat)
+ match = oldmatch(ctx, newpats, opts, globbed, default, badfn=badfn)
+ m = copy.copy(match)
+ lfile = lambda f: lfutil.standin(f) in manifest
+ m._files = [lfutil.standin(f) for f in m._files if lfile(f)]
+ m._fileroots = set(m._files)
+ origmatchfn = m.matchfn
+ m.matchfn = lambda f: (lfutil.isstandin(f) and
+ (f in manifest) and
+ origmatchfn(lfutil.splitstandin(f)) or
+ None)
+ return m
+ oldmatch = installmatchfn(overridematch)
+ listpats = []
+ for pat in pats:
+ if match_.patkind(pat) is not None:
+ listpats.append(pat)
+ else:
+ listpats.append(makestandin(pat))
- try:
- origcopyfile = util.copyfile
- copiedfiles = []
- def overridecopyfile(src, dest):
- if (lfutil.shortname in src and
- dest.startswith(repo.wjoin(lfutil.shortname))):
- destlfile = dest.replace(lfutil.shortname, '')
- if not opts['force'] and os.path.exists(destlfile):
- raise IOError('',
- _('destination largefile already exists'))
- copiedfiles.append((src, dest))
- origcopyfile(src, dest)
-
- util.copyfile = overridecopyfile
- result += orig(ui, repo, listpats, opts, rename)
- finally:
- util.copyfile = origcopyfile
-
- lfdirstate = lfutil.openlfdirstate(ui, repo)
- for (src, dest) in copiedfiles:
+ try:
+ origcopyfile = util.copyfile
+ copiedfiles = []
+ def overridecopyfile(src, dest):
if (lfutil.shortname in src and
dest.startswith(repo.wjoin(lfutil.shortname))):
- srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
- destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
- destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
- if not os.path.isdir(destlfiledir):
- os.makedirs(destlfiledir)
- if rename:
- os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
+ destlfile = dest.replace(lfutil.shortname, '')
+ if not opts['force'] and os.path.exists(destlfile):
+ raise IOError('',
+ _('destination largefile already exists'))
+ copiedfiles.append((src, dest))
+ origcopyfile(src, dest)
+
+ util.copyfile = overridecopyfile
+ result += orig(ui, repo, listpats, opts, rename)
+ finally:
+ util.copyfile = origcopyfile
- # The file is gone, but this deletes any empty parent
- # directories as a side-effect.
- util.unlinkpath(repo.wjoin(srclfile), True)
- lfdirstate.remove(srclfile)
- else:
- util.copyfile(repo.wjoin(srclfile),
- repo.wjoin(destlfile))
+ lfdirstate = lfutil.openlfdirstate(ui, repo)
+ for (src, dest) in copiedfiles:
+ if (lfutil.shortname in src and
+ dest.startswith(repo.wjoin(lfutil.shortname))):
+ srclfile = src.replace(repo.wjoin(lfutil.standin('')), '')
+ destlfile = dest.replace(repo.wjoin(lfutil.standin('')), '')
+ destlfiledir = os.path.dirname(repo.wjoin(destlfile)) or '.'
+ if not os.path.isdir(destlfiledir):
+ os.makedirs(destlfiledir)
+ if rename:
+ os.rename(repo.wjoin(srclfile), repo.wjoin(destlfile))
- lfdirstate.add(destlfile)
- lfdirstate.write()
- except util.Abort, e:
- if str(e) != _('no files to copy'):
- raise e
- else:
- nolfiles = True
+ # The file is gone, but this deletes any empty parent
+ # directories as a side-effect.
+ util.unlinkpath(repo.wjoin(srclfile), True)
+ lfdirstate.remove(srclfile)
+ else:
+ util.copyfile(repo.wjoin(srclfile),
+ repo.wjoin(destlfile))
+
+ lfdirstate.add(destlfile)
+ lfdirstate.write()
+ except util.Abort, e:
+ if str(e) != _('no files to copy'):
+ raise e
+ else:
+ nolfiles = True
finally:
restorematchfn()
wlock.release()
@@ -724,8 +723,8 @@
oldstandins = lfutil.getstandinsstate(repo)
def overridematch(mctx, pats=[], opts={}, globbed=False,
- default='relpath'):
- match = oldmatch(mctx, pats, opts, globbed, default)
+ default='relpath', badfn=None):
+ match = oldmatch(mctx, pats, opts, globbed, default, badfn=badfn)
m = copy.copy(match)
# revert supports recursing into subrepos, and though largefiles
@@ -744,7 +743,7 @@
return f
m._files = [tostandin(f) for f in m._files]
m._files = [f for f in m._files if f is not None]
- m._fmap = set(m._files)
+ m._fileroots = set(m._files)
origmatchfn = m.matchfn
def matchfn(f):
if lfutil.isstandin(f):
@@ -985,7 +984,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/largefiles/proto.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/largefiles/proto.py Mon Jun 15 13:31:22 2015 -0500
@@ -31,17 +31,16 @@
tmpfp = util.atomictempfile(path, createmode=repo.store.createmode)
try:
- try:
- proto.getfile(tmpfp)
- tmpfp._fp.seek(0)
- if sha != lfutil.hexsha1(tmpfp._fp):
- raise IOError(0, _('largefile contents do not match hash'))
- tmpfp.close()
- lfutil.linktousercache(repo, sha)
- except IOError, e:
- repo.ui.warn(_('largefiles: failed to put %s into store: %s\n') %
- (sha, e.strerror))
- return wireproto.pushres(1)
+ proto.getfile(tmpfp)
+ tmpfp._fp.seek(0)
+ if sha != lfutil.hexsha1(tmpfp._fp):
+ raise IOError(0, _('largefile contents do not match hash'))
+ tmpfp.close()
+ lfutil.linktousercache(repo, sha)
+ except IOError, e:
+ repo.ui.warn(_('largefiles: failed to put %s into store: %s\n') %
+ (sha, e.strerror))
+ return wireproto.pushres(1)
finally:
tmpfp.discard()
--- a/hgext/largefiles/remotestore.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/largefiles/remotestore.py Mon Jun 15 13:31:22 2015 -0500
@@ -36,13 +36,12 @@
self.ui.debug('remotestore: sendfile(%s, %s)\n' % (filename, hash))
fd = None
try:
- try:
- fd = lfutil.httpsendfile(self.ui, filename)
- except IOError, e:
- raise util.Abort(
- _('remotestore: could not open file %s: %s')
- % (filename, str(e)))
+ fd = lfutil.httpsendfile(self.ui, filename)
return self._put(hash, fd)
+ except IOError, e:
+ raise util.Abort(
+ _('remotestore: could not open file %s: %s')
+ % (filename, str(e)))
finally:
if fd:
fd.close()
--- a/hgext/largefiles/reposetup.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/largefiles/reposetup.py Mon Jun 15 13:31:22 2015 -0500
@@ -365,7 +365,7 @@
repo.prepushoutgoinghooks.add("largefiles", prepushoutgoinghook)
def checkrequireslfiles(ui, repo, **kwargs):
- if 'largefiles' not in repo.requirements and util.any(
+ if 'largefiles' not in repo.requirements and any(
lfutil.shortname+'/' in f[0] for f in repo.store.datafiles()):
repo.requirements.add('largefiles')
repo._writerequirements()
--- a/hgext/mq.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/mq.py Mon Jun 15 13:31:22 2015 -0500
@@ -76,6 +76,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
# force load strip extension formerly included in mq and import some utility
@@ -298,7 +302,7 @@
self.haspatch = diffstart > 1
self.plainmode = (plainmode or
'# HG changeset patch' not in self.comments and
- util.any(c.startswith('Date: ') or
+ any(c.startswith('Date: ') or
c.startswith('From: ')
for c in self.comments))
@@ -376,14 +380,17 @@
if repo.ui.configbool('mq', 'secret', False):
phase = phases.secret
if phase is not None:
- backup = repo.ui.backupconfig('phases', 'new-commit')
+ phasebackup = repo.ui.backupconfig('phases', 'new-commit')
+ allowemptybackup = repo.ui.backupconfig('ui', 'allowemptycommit')
try:
if phase is not None:
repo.ui.setconfig('phases', 'new-commit', phase, 'mq')
+ repo.ui.setconfig('ui', 'allowemptycommit', True)
return repo.commit(*args, **kwargs)
finally:
+ repo.ui.restoreconfig(allowemptybackup)
if phase is not None:
- repo.ui.restoreconfig(backup)
+ repo.ui.restoreconfig(phasebackup)
class AbortNoCleanup(error.Abort):
pass
@@ -807,9 +814,10 @@
def apply(self, repo, series, list=False, update_status=True,
strict=False, patchdir=None, merge=None, all_files=None,
tobackup=None, keepchanges=False):
- wlock = lock = tr = None
+ wlock = dsguard = lock = tr = None
try:
wlock = repo.wlock()
+ dsguard = cmdutil.dirstateguard(repo, 'mq.apply')
lock = repo.lock()
tr = repo.transaction("qpush")
try:
@@ -818,21 +826,22 @@
tobackup=tobackup, keepchanges=keepchanges)
tr.close()
self.savedirty()
+ dsguard.close()
return ret
except AbortNoCleanup:
tr.close()
self.savedirty()
+ dsguard.close()
raise
except: # re-raises
try:
tr.abort()
finally:
repo.invalidate()
- repo.dirstate.invalidate()
self.invalidate()
raise
finally:
- release(tr, lock, wlock)
+ release(tr, lock, dsguard, wlock)
self.removeundo(repo)
def _apply(self, repo, series, list=False, update_status=True,
@@ -1093,9 +1102,9 @@
if name.startswith(prefix):
raise util.Abort(_('patch name cannot begin with "%s"')
% prefix)
- for c in ('#', ':'):
+ for c in ('#', ':', '\r', '\n'):
if c in name:
- raise util.Abort(_('"%s" cannot be used in the name of a patch')
+ raise util.Abort(_('%r cannot be used in the name of a patch')
% c)
def checkpatchname(self, name, force=False):
@@ -1129,12 +1138,11 @@
if inclsubs:
substatestate = repo.dirstate['.hgsubstate']
if opts.get('include') or opts.get('exclude') or pats:
- match = scmutil.match(repo[None], pats, opts)
# detect missing files in pats
def badfn(f, msg):
if f != '.hgsubstate': # .hgsubstate is auto-created
raise util.Abort('%s: %s' % (f, msg))
- match.bad = badfn
+ match = scmutil.match(repo[None], pats, opts, badfn=badfn)
changes = repo.status(match=match)
else:
changes = self.checklocalchanges(repo, force=True)
@@ -1517,7 +1525,7 @@
"managed by this patch queue"))
if not repo[self.applied[-1].node].mutable():
raise util.Abort(
- _("popping would remove an immutable revision"),
+ _("popping would remove a public revision"),
hint=_('see "hg help phases" for details'))
# we know there are no local changes, so we can make a simplified
@@ -1588,7 +1596,7 @@
if repo.changelog.heads(top) != [top]:
raise util.Abort(_("cannot refresh a revision with children"))
if not repo[top].mutable():
- raise util.Abort(_("cannot refresh immutable revision"),
+ raise util.Abort(_("cannot refresh public revision"),
hint=_('see "hg help phases" for details'))
cparents = repo.changelog.parents(top)
@@ -1681,8 +1689,9 @@
bmlist = repo[top].bookmarks()
+ dsguard = None
try:
- repo.dirstate.beginparentchange()
+ dsguard = cmdutil.dirstateguard(repo, 'mq.refresh')
if diffopts.git or diffopts.upgrade:
copies = {}
for dst in a:
@@ -1735,13 +1744,12 @@
# assumes strip can roll itself back if interrupted
repo.setparents(*cparents)
- repo.dirstate.endparentchange()
self.applied.pop()
self.applieddirty = True
strip(self.ui, repo, [top], update=False, backup=False)
- except: # re-raises
- repo.dirstate.invalidate()
- raise
+ dsguard.close()
+ finally:
+ release(dsguard)
try:
# might be nice to attempt to roll back strip after this
--- a/hgext/notify.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/notify.py Mon Jun 15 13:31:22 2015 -0500
@@ -134,13 +134,14 @@
'''
import email, socket, time
-# On python2.4 you have to import this by name or they fail to
-# 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
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
# template for single changeset can include email headers.
@@ -190,8 +191,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/pager.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/pager.py Mon Jun 15 13:31:22 2015 -0500
@@ -55,40 +55,16 @@
'''
-import atexit, sys, os, signal, subprocess, errno, shlex
+import atexit, sys, os, signal, subprocess
from mercurial import commands, dispatch, util, extensions, cmdutil
from mercurial.i18n import _
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
-def _pagerfork(ui, p):
- if not util.safehasattr(os, 'fork'):
- sys.stdout = util.popen(p, 'wb')
- if ui._isatty(sys.stderr):
- sys.stderr = sys.stdout
- return
- fdin, fdout = os.pipe()
- pid = os.fork()
- if pid == 0:
- os.close(fdin)
- os.dup2(fdout, sys.stdout.fileno())
- if ui._isatty(sys.stderr):
- os.dup2(fdout, sys.stderr.fileno())
- os.close(fdout)
- return
- os.dup2(fdin, sys.stdin.fileno())
- os.close(fdin)
- os.close(fdout)
- try:
- os.execvp('/bin/sh', ['/bin/sh', '-c', p])
- except OSError, e:
- if e.errno == errno.ENOENT:
- # no /bin/sh, try executing the pager directly
- args = shlex.split(p)
- os.execvp(args[0], args)
- else:
- raise
-
def _pagersubprocess(ui, p):
pager = subprocess.Popen(p, shell=True, bufsize=-1,
close_fds=util.closefds, stdin=subprocess.PIPE,
@@ -110,13 +86,7 @@
pager.wait()
def _runpager(ui, p):
- # The subprocess module shipped with Python <= 2.4 is buggy (issue3533).
- # The compat version is buggy on Windows (issue3225), but has been shipping
- # with hg for a long time. Preserve existing functionality.
- if sys.version_info >= (2, 5):
- _pagersubprocess(ui, p)
- else:
- _pagerfork(ui, p)
+ _pagersubprocess(ui, p)
def uisetup(ui):
if '--debugger' in sys.argv or not ui.formatted():
--- a/hgext/patchbomb.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/patchbomb.py Mon Jun 15 13:31:22 2015 -0500
@@ -59,10 +59,6 @@
import os, errno, socket, tempfile, cStringIO
import email
-# On python2.4 you have to import these by name or they fail to
-# load. This was not a problem on Python 2.7.
-import email.Generator
-import email.MIMEMultipart
from mercurial import cmdutil, commands, hg, mail, patch, util
from mercurial import scmutil
@@ -71,6 +67,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
def prompt(ui, prompt, default=None, rest=':'):
--- a/hgext/progress.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/progress.py Mon Jun 15 13:31:22 2015 -0500
@@ -5,316 +5,8 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-"""show progress bars for some actions
-
-This extension uses the progress information logged by hg commands
-to draw progress bars that are as informative as possible. Some progress
-bars only offer indeterminate information, while others have a definite
-end point.
-
-The following settings are available::
-
- [progress]
- delay = 3 # number of seconds (float) before showing the progress bar
- changedelay = 1 # changedelay: minimum delay before showing a new topic.
- # If set to less than 3 * refresh, that value will
- # be used instead.
- refresh = 0.1 # time in seconds between refreshes of the progress bar
- format = topic bar number estimate # format of the progress bar
- width = <none> # if set, the maximum width of the progress information
- # (that is, min(width, term width) will be used)
- clear-complete = True # clear the progress bar after it's done
- disable = False # if true, don't show a progress bar
- assume-tty = False # if true, ALWAYS show a progress bar, unless
- # disable is given
-
-Valid entries for the format field are topic, bar, number, unit,
-estimate, speed, and item. item defaults to the last 20 characters of
-the item, but this can be changed by adding either ``-<num>`` which
-would take the last num characters, or ``+<num>`` for the first num
-characters.
-"""
-
-import sys
-import time
-import threading
-
-from mercurial.i18n import _
-testedwith = 'internal'
-
-from mercurial import encoding
-
-def spacejoin(*args):
- return ' '.join(s for s in args if s)
-
-def shouldprint(ui):
- return not ui.plain() and (ui._isatty(sys.stderr) or
- ui.configbool('progress', 'assume-tty'))
-
-def fmtremaining(seconds):
- if seconds < 60:
- # i18n: format XX seconds as "XXs"
- return _("%02ds") % (seconds)
- minutes = seconds // 60
- if minutes < 60:
- seconds -= minutes * 60
- # i18n: format X minutes and YY seconds as "XmYYs"
- return _("%dm%02ds") % (minutes, seconds)
- # we're going to ignore seconds in this case
- minutes += 1
- hours = minutes // 60
- minutes -= hours * 60
- if hours < 30:
- # i18n: format X hours and YY minutes as "XhYYm"
- return _("%dh%02dm") % (hours, minutes)
- # we're going to ignore minutes in this case
- hours += 1
- days = hours // 24
- hours -= days * 24
- if days < 15:
- # i18n: format X days and YY hours as "XdYYh"
- return _("%dd%02dh") % (days, hours)
- # we're going to ignore hours in this case
- days += 1
- weeks = days // 7
- days -= weeks * 7
- if weeks < 55:
- # i18n: format X weeks and YY days as "XwYYd"
- return _("%dw%02dd") % (weeks, days)
- # we're going to ignore days and treat a year as 52 weeks
- weeks += 1
- years = weeks // 52
- weeks -= years * 52
- # i18n: format X years and YY weeks as "XyYYw"
- return _("%dy%02dw") % (years, weeks)
-
-class progbar(object):
- def __init__(self, ui):
- self.ui = ui
- self._refreshlock = threading.Lock()
- self.resetstate()
-
- def resetstate(self):
- self.topics = []
- self.topicstates = {}
- self.starttimes = {}
- self.startvals = {}
- self.printed = False
- self.lastprint = time.time() + float(self.ui.config(
- 'progress', 'delay', default=3))
- self.curtopic = None
- self.lasttopic = None
- self.indetcount = 0
- self.refresh = float(self.ui.config(
- 'progress', 'refresh', default=0.1))
- self.changedelay = max(3 * self.refresh,
- float(self.ui.config(
- 'progress', 'changedelay', default=1)))
- self.order = self.ui.configlist(
- 'progress', 'format',
- default=['topic', 'bar', 'number', 'estimate'])
+"""show progress bars for some actions (DEPRECATED)
- def show(self, now, topic, pos, item, unit, total):
- if not shouldprint(self.ui):
- return
- termwidth = self.width()
- self.printed = True
- head = ''
- needprogress = False
- tail = ''
- for indicator in self.order:
- add = ''
- if indicator == 'topic':
- add = topic
- elif indicator == 'number':
- if total:
- add = ('% ' + str(len(str(total))) +
- 's/%s') % (pos, total)
- else:
- add = str(pos)
- elif indicator.startswith('item') and item:
- slice = 'end'
- if '-' in indicator:
- wid = int(indicator.split('-')[1])
- elif '+' in indicator:
- slice = 'beginning'
- wid = int(indicator.split('+')[1])
- else:
- wid = 20
- if slice == 'end':
- add = encoding.trim(item, wid, leftside=True)
- else:
- add = encoding.trim(item, wid)
- add += (wid - encoding.colwidth(add)) * ' '
- elif indicator == 'bar':
- add = ''
- needprogress = True
- elif indicator == 'unit' and unit:
- add = unit
- elif indicator == 'estimate':
- add = self.estimate(topic, pos, total, now)
- elif indicator == 'speed':
- add = self.speed(topic, pos, unit, now)
- if not needprogress:
- head = spacejoin(head, add)
- else:
- tail = spacejoin(tail, add)
- if needprogress:
- used = 0
- if head:
- used += encoding.colwidth(head) + 1
- if tail:
- used += encoding.colwidth(tail) + 1
- progwidth = termwidth - used - 3
- if total and pos <= total:
- amt = pos * progwidth // total
- bar = '=' * (amt - 1)
- if amt > 0:
- bar += '>'
- bar += ' ' * (progwidth - amt)
- else:
- progwidth -= 3
- self.indetcount += 1
- # mod the count by twice the width so we can make the
- # cursor bounce between the right and left sides
- amt = self.indetcount % (2 * progwidth)
- amt -= progwidth
- bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
- ' ' * int(abs(amt)))
- prog = ''.join(('[', bar , ']'))
- out = spacejoin(head, prog, tail)
- else:
- out = spacejoin(head, tail)
- sys.stderr.write('\r' + encoding.trim(out, termwidth))
- self.lasttopic = topic
- sys.stderr.flush()
-
- def clear(self):
- if not shouldprint(self.ui):
- return
- sys.stderr.write('\r%s\r' % (' ' * self.width()))
-
- def complete(self):
- if not shouldprint(self.ui):
- return
- if self.ui.configbool('progress', 'clear-complete', default=True):
- self.clear()
- else:
- sys.stderr.write('\n')
- sys.stderr.flush()
-
- def width(self):
- tw = self.ui.termwidth()
- return min(int(self.ui.config('progress', 'width', default=tw)), tw)
-
- def estimate(self, topic, pos, total, now):
- if total is None:
- return ''
- initialpos = self.startvals[topic]
- target = total - initialpos
- delta = pos - initialpos
- if delta > 0:
- elapsed = now - self.starttimes[topic]
- if elapsed > float(
- self.ui.config('progress', 'estimate', default=2)):
- seconds = (elapsed * (target - delta)) // delta + 1
- return fmtremaining(seconds)
- return ''
-
- def speed(self, topic, pos, unit, now):
- initialpos = self.startvals[topic]
- delta = pos - initialpos
- elapsed = now - self.starttimes[topic]
- if elapsed > float(
- self.ui.config('progress', 'estimate', default=2)):
- return _('%d %s/sec') % (delta / elapsed, unit)
- return ''
-
- def _oktoprint(self, now):
- '''Check if conditions are met to print - e.g. changedelay elapsed'''
- if (self.lasttopic is None # first time we printed
- # not a topic change
- or self.curtopic == self.lasttopic
- # it's been long enough we should print anyway
- or now - self.lastprint >= self.changedelay):
- return True
- else:
- return False
-
- def progress(self, topic, pos, item='', unit='', total=None):
- now = time.time()
- self._refreshlock.acquire()
- try:
- if pos is None:
- self.starttimes.pop(topic, None)
- self.startvals.pop(topic, None)
- self.topicstates.pop(topic, None)
- # reset the progress bar if this is the outermost topic
- if self.topics and self.topics[0] == topic and self.printed:
- self.complete()
- self.resetstate()
- # truncate the list of topics assuming all topics within
- # this one are also closed
- if topic in self.topics:
- self.topics = self.topics[:self.topics.index(topic)]
- # reset the last topic to the one we just unwound to,
- # so that higher-level topics will be stickier than
- # lower-level topics
- if self.topics:
- self.lasttopic = self.topics[-1]
- else:
- self.lasttopic = None
- else:
- if topic not in self.topics:
- self.starttimes[topic] = now
- self.startvals[topic] = pos
- self.topics.append(topic)
- self.topicstates[topic] = pos, item, unit, total
- self.curtopic = topic
- if now - self.lastprint >= self.refresh and self.topics:
- if self._oktoprint(now):
- self.lastprint = now
- self.show(now, topic, *self.topicstates[topic])
- finally:
- self._refreshlock.release()
-
-_singleton = None
-
-def uisetup(ui):
- global _singleton
- class progressui(ui.__class__):
- _progbar = None
-
- def _quiet(self):
- return self.debugflag or self.quiet
-
- def progress(self, *args, **opts):
- if not self._quiet():
- self._progbar.progress(*args, **opts)
- return super(progressui, self).progress(*args, **opts)
-
- def write(self, *args, **opts):
- if not self._quiet() and self._progbar.printed:
- self._progbar.clear()
- return super(progressui, self).write(*args, **opts)
-
- def write_err(self, *args, **opts):
- if not self._quiet() and self._progbar.printed:
- self._progbar.clear()
- return super(progressui, self).write_err(*args, **opts)
-
- # Apps that derive a class from ui.ui() can use
- # setconfig('progress', 'disable', 'True') to disable this extension
- if ui.configbool('progress', 'disable'):
- return
- if shouldprint(ui) and not ui.debugflag and not ui.quiet:
- ui.__class__ = progressui
- # we instantiate one globally shared progress bar to avoid
- # competing progress bars when multiple UI objects get created
- if not progressui._progbar:
- if _singleton is None:
- _singleton = progbar(ui)
- progressui._progbar = _singleton
-
-def reposetup(ui, repo):
- uisetup(repo.ui)
+This extension has been merged into core, you can remove it from your config.
+See hg help config.progress for configuration options.
+"""
--- a/hgext/purge.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/purge.py Mon Jun 15 13:31:22 2015 -0500
@@ -30,6 +30,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
@command('purge|clean',
--- a/hgext/rebase.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/rebase.py Mon Jun 15 13:31:22 2015 -0500
@@ -29,6 +29,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
def _savegraft(ctx, extra):
@@ -67,7 +71,7 @@
('e', 'edit', False, _('invoke editor on commit messages')),
('l', 'logfile', '',
_('read collapse commit message from file'), _('FILE')),
- ('', 'keep', False, _('keep original changesets')),
+ ('k', 'keep', False, _('keep original changesets')),
('', 'keepbranches', False, _('keep original branch names')),
('D', 'detach', False, _('(DEPRECATED)')),
('i', 'interactive', False, _('(DEPRECATED)')),
@@ -326,7 +330,7 @@
root = min(rebaseset)
if not keepf and not repo[root].mutable():
- raise util.Abort(_("can't rebase immutable changeset %s")
+ raise util.Abort(_("can't rebase public changeset %s")
% repo[root],
hint=_('see "hg help phases" for details'))
@@ -358,9 +362,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 +502,7 @@
if (activebookmark and
repo['.'].node() == repo._bookmarks[activebookmark]):
- bookmarks.setcurrent(repo, activebookmark)
+ bookmarks.activate(repo, activebookmark)
finally:
release(lock, wlock)
@@ -530,10 +534,9 @@
'''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
but also store useful information in extra.
Return node of committed revision.'''
+ dsguard = cmdutil.dirstateguard(repo, 'rebase')
try:
- repo.dirstate.beginparentchange()
repo.setparents(repo[p1].node(), repo[p2].node())
- repo.dirstate.endparentchange()
ctx = repo[rev]
if commitmsg is None:
commitmsg = ctx.description()
@@ -552,11 +555,10 @@
repo.ui.restoreconfig(backup)
repo.dirstate.setbranch(repo[newnode].branch())
+ dsguard.close()
return newnode
- except util.Abort:
- # Invalidate the previous setparents
- repo.dirstate.invalidate()
- raise
+ finally:
+ release(dsguard)
def rebasenode(repo, rev, p1, base, state, collapse, target):
'Rebase a single revision rev on top of p1 using base as merge ancestor'
@@ -867,7 +869,7 @@
immutable = [d for d in dstates if not repo[d].mutable()]
cleanup = True
if immutable:
- repo.ui.warn(_("warning: can't clean up immutable changesets %s\n")
+ repo.ui.warn(_("warning: can't clean up public changesets %s\n")
% ', '.join(str(repo[r]) for r in immutable),
hint=_('see "hg help phases" for details'))
cleanup = False
@@ -893,7 +895,7 @@
repair.strip(repo.ui, repo, strippoints)
if activebookmark and activebookmark in repo._bookmarks:
- bookmarks.setcurrent(repo, activebookmark)
+ bookmarks.activate(repo, activebookmark)
clearstatus(repo)
repo.ui.warn(_('rebase aborted\n'))
@@ -1057,7 +1059,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'))
@@ -1118,4 +1120,3 @@
_("use 'hg rebase --continue' or 'hg rebase --abort'")])
# ensure rebased rev are not hidden
extensions.wrapfunction(repoview, '_getdynamicblockers', _rebasedvisible)
-
--- a/hgext/record.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/record.py Mon Jun 15 13:31:22 2015 -0500
@@ -13,6 +13,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
@@ -50,7 +54,12 @@
This command is not available when committing a merge.'''
opts["interactive"] = True
- commands.commit(ui, repo, *pats, **opts)
+ backup = ui.backupconfig('experimental', 'crecord')
+ try:
+ ui.setconfig('experimental', 'crecord', False, 'record')
+ commands.commit(ui, repo, *pats, **opts)
+ finally:
+ ui.restoreconfig(backup)
def qrefresh(origfn, ui, repo, *pats, **opts):
if not opts['interactive']:
@@ -92,8 +101,13 @@
opts['checkname'] = False
mq.new(ui, repo, patch, *pats, **opts)
- cmdutil.dorecord(ui, repo, committomq, 'qnew', False,
- cmdutil.recordfilter, *pats, **opts)
+ backup = ui.backupconfig('experimental', 'crecord')
+ try:
+ ui.setconfig('experimental', 'crecord', False, 'record')
+ cmdutil.dorecord(ui, repo, committomq, 'qnew', False,
+ cmdutil.recordfilter, *pats, **opts)
+ finally:
+ ui.restoreconfig(backup)
def qnew(origfn, ui, repo, patch, *args, **opts):
if opts['interactive']:
--- a/hgext/relink.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/relink.py Mon Jun 15 13:31:22 2015 -0500
@@ -13,6 +13,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
@command('relink', [], _('[ORIGIN]'))
--- a/hgext/schemes.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/schemes.py Mon Jun 15 13:31:22 2015 -0500
@@ -44,6 +44,10 @@
from mercurial import extensions, hg, templater, util
from mercurial.i18n import _
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
--- a/hgext/share.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/share.py Mon Jun 15 13:31:22 2015 -0500
@@ -12,6 +12,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
@command('share',
--- a/hgext/shelve.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/shelve.py Mon Jun 15 13:31:22 2015 -0500
@@ -21,6 +21,7 @@
shelve".
"""
+import collections
from mercurial.i18n import _
from mercurial.node import nullid, nullrev, bin, hex
from mercurial import changegroup, cmdutil, scmutil, phases, commands
@@ -32,6 +33,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
class shelvedfile(object):
@@ -143,7 +148,7 @@
Much faster than the revset ancestors(ctx) & draft()"""
seen = set([nullrev])
- visit = util.deque()
+ visit = collections.deque()
visit.append(ctx)
while visit:
ctx = visit.popleft()
@@ -163,7 +168,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('/', '_')
@@ -284,17 +289,15 @@
"""subcommand that deletes a specific shelve"""
if not pats:
raise util.Abort(_('no shelved changes specified!'))
- wlock = None
+ wlock = repo.wlock()
try:
- wlock = repo.wlock()
- try:
- for name in pats:
- for suffix in 'hg patch'.split():
- shelvedfile(repo, name, suffix).unlink()
- except OSError, err:
- if err.errno != errno.ENOENT:
- raise
- raise util.Abort(_("shelved change '%s' not found") % name)
+ for name in pats:
+ for suffix in 'hg patch'.split():
+ shelvedfile(repo, name, suffix).unlink()
+ except OSError, err:
+ if err.errno != errno.ENOENT:
+ raise
+ raise util.Abort(_("shelved change '%s' not found") % name)
finally:
lockmod.release(wlock)
@@ -363,6 +366,17 @@
finally:
fp.close()
+def singlepatchcmds(ui, repo, pats, opts, subcommand):
+ """subcommand that displays a single shelf"""
+ if len(pats) != 1:
+ raise util.Abort(_("--%s expects a single shelf") % subcommand)
+ shelfname = pats[0]
+
+ if not shelvedfile(repo, shelfname, 'patch').exists():
+ raise util.Abort(_("cannot find shelf %s") % shelfname)
+
+ listcmd(ui, repo, pats, opts)
+
def checkparents(repo, state):
"""check parent while resuming an unshelve"""
if state.parents != repo.dirstate.parents():
@@ -658,8 +672,7 @@
('p', 'patch', None,
_('show patch')),
('i', 'interactive', None,
- _('interactive mode, only works while creating a shelve'
- '(EXPERIMENTAL)')),
+ _('interactive mode, only works while creating a shelve')),
('', 'stat', None,
_('output diffstat-style summary of changes'))] + commands.walkopts,
_('hg shelve [OPTION]... [FILE]...'))
@@ -693,21 +706,21 @@
cmdutil.checkunfinished(repo)
allowables = [
- ('addremove', 'create'), # 'create' is pseudo action
- ('cleanup', 'cleanup'),
-# ('date', 'create'), # ignored for passing '--date "0 0"' in tests
- ('delete', 'delete'),
- ('edit', 'create'),
- ('list', 'list'),
- ('message', 'create'),
- ('name', 'create'),
- ('patch', 'list'),
- ('stat', 'list'),
+ ('addremove', set(['create'])), # 'create' is pseudo action
+ ('cleanup', set(['cleanup'])),
+# ('date', set(['create'])), # ignored for passing '--date "0 0"' in tests
+ ('delete', set(['delete'])),
+ ('edit', set(['create'])),
+ ('list', set(['list'])),
+ ('message', set(['create'])),
+ ('name', set(['create'])),
+ ('patch', set(['patch', 'list'])),
+ ('stat', set(['stat', 'list'])),
]
def checkopt(opt):
if opts[opt]:
for i, allowable in allowables:
- if opts[i] and opt != allowable:
+ if opts[i] and opt not in allowable:
raise util.Abort(_("options '--%s' and '--%s' may not be "
"used together") % (opt, i))
return True
@@ -719,11 +732,11 @@
return deletecmd(ui, repo, pats)
elif checkopt('list'):
return listcmd(ui, repo, pats, opts)
+ elif checkopt('patch'):
+ return singlepatchcmds(ui, repo, pats, opts, subcommand='patch')
+ elif checkopt('stat'):
+ return singlepatchcmds(ui, repo, pats, opts, subcommand='stat')
else:
- for i in ('patch', 'stat'):
- if opts[i]:
- raise util.Abort(_("option '--%s' may not be "
- "used when shelving a change") % (i,))
return createcmd(ui, repo, pats, opts)
def extsetup(ui):
--- a/hgext/strip.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/strip.py Mon Jun 15 13:31:22 2015 -0500
@@ -11,6 +11,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
def checksubstate(repo, baserev=None):
@@ -60,8 +64,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/hgext/transplant.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/transplant.py Mon Jun 15 13:31:22 2015 -0500
@@ -26,6 +26,10 @@
cmdtable = {}
command = cmdutil.command(cmdtable)
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
class transplantentry(object):
--- a/hgext/win32mbcs.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/win32mbcs.py Mon Jun 15 13:31:22 2015 -0500
@@ -48,6 +48,10 @@
import os, sys
from mercurial.i18n import _
from mercurial import util, encoding
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
_encoding = None # see extsetup
--- a/hgext/win32text.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/win32text.py Mon Jun 15 13:31:22 2015 -0500
@@ -46,6 +46,10 @@
from mercurial import util
import re
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
# regexp for single LF without CR preceding.
--- a/hgext/zeroconf/__init__.py Sat Jun 13 20:14:22 2015 +0900
+++ b/hgext/zeroconf/__init__.py Mon Jun 15 13:31:22 2015 -0500
@@ -31,6 +31,10 @@
from mercurial import extensions
from mercurial.hgweb import server as servermod
+# Note for extension authors: ONLY specify testedwith = 'internal' for
+# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
+# be specifying the version(s) of Mercurial they are tested with, or
+# leave the attribute unspecified.
testedwith = 'internal'
# publish
--- a/mercurial/ancestor.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/ancestor.py Mon Jun 15 13:31:22 2015 -0500
@@ -5,8 +5,8 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+import collections
import heapq
-import util
from node import nullrev
def commonancestorsheads(pfunc, *nodes):
@@ -314,7 +314,7 @@
parentrevs = self._parentrevs
stoprev = self._stoprev
- visit = util.deque(revs)
+ visit = collections.deque(revs)
while visit:
for parent in parentrevs(visit.popleft()):
--- a/mercurial/archival.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/archival.py Mon Jun 15 13:31:22 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
@@ -50,7 +54,7 @@
def guesskind(dest):
for kind, extensions in exts.iteritems():
- if util.any(dest.endswith(ext) for ext in extensions):
+ if any(dest.endswith(ext) for ext in extensions):
return kind
return None
--- a/mercurial/bookmarks.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/bookmarks.py Mon Jun 15 13:31:22 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):
@@ -22,7 +22,7 @@
{hash}\s{name}\n (the same format as localtags) in
.hg/bookmarks. The mapping is stored as {name: nodeid}.
- This class does NOT handle the "current" bookmark state at this
+ This class does NOT handle the "active" bookmark state at this
time.
"""
@@ -80,11 +80,12 @@
'''
repo = self._repo
self._writerepo(repo)
+ repo.invalidatevolatilesets()
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 +107,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,17 +129,17 @@
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
- if current == mark:
+ active = repo._activebookmark
+ if active == mark:
return
wlock = repo.wlock()
@@ -149,42 +149,36 @@
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
- except OSError, inst:
- if inst.errno != errno.ENOENT:
- raise
+ repo.vfs.unlink('bookmarks.current')
+ 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,33 +201,33 @@
check out and where to move the active bookmark from, if needed.'''
movemarkfrom = None
if checkout is None:
- curmark = repo._bookmarkcurrent
- if iscurrent(repo):
+ activemark = repo._activebookmark
+ if isactivewdirparent(repo):
movemarkfrom = repo['.'].node()
- elif curmark:
- ui.status(_("updating to active bookmark %s\n") % curmark)
- checkout = curmark
+ elif activemark:
+ ui.status(_("updating to active bookmark %s\n") % activemark)
+ checkout = activemark
return (checkout, movemarkfrom)
def update(repo, parents, node):
deletefrom = parents
marks = repo._bookmarks
update = False
- cur = repo._bookmarkcurrent
- if not cur:
+ active = repo._activebookmark
+ if not active:
return False
- if marks[cur] in parents:
+ if marks[active] in parents:
new = repo[node]
divs = [repo[b] for b in marks
- if b.split('@', 1)[0] == cur.split('@', 1)[0]]
+ if b.split('@', 1)[0] == active.split('@', 1)[0]]
anc = repo.changelog.ancestors([new.rev()])
deletefrom = [b.node() for b in divs if b.rev() in anc or b == new]
- if validdest(repo, repo[marks[cur]], new):
- marks[cur] = new.node()
+ if validdest(repo, repo[marks[active]], new):
+ marks[active] = new.node()
update = True
- if deletedivergent(repo, deletefrom, cur):
+ if deletedivergent(repo, deletefrom, active):
update = True
if update:
@@ -408,6 +402,11 @@
if scid in repo: # add remote bookmarks for changes we already have
changed.append((b, bin(scid), status,
_("adding remote bookmark %s\n") % (b)))
+ elif b in explicit:
+ explicit.remove(b)
+ ui.warn(_("remote bookmark %s points to locally missing %s\n")
+ % (b, scid[:12]))
+
for b, scid, dcid in advsrc:
changed.append((b, bin(scid), status,
_("updating bookmark %s\n") % (b)))
@@ -434,6 +433,11 @@
explicit.discard(b)
changed.append((b, bin(scid), status,
_("importing bookmark %s\n") % (b)))
+ for b, scid, dcid in differ:
+ if b in explicit:
+ explicit.remove(b)
+ ui.warn(_("remote bookmark %s points to locally missing %s\n")
+ % (b, scid[:12]))
if changed:
tr = trfunc()
--- a/mercurial/bundle2.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/bundle2.py Mon Jun 15 13:31:22 2015 -0500
@@ -66,7 +66,7 @@
:header size: int32
- The total number of Bytes used by the part headers. When the header is empty
+ The total number of Bytes used by the part header. When the header is empty
(size = 0) this is interpreted as the end of stream marker.
:header:
@@ -156,7 +156,7 @@
import url
import re
-import changegroup, error
+import changegroup, error, tags
from i18n import _
_pack = struct.pack
@@ -173,6 +173,16 @@
_parttypeforbidden = re.compile('[^a-zA-Z0-9_:-]')
+def outdebug(ui, message):
+ """debug regarding output stream (bundling)"""
+ if ui.configbool('devel', 'bundle2.debug', False):
+ ui.debug('bundle2-output: %s\n' % message)
+
+def indebug(ui, message):
+ """debug on input stream (unbundling)"""
+ if ui.configbool('devel', 'bundle2.debug', False):
+ ui.debug('bundle2-input: %s\n' % message)
+
def validateparttype(parttype):
"""raise ValueError if a parttype contains invalid character"""
if _parttypeforbidden.search(parttype):
@@ -310,13 +320,24 @@
# - replace this is a init function soon.
# - exception catching
unbundler.params
- iterparts = unbundler.iterparts()
+ if repo.ui.debugflag:
+ msg = ['bundle2-input-bundle:']
+ if unbundler.params:
+ msg.append(' %i params')
+ if op.gettransaction is None:
+ msg.append(' no-transaction')
+ else:
+ msg.append(' with-transaction')
+ msg.append('\n')
+ repo.ui.debug(''.join(msg))
+ iterparts = enumerate(unbundler.iterparts())
part = None
+ nbpart = 0
try:
- for part in iterparts:
+ for nbpart, part in iterparts:
_processpart(op, part)
- except Exception, exc:
- for part in iterparts:
+ except BaseException, exc:
+ for nbpart, part in iterparts:
# consume the bundle content
part.seek(0, 2)
# Small hack to let caller code distinguish exceptions from bundle2
@@ -326,10 +347,16 @@
# craziness in a future version.
exc.duringunbundle2 = True
salvaged = []
+ replycaps = None
if op.reply is not None:
salvaged = op.reply.salvageoutput()
+ replycaps = op.reply.capabilities
+ exc._replycaps = replycaps
exc._bundle2salvagedoutput = salvaged
raise
+ finally:
+ repo.ui.debug('bundle2-input-bundle: %i parts total\n' % nbpart)
+
return op
def _processpart(op, part):
@@ -337,23 +364,43 @@
The part is guaranteed to have been fully consumed when the function exits
(even if an exception is raised)."""
+ status = 'unknown' # used by debug output
try:
try:
handler = parthandlermapping.get(part.type)
if handler is None:
+ status = 'unsupported-type'
raise error.UnsupportedPartError(parttype=part.type)
- op.ui.debug('found a handler for part %r\n' % part.type)
+ indebug(op.ui, 'found a handler for part %r' % part.type)
unknownparams = part.mandatorykeys - handler.params
if unknownparams:
unknownparams = list(unknownparams)
unknownparams.sort()
+ status = 'unsupported-params (%s)' % unknownparams
raise error.UnsupportedPartError(parttype=part.type,
params=unknownparams)
+ status = 'supported'
except error.UnsupportedPartError, exc:
if part.mandatory: # mandatory parts
raise
- op.ui.debug('ignoring unsupported advisory part %s\n' % exc)
+ indebug(op.ui, 'ignoring unsupported advisory part %s' % exc)
return # skip to part processing
+ finally:
+ if op.ui.debugflag:
+ msg = ['bundle2-input-part: "%s"' % part.type]
+ if not part.mandatory:
+ msg.append(' (advisory)')
+ nbmp = len(part.mandatorykeys)
+ nbap = len(part.params) - nbmp
+ if nbmp or nbap:
+ msg.append(' (params:')
+ if nbmp:
+ msg.append(' %i mandatory' % nbmp)
+ if nbap:
+ msg.append(' %i advisory' % nbmp)
+ msg.append(')')
+ msg.append(' %s\n' % status)
+ op.ui.debug(''.join(msg))
# handler is called outside the above try block so that we don't
# risk catching KeyErrors from anything other than the
@@ -464,20 +511,26 @@
# methods used to generate the bundle2 stream
def getchunks(self):
- self.ui.debug('start emission of %s stream\n' % self._magicstring)
+ if self.ui.debugflag:
+ msg = ['bundle2-output-bundle: "%s",' % self._magicstring]
+ if self._params:
+ msg.append(' (%i params)' % len(self._params))
+ msg.append(' %i parts total\n' % len(self._parts))
+ self.ui.debug(''.join(msg))
+ outdebug(self.ui, 'start emission of %s stream' % self._magicstring)
yield self._magicstring
param = self._paramchunk()
- self.ui.debug('bundle parameter: %s\n' % param)
+ outdebug(self.ui, 'bundle parameter: %s' % param)
yield _pack(_fstreamparamsize, len(param))
if param:
yield param
- self.ui.debug('start of parts\n')
+ outdebug(self.ui, 'start of parts')
for part in self._parts:
- self.ui.debug('bundle part: "%s"\n' % part.type)
- for chunk in part.getchunks():
+ outdebug(self.ui, 'bundle part: "%s"' % part.type)
+ for chunk in part.getchunks(ui=self.ui):
yield chunk
- self.ui.debug('end of bundle\n')
+ outdebug(self.ui, 'end of bundle')
yield _pack(_fpartheadersize, 0)
def _paramchunk(self):
@@ -555,7 +608,7 @@
if unbundlerclass is None:
raise util.Abort(_('unknown bundle version %s') % version)
unbundler = unbundlerclass(ui, fp)
- ui.debug('start processing of %s stream\n' % header)
+ indebug(ui, 'start processing of %s stream' % header)
return unbundler
class unbundle20(unpackermixin):
@@ -572,7 +625,7 @@
@util.propertycache
def params(self):
"""dictionary of stream level parameters"""
- self.ui.debug('reading bundle2 stream parameters\n')
+ indebug(self.ui, 'reading bundle2 stream parameters')
params = {}
paramssize = self._unpack(_fstreamparamsize)[0]
if paramssize < 0:
@@ -605,7 +658,7 @@
# Some logic will be later added here to try to process the option for
# a dict of known parameter.
if name[0].islower():
- self.ui.debug("ignoring unknown parameter %r\n" % name)
+ indebug(self.ui, "ignoring unknown parameter %r" % name)
else:
raise error.UnsupportedPartError(params=(name,))
@@ -614,14 +667,14 @@
"""yield all parts contained in the stream"""
# make sure param have been loaded
self.params
- self.ui.debug('start extraction of bundle2 parts\n')
+ indebug(self.ui, 'start extraction of bundle2 parts')
headerblock = self._readpartheader()
while headerblock is not None:
part = unbundlepart(self.ui, headerblock, self._fp)
yield part
part.seek(0, 2)
headerblock = self._readpartheader()
- self.ui.debug('end of bundle2 stream\n')
+ indebug(self.ui, 'end of bundle2 stream')
def _readpartheader(self):
"""reads a part header size and return the bytes blob
@@ -631,7 +684,7 @@
if headersize < 0:
raise error.BundleValueError('negative part header size: %i'
% headersize)
- self.ui.debug('part header size: %i\n' % headersize)
+ indebug(self.ui, 'part header size: %i' % headersize)
if headersize:
return self._readexact(headersize)
return None
@@ -718,15 +771,39 @@
params.append((name, value))
# methods used to generates the bundle2 stream
- def getchunks(self):
+ def getchunks(self, ui):
if self._generated is not None:
raise RuntimeError('part can only be consumed once')
self._generated = False
+
+ if ui.debugflag:
+ msg = ['bundle2-output-part: "%s"' % self.type]
+ if not self.mandatory:
+ msg.append(' (advisory)')
+ nbmp = len(self.mandatoryparams)
+ nbap = len(self.advisoryparams)
+ if nbmp or nbap:
+ msg.append(' (params:')
+ if nbmp:
+ msg.append(' %i mandatory' % nbmp)
+ if nbap:
+ msg.append(' %i advisory' % nbmp)
+ msg.append(')')
+ if not self.data:
+ msg.append(' empty payload')
+ elif util.safehasattr(self.data, 'next'):
+ msg.append(' streamed payload')
+ else:
+ msg.append(' %i bytes payload' % len(self.data))
+ msg.append('\n')
+ ui.debug(''.join(msg))
+
#### header
if self.mandatory:
parttype = self.type.upper()
else:
parttype = self.type.lower()
+ outdebug(ui, 'part %s: "%s"' % (self.id, parttype))
## parttype
header = [_pack(_fparttypesize, len(parttype)),
parttype, _pack(_fpartid, self.id),
@@ -755,27 +832,33 @@
header.append(value)
## finalize header
headerchunk = ''.join(header)
+ outdebug(ui, 'header chunk size: %i' % len(headerchunk))
yield _pack(_fpartheadersize, len(headerchunk))
yield headerchunk
## payload
try:
for chunk in self._payloadchunks():
+ outdebug(ui, 'payload chunk size: %i' % len(chunk))
yield _pack(_fpayloadsize, len(chunk))
yield chunk
- except Exception, exc:
+ except BaseException, exc:
# backup exception data for later
+ ui.debug('bundle2-input-stream-interrupt: encoding exception %s'
+ % exc)
exc_info = sys.exc_info()
msg = 'unexpected error: %s' % exc
interpart = bundlepart('error:abort', [('message', msg)],
mandatory=False)
interpart.id = 0
yield _pack(_fpayloadsize, -1)
- for chunk in interpart.getchunks():
+ for chunk in interpart.getchunks(ui=ui):
yield chunk
+ outdebug(ui, 'closing payload chunk')
# abort current part payload
yield _pack(_fpayloadsize, 0)
raise exc_info[0], exc_info[1], exc_info[2]
# end of payload
+ outdebug(ui, 'closing payload chunk')
yield _pack(_fpayloadsize, 0)
self._generated = True
@@ -817,20 +900,25 @@
if headersize < 0:
raise error.BundleValueError('negative part header size: %i'
% headersize)
- self.ui.debug('part header size: %i\n' % headersize)
+ indebug(self.ui, 'part header size: %i\n' % headersize)
if headersize:
return self._readexact(headersize)
return None
def __call__(self):
- self.ui.debug('bundle2 stream interruption, looking for a part.\n')
+
+ self.ui.debug('bundle2-input-stream-interrupt:'
+ ' opening out of band context\n')
+ indebug(self.ui, 'bundle2 stream interruption, looking for a part.')
headerblock = self._readpartheader()
if headerblock is None:
- self.ui.debug('no part found during interruption.\n')
+ indebug(self.ui, 'no part found during interruption.')
return
part = unbundlepart(self.ui, headerblock, self._fp)
op = interruptoperation(self.ui)
_processpart(op, part)
+ self.ui.debug('bundle2-input-stream-interrupt:'
+ ' closing out of band context\n')
class interruptoperation(object):
"""A limited operation to be use by part handler during interruption
@@ -910,7 +998,7 @@
pos = self._chunkindex[chunknum][0]
payloadsize = self._unpack(_fpayloadsize)[0]
- self.ui.debug('payload chunk size: %i\n' % payloadsize)
+ indebug(self.ui, 'payload chunk size: %i' % payloadsize)
while payloadsize:
if payloadsize == flaginterrupt:
# interruption detection, the handler will now read a
@@ -928,7 +1016,7 @@
super(unbundlepart, self).tell()))
yield result
payloadsize = self._unpack(_fpayloadsize)[0]
- self.ui.debug('payload chunk size: %i\n' % payloadsize)
+ indebug(self.ui, 'payload chunk size: %i' % payloadsize)
def _findchunk(self, pos):
'''for a given payload position, return a chunk number and offset'''
@@ -943,16 +1031,16 @@
"""read the header and setup the object"""
typesize = self._unpackheader(_fparttypesize)[0]
self.type = self._fromheader(typesize)
- self.ui.debug('part type: "%s"\n' % self.type)
+ indebug(self.ui, 'part type: "%s"' % self.type)
self.id = self._unpackheader(_fpartid)[0]
- self.ui.debug('part id: "%s"\n' % self.id)
+ indebug(self.ui, 'part id: "%s"' % self.id)
# extract mandatory bit from type
self.mandatory = (self.type != self.type.lower())
self.type = self.type.lower()
## reading parameters
# param count
mancount, advcount = self._unpackheader(_fpartparamcount)
- self.ui.debug('part parameters: %i\n' % (mancount + advcount))
+ indebug(self.ui, 'part parameters: %i' % (mancount + advcount))
# param size
fparamsizes = _makefpartparamsizes(mancount + advcount)
paramsizes = self._unpackheader(fparamsizes)
@@ -982,9 +1070,12 @@
data = self._payloadstream.read()
else:
data = self._payloadstream.read(size)
+ self._pos += len(data)
if size is None or len(data) < size:
+ if not self.consumed and self._pos:
+ self.ui.debug('bundle2-input-part: total payload size %i\n'
+ % self._pos)
self.consumed = True
- self._pos += len(data)
return data
def tell(self):
@@ -1015,11 +1106,16 @@
raise util.Abort(_('Seek failed\n'))
self._pos = newpos
+# These are only the static capabilities.
+# Check the 'getrepocaps' function for the rest.
capabilities = {'HG20': (),
+ 'error': ('abort', 'unsupportedcontent', 'pushraced',
+ 'pushkey'),
'listkeys': (),
'pushkey': (),
'digests': tuple(sorted(util.DIGESTS.keys())),
'remote-changegroup': ('http', 'https'),
+ 'hgtagsfnodes': (),
}
def getrepocaps(repo, allowpushback=False):
@@ -1050,7 +1146,7 @@
obscaps = caps.get('obsmarkers', ())
return [int(c[1:]) for c in obscaps if c.startswith('V')]
-@parthandler('changegroup', ('version',))
+@parthandler('changegroup', ('version', 'nbchanges'))
def handlechangegroup(op, inpart):
"""apply a changegroup part on the repo
@@ -1069,7 +1165,11 @@
cg = unpacker(inpart, 'UN')
# the source and url passed here are overwritten by the one contained in
# the transaction.hookargs argument. So 'bundle2' is a placeholder
- ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
+ nbchangesets = None
+ if 'nbchanges' in inpart.params:
+ nbchangesets = int(inpart.params.get('nbchanges'))
+ ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2',
+ expectedtotal=nbchangesets)
op.records.add('changegroup', {'return': ret})
if op.reply is not None:
# This is definitely not the final form of this
@@ -1195,6 +1295,17 @@
"""Used to transmit abort error over the wire"""
raise util.Abort(inpart.params['message'], hint=inpart.params.get('hint'))
+@parthandler('error:pushkey', ('namespace', 'key', 'new', 'old', 'ret',
+ 'in-reply-to'))
+def handleerrorpushkey(op, inpart):
+ """Used to transmit failure of a mandatory pushkey over the wire"""
+ kwargs = {}
+ for name in ('namespace', 'key', 'new', 'old', 'ret'):
+ value = inpart.params.get(name)
+ if value is not None:
+ kwargs[name] = value
+ raise error.PushkeyFailed(inpart.params['in-reply-to'], **kwargs)
+
@parthandler('error:unsupportedcontent', ('parttype', 'params'))
def handleerrorunsupportedcontent(op, inpart):
"""Used to transmit unknown content error over the wire"""
@@ -1238,6 +1349,12 @@
rpart = op.reply.newpart('reply:pushkey')
rpart.addparam('in-reply-to', str(inpart.id), mandatory=False)
rpart.addparam('return', '%i' % ret, mandatory=False)
+ if inpart.mandatory and not ret:
+ kwargs = {}
+ for key in ('namespace', 'key', 'new', 'old', 'ret'):
+ if key in inpart.params:
+ kwargs[key] = inpart.params[key]
+ raise error.PushkeyFailed(partid=str(inpart.id), **kwargs)
@parthandler('reply:pushkey', ('return', 'in-reply-to'))
def handlepushkeyreply(op, inpart):
@@ -1265,8 +1382,29 @@
@parthandler('reply:obsmarkers', ('new', 'in-reply-to'))
-def handlepushkeyreply(op, inpart):
+def handleobsmarkerreply(op, inpart):
"""retrieve the result of a pushkey request"""
ret = int(inpart.params['new'])
partid = int(inpart.params['in-reply-to'])
op.records.add('obsmarkers', {'new': ret}, partid)
+
+@parthandler('hgtagsfnodes')
+def handlehgtagsfnodes(op, inpart):
+ """Applies .hgtags fnodes cache entries to the local repo.
+
+ Payload is pairs of 20 byte changeset nodes and filenodes.
+ """
+ cache = tags.hgtagsfnodescache(op.repo.unfiltered())
+
+ count = 0
+ while True:
+ node = inpart.read(20)
+ fnode = inpart.read(20)
+ if len(node) < 20 or len(fnode) < 20:
+ op.ui.debug('received incomplete .hgtags fnodes data, ignoring\n')
+ break
+ cache.setfnode(node, fnode)
+ count += 1
+
+ cache.write()
+ op.ui.debug('applied %i hgtags fnodes cache entries\n' % count)
--- a/mercurial/bundlerepo.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/bundlerepo.py Mon Jun 15 13:31:22 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 Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/changegroup.py Mon Jun 15 13:31:22 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)
@@ -607,7 +615,7 @@
bundler = cg1packer(repo, bundlecaps)
return getsubset(repo, outgoing, bundler, source)
-def _computeoutgoing(repo, heads, common):
+def computeoutgoing(repo, heads, common):
"""Computes which revs are outgoing given a set of common
and a set of heads.
@@ -626,22 +634,6 @@
heads = cl.heads()
return discovery.outgoing(cl, common, heads)
-def getchangegroupraw(repo, source, heads=None, common=None, bundlecaps=None,
- version='01'):
- """Like changegroupsubset, but returns the set difference between the
- ancestors of heads and the ancestors common.
-
- If heads is None, use the local heads. If common is None, use [nullid].
-
- If version is None, use a version '1' changegroup.
-
- The nodes in common might not all be known locally due to the way the
- current discovery protocol works. Returns a raw changegroup generator.
- """
- outgoing = _computeoutgoing(repo, heads, common)
- return getlocalchangegroupraw(repo, source, outgoing, bundlecaps=bundlecaps,
- version=version)
-
def getchangegroup(repo, source, heads=None, common=None, bundlecaps=None):
"""Like changegroupsubset, but returns the set difference between the
ancestors of heads and the ancestors common.
@@ -651,7 +643,7 @@
The nodes in common might not all be known locally due to the way the
current discovery protocol works.
"""
- outgoing = _computeoutgoing(repo, heads, common)
+ outgoing = computeoutgoing(repo, heads, common)
return getlocalchangegroup(repo, source, outgoing, bundlecaps=bundlecaps)
def changegroup(repo, basenodes, source):
@@ -703,7 +695,7 @@
return revisions, files
def addchangegroup(repo, source, srctype, url, emptyok=False,
- targetphase=phases.draft):
+ targetphase=phases.draft, expectedtotal=None):
"""Add the changegroup returned by source.read() to this repo.
srctype is a string like 'push', 'pull', or 'unbundle'. url is
the URL of the repo where this changegroup is coming from.
@@ -749,16 +741,15 @@
repo.ui.status(_("adding changesets\n"))
clstart = len(cl)
class prog(object):
- step = _('changesets')
- count = 1
- ui = repo.ui
- total = None
- def __call__(repo):
- repo.ui.progress(repo.step, repo.count, unit=_('chunks'),
- total=repo.total)
- repo.count += 1
- pr = prog()
- source.callback = pr
+ def __init__(self, step, total):
+ self._step = step
+ self._total = total
+ self._count = 1
+ def __call__(self):
+ repo.ui.progress(self._step, self._count, unit=_('chunks'),
+ total=self._total)
+ self._count += 1
+ source.callback = prog(_('changesets'), expectedtotal)
source.changelogheader()
srccontent = cl.addgroup(source, csmap, trp)
@@ -773,9 +764,8 @@
# pull off the manifest group
repo.ui.status(_("adding manifests\n"))
- pr.step = _('manifests')
- pr.count = 1
- pr.total = changesets # manifests <= changesets
+ # manifests <= changesets
+ source.callback = prog(_('manifests'), changesets)
# no need to check for empty manifest group here:
# if the result of the merge of 1 and 2 is the same in 3 and 4,
# no new manifest will be created and the manifest group will
@@ -788,19 +778,16 @@
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)
# process the files
repo.ui.status(_("adding file changes\n"))
- pr.step = _('files')
- pr.count = 1
- pr.total = efiles
source.callback = None
-
+ pr = prog(_('files'), efiles)
newrevs, newfiles = addchangegroupfiles(repo, source, revmap, trp, pr,
needfiles)
revisions += newrevs
--- a/mercurial/changelog.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/changelog.py Mon Jun 15 13:31:22 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 Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/cmdutil.py Mon Jun 15 13:31:22 2015 -0500
@@ -14,9 +14,22 @@
import changelog
import bookmarks
import encoding
+import formatter
import crecord as crecordmod
import lock as lockmod
+def ishunk(x):
+ hunkclasses = (crecordmod.uihunk, patch.recordhunk)
+ return isinstance(x, hunkclasses)
+
+def newandmodified(chunks, originalchunks):
+ newlyaddedandmodifiedfiles = set()
+ for chunk in chunks:
+ if ishunk(chunk) and chunk.header.isnewfile() and chunk not in \
+ originalchunks:
+ newlyaddedandmodifiedfiles.add(chunk.header.filename())
+ return newlyaddedandmodifiedfiles
+
def parsealiases(cmd):
return cmd.lstrip("^").split("|")
@@ -33,7 +46,7 @@
setattr(ui, 'write', wrap)
return oldwrite
-def filterchunks(ui, originalhunks, usecurses, testfile):
+def filterchunks(ui, originalhunks, usecurses, testfile, operation=None):
if usecurses:
if testfile:
recordfn = crecordmod.testdecorator(testfile,
@@ -41,17 +54,24 @@
else:
recordfn = crecordmod.chunkselector
- return crecordmod.filterpatch(ui, originalhunks, recordfn)
+ return crecordmod.filterpatch(ui, originalhunks, recordfn, operation)
else:
- return patch.filterpatch(ui, originalhunks)
-
-def recordfilter(ui, originalhunks):
+ return patch.filterpatch(ui, originalhunks, operation)
+
+def recordfilter(ui, originalhunks, operation=None):
+ """ Prompts the user to filter the originalhunks and return a list of
+ selected hunks.
+ *operation* is used for ui purposes to indicate the user
+ what kind of filtering they are doing: reverting, commiting, shelving, etc.
+ *operation* has to be a translated string.
+ """
usecurses = ui.configbool('experimental', 'crecord', False)
testfile = ui.config('experimental', 'crecordtest', None)
oldwrite = setupwrapcolorwrite(ui)
try:
- newchunks = filterchunks(ui, originalhunks, usecurses, testfile)
+ newchunks = filterchunks(ui, originalhunks, usecurses, testfile,
+ operation)
finally:
ui.write = oldwrite
return newchunks
@@ -59,8 +79,6 @@
def dorecord(ui, repo, commitfunc, cmdsuggest, backupall,
filterfn, *pats, **opts):
import merge as mergemod
- hunkclasses = (crecordmod.uihunk, patch.recordhunk)
- ishunk = lambda x: isinstance(x, hunkclasses)
if not ui.interactive():
raise util.Abort(_('running non-interactively, use %s instead') %
@@ -107,11 +125,7 @@
# We need to keep a backup of files that have been newly added and
# modified during the recording process because there is a previous
# version without the edit in the workdir
- newlyaddedandmodifiedfiles = set()
- for chunk in chunks:
- if ishunk(chunk) and chunk.header.isnewfile() and chunk not in \
- originalchunks:
- newlyaddedandmodifiedfiles.add(chunk.header.filename())
+ newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
contenders = set()
for h in chunks:
try:
@@ -450,14 +464,17 @@
"""opens the changelog, manifest, a filelog or a given revlog"""
cl = opts['changelog']
mf = opts['manifest']
+ dir = opts['dir']
msg = None
if cl and mf:
msg = _('cannot specify --changelog and --manifest at the same time')
+ elif cl and dir:
+ msg = _('cannot specify --changelog and --dir at the same time')
elif cl or mf:
if file_:
msg = _('cannot specify filename with --changelog or --manifest')
elif not repo:
- msg = _('cannot specify --changelog or --manifest '
+ msg = _('cannot specify --changelog or --manifest or --dir '
'without a repository')
if msg:
raise util.Abort(msg)
@@ -466,6 +483,13 @@
if repo:
if cl:
r = repo.unfiltered().changelog
+ elif dir:
+ if 'treemanifest' not in repo.requirements:
+ raise util.Abort(_("--dir can only be used on repos with "
+ "treemanifest enabled"))
+ dirlog = repo.dirlog(file_)
+ if len(dirlog):
+ r = dirlog
elif mf:
r = repo.manifest
elif file_:
@@ -818,6 +842,7 @@
msg = _('applied to working directory')
rejects = False
+ dsguard = None
try:
cmdline_message = logmessage(ui, opts)
@@ -859,7 +884,7 @@
n = None
if update:
- repo.dirstate.beginparentchange()
+ dsguard = dirstateguard(repo, 'tryimportone')
if p1 != parents[0]:
updatefunc(repo, p1.node())
if p2 != parents[1]:
@@ -896,10 +921,16 @@
editor = None
else:
editor = getcommiteditor(editform=editform, **opts)
- n = repo.commit(message, opts.get('user') or user,
- opts.get('date') or date, match=m,
- editor=editor, force=partial)
- repo.dirstate.endparentchange()
+ allowemptyback = repo.ui.backupconfig('ui', 'allowemptycommit')
+ try:
+ if partial:
+ repo.ui.setconfig('ui', 'allowemptycommit', True)
+ n = repo.commit(message, opts.get('user') or user,
+ opts.get('date') or date, match=m,
+ editor=editor)
+ finally:
+ repo.ui.restoreconfig(allowemptyback)
+ dsguard.close()
else:
if opts.get('exact') or opts.get('import_branch'):
branch = branch or 'default'
@@ -937,6 +968,7 @@
msg = _('created %s') % short(n)
return (msg, n, rejects)
finally:
+ lockmod.release(dsguard)
os.unlink(tmpname)
def export(repo, revs, template='hg-%h.patch', fp=None, switch_parent=False,
@@ -1443,9 +1475,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', ''))
@@ -1462,40 +1494,7 @@
if not tmpl:
return None, None
- # looks like a literal template?
- if '{' in tmpl:
- return tmpl, None
-
- # perhaps a stock style?
- if not os.path.split(tmpl)[0]:
- mapname = (templater.templatepath('map-cmdline.' + tmpl)
- or templater.templatepath(tmpl))
- if mapname and os.path.isfile(mapname):
- return None, mapname
-
- # perhaps it's a reference to [templates]
- t = ui.config('templates', tmpl)
- if t:
- try:
- tmpl = templater.parsestring(t)
- except SyntaxError:
- tmpl = templater.parsestring(t, quoted=False)
- return tmpl, None
-
- if tmpl == 'list':
- ui.write(_("available styles: %s\n") % templater.stylelist())
- raise util.Abort(_("specify a template"))
-
- # perhaps it's a path to a map or a template
- if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
- # is it a mapfile for a style?
- if os.path.basename(tmpl).startswith("map-"):
- return None, os.path.realpath(tmpl)
- tmpl = open(tmpl).read()
- return tmpl, None
-
- # constant string?
- return tmpl, None
+ return formatter.lookuptemplate(ui, 'changeset', tmpl)
def show_changeset(ui, repo, opts, buffered=False):
"""show one changeset using template or regular display.
@@ -1731,7 +1730,8 @@
if not revs:
return []
wanted = set()
- slowpath = match.anypats() or (match.files() and opts.get('removed'))
+ slowpath = match.anypats() or ((match.isexact() or match.prefix()) and
+ opts.get('removed'))
fncache = {}
change = repo.changectx
@@ -1743,8 +1743,7 @@
if match.always():
# No files, no patterns. Display all revs.
wanted = revs
-
- if not slowpath and match.files():
+ elif not slowpath:
# We only have to read through the filelog to find wanted revisions
try:
@@ -1812,7 +1811,7 @@
# Now that wanted is correctly initialized, we can iterate over the
# revision range, yielding only revisions in wanted.
def iterate():
- if follow and not match.files():
+ if follow and match.always():
ff = _followfilter(repo, onlyfirst=opts.get('follow_first'))
def want(rev):
return ff.match(rev) and rev in wanted
@@ -1825,13 +1824,12 @@
for windowsize in increasingwindows():
nrevs = []
for i in xrange(windowsize):
- try:
- rev = it.next()
- if want(rev):
- nrevs.append(rev)
- except (StopIteration):
+ rev = next(it, None)
+ if rev is None:
stopiteration = True
break
+ elif want(rev):
+ nrevs.append(rev)
for rev in sorted(nrevs):
fns = fncache.get(rev)
ctx = change(rev)
@@ -1916,10 +1914,7 @@
# --follow with FILE behaviour depends on revs...
it = iter(revs)
startrev = it.next()
- try:
- followdescendants = startrev < it.next()
- except (StopIteration):
- followdescendants = False
+ followdescendants = startrev < next(it, startrev)
# branch and only_branch are really aliases and must be handled at
# the same time
@@ -1931,7 +1926,8 @@
# platforms without shell expansion (windows).
wctx = repo[None]
match, pats = scmutil.matchandpats(wctx, pats, opts)
- slowpath = match.anypats() or (match.files() and opts.get('removed'))
+ slowpath = match.anypats() or ((match.isexact() or match.prefix()) and
+ opts.get('removed'))
if not slowpath:
for f in match.files():
if follow and f not in wctx:
@@ -2113,15 +2109,11 @@
if not opts.get('rev'):
revs.sort(reverse=True)
if limit is not None:
- count = 0
limitedrevs = []
- it = iter(revs)
- while count < limit:
- try:
- limitedrevs.append(it.next())
- except (StopIteration):
+ for idx, r in enumerate(revs):
+ if limit <= idx:
break
- count += 1
+ limitedrevs.append(r)
revs = revset.baseset(limitedrevs)
return revs, expr, filematcher
@@ -2189,15 +2181,16 @@
def add(ui, repo, match, prefix, explicitonly, **opts):
join = lambda f: os.path.join(prefix, f)
bad = []
- oldbad = match.bad
- match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
+
+ badfn = lambda x, y: bad.append(x) or match.bad(x, y)
names = []
wctx = repo[None]
cca = None
abort, warn = scmutil.checkportabilityalert(ui)
if abort or warn:
cca = scmutil.casecollisionauditor(ui, abort, repo.dirstate)
- for f in wctx.walk(match):
+
+ for f in wctx.walk(matchmod.badmatch(match, badfn)):
exact = match.exact(f)
if exact or not explicitonly and f not in wctx and repo.wvfs.lexists(f):
if cca:
@@ -2226,11 +2219,11 @@
def forget(ui, repo, match, prefix, explicitonly):
join = lambda f: os.path.join(prefix, f)
bad = []
- oldbad = match.bad
- match.bad = lambda x, y: bad.append(x) or oldbad(x, y)
+ badfn = lambda x, y: bad.append(x) or match.bad(x, y)
wctx = repo[None]
forgot = []
- s = repo.status(match=match, clean=True)
+
+ s = repo.status(match=matchmod.badmatch(match, badfn), clean=True)
forget = sorted(s[0] + s[1] + s[3] + s[6])
if explicitonly:
forget = [f for f in forget if match.exact(f)]
@@ -2287,12 +2280,16 @@
fm.write('path', fmt, m.rel(f))
ret = 0
- if subrepos:
- for subpath in sorted(ctx.substate):
+ for subpath in sorted(ctx.substate):
+ def matchessubrepo(subpath):
+ return (m.always() or m.exact(subpath)
+ or any(f.startswith(subpath + '/') for f in m.files()))
+
+ if subrepos or matchessubrepo(subpath):
sub = ctx.sub(subpath)
try:
submatch = matchmod.narrowmatcher(subpath, m)
- if sub.printfiles(ui, submatch, fm, fmt) == 0:
+ if sub.printfiles(ui, submatch, fm, fmt, subrepos) == 0:
ret = 0
except error.LookupError:
ui.status(_("skipping missing subrepository: %s\n")
@@ -2336,7 +2333,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
@@ -2408,22 +2405,16 @@
return 0
# Don't warn about "missing" files that are really in subrepos
- bad = matcher.bad
-
def badfn(path, msg):
for subpath in ctx.substate:
if path.startswith(subpath):
return
- bad(path, msg)
-
- matcher.bad = badfn
-
- for abs in ctx.walk(matcher):
+ matcher.bad(path, msg)
+
+ for abs in ctx.walk(matchmod.badmatch(matcher, badfn)):
write(abs)
err = 0
- matcher.bad = bad
-
for subpath in sorted(ctx.substate):
sub = ctx.sub(subpath)
try:
@@ -2464,9 +2455,10 @@
ui.note(_('amending changeset %s\n') % old)
base = old.p1()
- wlock = lock = newid = None
+ wlock = dsguard = lock = newid = None
try:
wlock = repo.wlock()
+ dsguard = dirstateguard(repo, 'amend')
lock = repo.lock()
tr = repo.transaction('amend')
try:
@@ -2480,13 +2472,13 @@
# First, do a regular commit to record all changes in the working
# directory (if there are any)
ui.callhooks = False
- currentbookmark = repo._bookmarkcurrent
+ activebookmark = 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 = activebookmark
ui.callhooks = True
ctx = repo[node]
@@ -2637,6 +2629,7 @@
tr.close()
finally:
tr.release()
+ dsguard.close()
if not createmarkers and newid != old.node():
# Strip the intermediate commit (if there was one) and the amended
# commit
@@ -2645,9 +2638,7 @@
ui.note(_('stripping amended changeset %s\n') % old)
repair.strip(ui, repo, old.node(), topic='amend-backup')
finally:
- if newid is None:
- repo.dirstate.invalidate()
- lockmod.release(lock, wlock)
+ lockmod.release(lock, dsguard, wlock)
return newid
def commiteditor(repo, ctx, subs, editform=''):
@@ -2721,8 +2712,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])
@@ -2815,8 +2806,7 @@
targetsubs = sorted(s for s in wctx.substate if m(s))
if not m.always():
- m.bad = lambda x, y: False
- for abs in repo.walk(m):
+ for abs in repo.walk(matchmod.badmatch(m, lambda x, y: False)):
names[abs] = m.rel(abs), m.exact(abs)
# walk target manifest to fill `names`
@@ -2832,8 +2822,7 @@
return
ui.warn("%s: %s\n" % (m.rel(path), msg))
- m.bad = badfn
- for abs in ctx.walk(m):
+ for abs in ctx.walk(matchmod.badmatch(m, badfn)):
if abs not in names:
names[abs] = m.rel(abs), m.exact(abs)
@@ -3103,17 +3092,33 @@
else:
normal = repo.dirstate.normal
+ newlyaddedandmodifiedfiles = set()
if interactive:
# Prompt the user for changes to revert
torevert = [repo.wjoin(f) for f in actions['revert'][0]]
m = scmutil.match(ctx, torevert, {})
- diff = patch.diff(repo, None, ctx.node(), m)
+ diffopts = patch.difffeatureopts(repo.ui, whitespace=True)
+ diffopts.nodates = True
+ diffopts.git = True
+ reversehunks = repo.ui.configbool('experimental',
+ 'revertalternateinteractivemode',
+ False)
+ if reversehunks:
+ diff = patch.diff(repo, ctx.node(), None, m, opts=diffopts)
+ else:
+ diff = patch.diff(repo, None, ctx.node(), m, opts=diffopts)
originalchunks = patch.parsepatch(diff)
+
try:
+
chunks = recordfilter(repo.ui, originalchunks)
+ if reversehunks:
+ chunks = patch.reversehunks(chunks)
+
except patch.PatchError, err:
raise util.Abort(_('error parsing patch: %s') % err)
+ newlyaddedandmodifiedfiles = newandmodified(chunks, originalchunks)
# Apply changes
fp = cStringIO.StringIO()
for c in chunks:
@@ -3137,8 +3142,10 @@
repo.dirstate.normallookup(f)
for f in actions['add'][0]:
- checkout(f)
- repo.dirstate.add(f)
+ # Don't checkout modified files, they are already created by the diff
+ if f not in newlyaddedandmodifiedfiles:
+ checkout(f)
+ repo.dirstate.add(f)
normal = repo.dirstate.normallookup
if node == parent and p2 == nullid:
@@ -3259,3 +3266,59 @@
for f, clearable, allowcommit, msg, hint in unfinishedstates:
if clearable and repo.vfs.exists(f):
util.unlink(repo.join(f))
+
+class dirstateguard(object):
+ '''Restore dirstate at unexpected failure.
+
+ At the construction, this class does:
+
+ - write current ``repo.dirstate`` out, and
+ - save ``.hg/dirstate`` into the backup file
+
+ This restores ``.hg/dirstate`` from backup file, if ``release()``
+ is invoked before ``close()``.
+
+ This just removes the backup file at ``close()`` before ``release()``.
+ '''
+
+ def __init__(self, repo, name):
+ repo.dirstate.write()
+ self._repo = repo
+ self._filename = 'dirstate.backup.%s.%d' % (name, id(self))
+ repo.vfs.write(self._filename, repo.vfs.tryread('dirstate'))
+ self._active = True
+ self._closed = False
+
+ def __del__(self):
+ if self._active: # still active
+ # this may occur, even if this class is used correctly:
+ # for example, releasing other resources like transaction
+ # may raise exception before ``dirstateguard.release`` in
+ # ``release(tr, ....)``.
+ self._abort()
+
+ def close(self):
+ if not self._active: # already inactivated
+ msg = (_("can't close already inactivated backup: %s")
+ % self._filename)
+ raise util.Abort(msg)
+
+ self._repo.vfs.unlink(self._filename)
+ self._active = False
+ self._closed = True
+
+ def _abort(self):
+ # this "invalidate()" prevents "wlock.release()" from writing
+ # changes of dirstate out after restoring to original status
+ self._repo.dirstate.invalidate()
+
+ self._repo.vfs.rename(self._filename, 'dirstate')
+ self._active = False
+
+ def release(self):
+ if not self._closed:
+ if not self._active: # already inactivated
+ msg = (_("can't release already inactivated backup: %s")
+ % self._filename)
+ raise util.Abort(msg)
+ self._abort()
--- a/mercurial/commands.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/commands.py Mon Jun 15 13:31:22 2015 -0500
@@ -40,6 +40,12 @@
# @command decorator.
inferrepo = ''
+# label constants
+# until 3.5, bookmarks.current was the advertised name, not
+# bookmarks.active, so we must use both to avoid breaking old
+# custom styles
+activebookmarklabel = 'bookmarks.active bookmarks.current'
+
# common command options
globalopts = [
@@ -344,8 +350,8 @@
def bad(x, y):
raise util.Abort("%s: %s" % (x, y))
- m = scmutil.match(ctx, pats, opts)
- m.bad = bad
+ m = scmutil.match(ctx, pats, opts, badfn=bad)
+
follow = not opts.get('no_follow')
diffopts = patch.difffeatureopts(ui, opts, section='annotate',
whitespace=True)
@@ -979,8 +985,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 +1000,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 +1011,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 +1020,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,9 +1041,9 @@
if len(marks) == 0 and not fm:
ui.status(_("no bookmarks set\n"))
for bmark, n in sorted(marks.iteritems()):
- current = repo._bookmarkcurrent
- if bmark == current:
- prefix, label = '*', 'bookmarks.current'
+ active = repo._activebookmark
+ if bmark == active:
+ prefix, label = '*', activebookmarklabel
else:
prefix, label = ' ', ''
@@ -1048,7 +1054,7 @@
pad = " " * (25 - encoding.colwidth(bmark))
fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
repo.changelog.rev(n), hexfn(n), label=label)
- fm.data(active=(bmark == current))
+ fm.data(active=(bmark == active))
fm.plain('\n')
fm.end()
@@ -1080,7 +1086,9 @@
change.
Use the command :hg:`update` to switch to an existing branch. Use
- :hg:`commit --close-branch` to mark this branch as closed.
+ :hg:`commit --close-branch` to mark this branch head as closed.
+ When all heads of the branch are closed, the branch will be
+ considered closed.
Returns 0 on success.
"""
@@ -1107,8 +1115,13 @@
scmutil.checknewlabel(repo, label, 'branch')
repo.dirstate.setbranch(label)
ui.status(_('marked working directory as branch %s\n') % label)
- ui.status(_('(branches are permanent and global, '
- 'did you want a bookmark?)\n'))
+
+ # find any open named branches aside from default
+ others = [n for n, h, t, c in repo.branchmap().iterbranches()
+ if n != "default" and not c]
+ if not others:
+ ui.status(_('(branches are permanent and global, '
+ 'did you want a bookmark?)\n'))
finally:
wlock.release()
@@ -1413,7 +1426,7 @@
[('A', 'addremove', None,
_('mark new/missing files as added/removed before committing')),
('', 'close-branch', None,
- _('mark a branch as closed, hiding it from the branch list')),
+ _('mark a branch head as closed')),
('', 'amend', None, _('amend the parent of the working directory')),
('s', 'secret', None, _('use the secret phase for committing')),
('e', 'edit', None, _('invoke editor on commit messages')),
@@ -1439,6 +1452,10 @@
commit fails, you will find a backup of your message in
``.hg/last-message.txt``.
+ The --close-branch flag can be used to mark the current branch
+ head closed. When all heads of a branch are closed, the branch
+ will be considered closed and no longer listed.
+
The --amend flag can be used to amend the parent of the
working directory with a new commit that contains the changes
in the parent in addition to those currently reported by :hg:`status`,
@@ -1506,7 +1523,7 @@
match,
extra=extra)
- current = repo._bookmarkcurrent
+ active = repo._activebookmark
marks = old.bookmarks()
node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
if node == old.node():
@@ -1518,8 +1535,8 @@
newmarks = repo._bookmarks
for bm in marks:
newmarks[bm] = node
- if bm == current:
- bookmarks.setcurrent(repo, bm)
+ if bm == active:
+ bookmarks.activate(repo, bm)
newmarks.write()
else:
def commitfunc(ui, repo, message, match, opts):
@@ -2056,7 +2073,8 @@
@command('debugdata',
[('c', 'changelog', False, _('open changelog')),
- ('m', 'manifest', False, _('open manifest'))],
+ ('m', 'manifest', False, _('open manifest')),
+ ('', 'dir', False, _('open directory manifest'))],
_('-c|-m|FILE REV'))
def debugdata(ui, repo, file_, rev=None, **opts):
"""dump the contents of a data file revision"""
@@ -2163,8 +2181,8 @@
'''parse and apply a fileset specification'''
ctx = scmutil.revsingle(repo, opts.get('rev'), None)
if ui.verbose:
- tree = fileset.parse(expr)[0]
- ui.note(tree, "\n")
+ tree = fileset.parse(expr)
+ ui.note(fileset.prettyformat(tree), "\n")
for f in ctx.getfileset(expr):
ui.write("%s\n" % f)
@@ -2227,6 +2245,7 @@
@command('debugindex',
[('c', 'changelog', False, _('open changelog')),
('m', 'manifest', False, _('open manifest')),
+ ('', 'dir', False, _('open directory manifest')),
('f', 'format', 0, _('revlog format'), _('FORMAT'))],
_('[-f FORMAT] -c|-m|FILE'),
optionalrepo=True)
@@ -2545,26 +2564,25 @@
try:
tr = repo.transaction('debugobsolete')
try:
- try:
- date = opts.get('date')
- if date:
- date = util.parsedate(date)
- else:
- date = None
- prec = parsenodeid(precursor)
- parents = None
- if opts['record_parents']:
- if prec not in repo.unfiltered():
- raise util.Abort('cannot used --record-parents on '
- 'unknown changesets')
- parents = repo.unfiltered()[prec].parents()
- parents = tuple(p.node() for p in parents)
- repo.obsstore.create(tr, prec, succs, opts['flags'],
- parents=parents, date=date,
- metadata=metadata)
- tr.close()
- except ValueError, exc:
- raise util.Abort(_('bad obsmarker input: %s') % exc)
+ date = opts.get('date')
+ if date:
+ date = util.parsedate(date)
+ else:
+ date = None
+ prec = parsenodeid(precursor)
+ parents = None
+ if opts['record_parents']:
+ if prec not in repo.unfiltered():
+ raise util.Abort('cannot used --record-parents on '
+ 'unknown changesets')
+ parents = repo.unfiltered()[prec].parents()
+ parents = tuple(p.node() for p in parents)
+ repo.obsstore.create(tr, prec, succs, opts['flags'],
+ parents=parents, date=date,
+ metadata=metadata)
+ tr.close()
+ except ValueError, exc:
+ raise util.Abort(_('bad obsmarker input: %s') % exc)
finally:
tr.release()
finally:
@@ -2730,6 +2748,7 @@
@command('debugrevlog',
[('c', 'changelog', False, _('open changelog')),
('m', 'manifest', False, _('open manifest')),
+ ('', 'dir', False, _('open directory manifest')),
('d', 'dump', False, _('dump index data'))],
_('-c|-m|FILE'),
optionalrepo=True)
@@ -2916,7 +2935,7 @@
expansion.
"""
if ui.verbose:
- tree = revset.parse(expr)[0]
+ tree = revset.parse(expr)
ui.note(revset.prettyformat(tree), "\n")
newtree = revset.findaliases(ui, tree)
if newtree != tree:
@@ -4045,8 +4064,8 @@
parents = ctx.parents()
changed = ""
if default or id or num:
- if (util.any(repo.status())
- or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
+ if (any(repo.status())
+ or any(ctx.sub(s).dirty() for s in ctx.substate)):
changed = '+'
if default or id:
output = ["%s%s" %
@@ -4213,7 +4232,7 @@
cmdutil.bailifchanged(repo)
base = opts["base"]
- wlock = lock = tr = None
+ wlock = dsguard = lock = tr = None
msgs = []
ret = 0
@@ -4221,7 +4240,7 @@
try:
try:
wlock = repo.wlock()
- repo.dirstate.beginparentchange()
+ dsguard = cmdutil.dirstateguard(repo, 'import')
if not opts.get('no_commit'):
lock = repo.lock()
tr = repo.transaction('import')
@@ -4262,18 +4281,16 @@
tr.close()
if msgs:
repo.savecommitmessage('\n* * *\n'.join(msgs))
- repo.dirstate.endparentchange()
+ dsguard.close()
return ret
- except: # re-raises
- # wlock.release() indirectly calls dirstate.write(): since
- # we're crashing, we do not want to change the working dir
- # parent after all, so make sure it writes nothing
- repo.dirstate.invalidate()
- raise
+ finally:
+ # TODO: get rid of this meaningless try/finally enclosing.
+ # this is kept only to reduce changes in a patch.
+ pass
finally:
if tr:
tr.release()
- release(lock, wlock)
+ release(lock, dsguard, wlock)
@command('incoming|in',
[('f', 'force', None,
@@ -4425,8 +4442,8 @@
ret = 1
ctx = repo[rev]
- m = scmutil.match(ctx, pats, opts, default='relglob')
- m.bad = lambda x, y: False
+ m = scmutil.match(ctx, pats, opts, default='relglob',
+ badfn=lambda x, y: False)
for abs in ctx.matches(m):
if opts.get('fullpath'):
@@ -4702,9 +4719,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 +4736,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()]
@@ -4952,11 +4969,11 @@
('f', 'force', False, _('allow to move boundary backward')),
('r', 'rev', [], _('target revision'), _('REV')),
],
- _('[-p|-d|-s] [-f] [-r] REV...'))
+ _('[-p|-d|-s] [-f] [-r] [REV...]'))
def phase(ui, repo, *revs, **opts):
"""set or show the current phase name
- With no argument, show the phase name of specified revisions.
+ With no argument, show the phase name of the current revision(s).
With one of -p/--public, -d/--draft or -s/--secret, change the
phase value of the specified revisions.
@@ -4981,7 +4998,9 @@
revs = list(revs)
revs.extend(opts['rev'])
if not revs:
- raise util.Abort(_('no revisions specified'))
+ # display both parents as the second parent phase can influence
+ # the phase of a merge commit
+ revs = [c.rev() for c in repo[None].parents()]
revs = scmutil.revrange(repo, revs)
@@ -5049,7 +5068,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())
@@ -5100,11 +5119,17 @@
revs, checkout = hg.addbranchrevs(repo, other, branches,
opts.get('rev'))
- remotebookmarks = other.listkeys('bookmarks')
-
+
+ pullopargs = {}
if opts.get('bookmark'):
if not revs:
revs = []
+ # The list of bookmark used here is not the one used to actually
+ # update the bookmark name. This can result in the revision pulled
+ # not ending up with the name of the bookmark because of a race
+ # condition on the server. (See issue 4689 for details)
+ remotebookmarks = other.listkeys('bookmarks')
+ pullopargs['remotebookmarks'] = remotebookmarks
for b in opts['bookmark']:
if b not in remotebookmarks:
raise util.Abort(_('remote bookmark %s not found!') % b)
@@ -5112,6 +5137,9 @@
if revs:
try:
+ # When 'rev' is a bookmark name, we cannot guarantee that it
+ # will be updated with that name because of a race condition
+ # server side. (See issue 4689 for details)
oldrevs = revs
revs = [] # actually, nodes
for r in oldrevs:
@@ -5126,7 +5154,8 @@
modheads = exchange.pull(repo, other, heads=revs,
force=opts.get('force'),
- bookmarks=opts.get('bookmark', ())).cgresult
+ bookmarks=opts.get('bookmark', ()),
+ opargs=pullopargs).cgresult
if checkout:
checkout = str(repo.changelog.rev(checkout))
repo._subtoppath = source
@@ -5526,7 +5555,7 @@
hint = _("uncommitted merge, use --all to discard all changes,"
" or 'hg update -C .' to abort the merge")
raise util.Abort(msg, hint=hint)
- dirty = util.any(repo.status())
+ dirty = any(repo.status())
node = ctx.node()
if node != parent:
if dirty:
@@ -5878,7 +5907,7 @@
"""summarize working directory state
This generates a brief summary of the working directory state,
- including parents, branch, commit status, and available updates.
+ including parents, branch, commit status, phase and available updates.
With the --remote option, this will check the default paths for
incoming and outgoing changes. This can be time-consuming.
@@ -5920,15 +5949,15 @@
ui.status(m, label='log.branch')
if marks:
- current = repo._bookmarkcurrent
+ active = repo._activebookmark
# i18n: column positioning for "hg summary"
ui.write(_('bookmarks:'), label='log.bookmark')
- if current is not None:
- if current in marks:
- ui.write(' *' + current, label='bookmarks.current')
- marks.remove(current)
+ if active is not None:
+ if active in marks:
+ ui.write(' *' + active, label=activebookmarklabel)
+ marks.remove(active)
else:
- ui.write(' [%s]' % current, label='bookmarks.current')
+ ui.write(' [%s]' % active, label=activebookmarklabel)
for m in marks:
ui.write(' ' + m, label='log.bookmark')
ui.write('\n', label='log.bookmark')
@@ -5984,6 +6013,14 @@
elif pnode not in bheads:
t += _(' (new branch head)')
+ if parents:
+ pendingphase = max(p.phase() for p in parents)
+ else:
+ pendingphase = phases.public
+
+ if pendingphase > phases.newcommitphase(ui):
+ t += ' (%s)' % phases.phasenames[pendingphase]
+
if cleanworkdir:
# i18n: column positioning for "hg summary"
ui.status(_('commit: %s\n') % t.strip())
@@ -6006,6 +6043,17 @@
ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
(new, len(bheads)))
+ t = []
+ draft = len(repo.revs('draft()'))
+ if draft:
+ t.append(_('%d draft') % draft)
+ secret = len(repo.revs('secret()'))
+ if secret:
+ t.append(_('%d secret') % secret)
+
+ if draft or secret:
+ ui.status(_('phases: %s\n') % ', '.join(t))
+
cmdutil.summaryhooks(ui, repo)
if opts.get('remote'):
@@ -6329,7 +6377,7 @@
Update the repository's working directory to the specified
changeset. If no changeset is specified, update to the tip of the
- current named branch and move the current bookmark (see :hg:`help
+ current named branch and move the active bookmark (see :hg:`help
bookmarks`).
Update sets the working directory's parent revision to the specified
@@ -6382,7 +6430,7 @@
cmdutil.clearunfinished(repo)
- # with no argument, we also move the current bookmark, if any
+ # with no argument, we also move the active bookmark, if any
rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
# if we defined a bookmark, we have to remember the original bookmark name
@@ -6411,15 +6459,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/config.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/config.py Mon Jun 15 13:31:22 2015 -0500
@@ -10,10 +10,11 @@
import os, errno
class config(object):
- def __init__(self, data=None):
+ def __init__(self, data=None, includepaths=[]):
self._data = {}
self._source = {}
self._unset = []
+ self._includepaths = includepaths
if data:
for k in data._data:
self._data[k] = data[k].copy()
@@ -110,13 +111,17 @@
item = None
cont = False
m = includere.match(l)
- if m:
- inc = util.expandpath(m.group(1))
- base = os.path.dirname(src)
- inc = os.path.normpath(os.path.join(base, inc))
- if include:
+
+ if m and include:
+ expanded = util.expandpath(m.group(1))
+ includepaths = [os.path.dirname(src)] + self._includepaths
+
+ for base in includepaths:
+ inc = os.path.normpath(os.path.join(base, expanded))
+
try:
include(inc, remap=remap, sections=sections)
+ break
except IOError, inst:
if inst.errno != errno.ENOENT:
raise error.ParseError(_("cannot include %s (%s)")
--- a/mercurial/context.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/context.py Mon Jun 15 13:31:22 2015 -0500
@@ -9,7 +9,7 @@
from i18n import _
import mdiff, error, util, scmutil, subrepo, patch, encoding, phases
import match as matchmod
-import copy, os, errno, stat
+import os, errno, stat
import obsolete as obsmod
import repoview
import fileset
@@ -251,11 +251,16 @@
def sub(self, path):
return subrepo.subrepo(self, path)
- def match(self, pats=[], include=None, exclude=None, default='glob'):
+ def nullsub(self, path, pctx):
+ return subrepo.nullsubrepo(self, path, pctx)
+
+ def match(self, pats=[], include=None, exclude=None, default='glob',
+ listsubrepos=False, badfn=None):
r = self._repo
return matchmod.match(r.root, r.getcwd(), pats,
include, exclude, default,
- auditor=r.auditor, ctx=self)
+ auditor=r.auditor, ctx=self,
+ listsubrepos=listsubrepos, badfn=badfn)
def diff(self, ctx2=None, match=None, **opts):
"""Returns a diff generator for the given contexts and matcher"""
@@ -338,7 +343,7 @@
def makememctx(repo, parents, text, user, date, branch, files, store,
- editor=None):
+ editor=None, extra=None):
def getfilectx(repo, memctx, path):
data, mode, copied = store.getfile(path)
if data is None:
@@ -346,7 +351,8 @@
islink, isexec = mode
return memfilectx(repo, path, data, islink=islink, isexec=isexec,
copied=copied, memctx=memctx)
- extra = {}
+ if extra is None:
+ extra = {}
if branch:
extra['branch'] = encoding.fromlocal(branch)
ctx = memctx(repo, parents, text, files, getfilectx, user,
@@ -459,7 +465,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)
@@ -589,19 +595,17 @@
def walk(self, match):
'''Generates matching file names.'''
- # Override match.bad method to have message with nodeid
- match = copy.copy(match)
- oldbad = match.bad
+ # Wrap match.bad method to have message with nodeid
def bad(fn, msg):
# The manifest doesn't know about subrepos, so don't complain about
# paths into valid subrepos.
- if util.any(fn == s or fn.startswith(s + '/')
- for s in self.substate):
+ if any(fn == s or fn.startswith(s + '/')
+ for s in self.substate):
return
- oldbad(fn, _('no such file in rev %s') % self)
- match.bad = bad
+ match.bad(fn, _('no such file in rev %s') % self)
- return self._manifest.walk(match)
+ m = matchmod.badmatch(match, bad)
+ return self._manifest.walk(m)
def matches(self, match):
return self.walk(match)
@@ -1443,17 +1447,21 @@
finally:
wlock.release()
- def match(self, pats=[], include=None, exclude=None, default='glob'):
+ def match(self, pats=[], include=None, exclude=None, default='glob',
+ listsubrepos=False, badfn=None):
r = self._repo
# Only a case insensitive filesystem needs magic to translate user input
# to actual case in the filesystem.
if not util.checkcase(r.root):
return matchmod.icasefsmatcher(r.root, r.getcwd(), pats, include,
- exclude, default, r.auditor, self)
+ exclude, default, r.auditor, self,
+ listsubrepos=listsubrepos,
+ badfn=badfn)
return matchmod.match(r.root, r.getcwd(), pats,
include, exclude, default,
- auditor=r.auditor, ctx=self)
+ auditor=r.auditor, ctx=self,
+ listsubrepos=listsubrepos, badfn=badfn)
def _filtersuspectsymlink(self, files):
if not files or self._repo.dirstate._checklink:
--- a/mercurial/copies.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/copies.py Mon Jun 15 13:31:22 2015 -0500
@@ -5,15 +5,9 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import util
+import util, pathutil
import heapq
-def _dirname(f):
- s = f.rfind("/")
- if s == -1:
- return ""
- return f[:s]
-
def _findlimit(repo, a, b):
"""
Find the last revision that needs to be checked to ensure that a full
@@ -376,6 +370,7 @@
# generate a directory move map
d1, d2 = c1.dirs(), c2.dirs()
+ # Hack for adding '', which is not otherwise added, to d1 and d2
d1.addpath('/')
d2.addpath('/')
invalid = set()
@@ -384,7 +379,7 @@
# examine each file copy for a potential directory move, which is
# when all the files in a directory are moved to a new directory
for dst, src in fullcopy.iteritems():
- dsrc, ddst = _dirname(src), _dirname(dst)
+ dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
if dsrc in invalid:
# already seen to be uninteresting
continue
--- a/mercurial/crecord.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/crecord.py Mon Jun 15 13:31:22 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:
@@ -424,9 +425,11 @@
def __repr__(self):
return '<hunk %r@%d>' % (self.filename(), self.fromline)
-def filterpatch(ui, chunks, chunkselector):
+def filterpatch(ui, chunks, chunkselector, operation=None):
"""interactively filter patch chunks into applied-only chunks"""
+ if operation is None:
+ operation = _('confirm')
chunks = list(chunks)
# convert chunks list into structure suitable for displaying/modifying
# with curses. create a list of headers only.
@@ -508,6 +511,7 @@
self.ui = ui
+ self.errorstr = None
# list of all chunks
self.chunklist = []
for h in headerlist:
@@ -973,6 +977,12 @@
# print out the status lines at the top
try:
+ if self.errorstr is not None:
+ printstring(self.statuswin, self.errorstr, pairname='legend')
+ printstring(self.statuswin, 'Press any key to continue',
+ pairname='legend')
+ self.statuswin.refresh()
+ return
printstring(self.statuswin,
"SELECT CHUNKS: (j/k/up/dn/pgup/pgdn) move cursor; "
"(space/A) toggle hunk/all; (e)dit hunk;",
@@ -1416,6 +1426,13 @@
"""
edit the currently chelected chunk
"""
+ def updateui(self):
+ self.numpadlines = self.getnumlinesdisplayed(ignorefolding=True) + 1
+ self.chunkpad = curses.newpad(self.numpadlines, self.xscreensize)
+ self.updatescroll()
+ self.stdscr.refresh()
+ self.statuswin.refresh()
+ self.stdscr.keypad(1)
def editpatchwitheditor(self, chunk):
if chunk is None:
@@ -1451,9 +1468,11 @@
f.close()
# start the editor and wait for it to complete
editor = self.ui.geteditor()
- self.ui.system("%s \"%s\"" % (editor, patchfn),
- environ={'hguser': self.ui.username()},
- onerr=util.Abort, errprefix=_("edit failed"))
+ ret = self.ui.system("%s \"%s\"" % (editor, patchfn),
+ environ={'hguser': self.ui.username()})
+ if ret != 0:
+ self.errorstr = "Editor exited with status %d" % ret
+ return None
# remove comment lines
patchfp = open(patchfn)
ncpatchfp = cStringIO.StringIO()
@@ -1478,6 +1497,10 @@
beforeadded, beforeremoved = item.added, item.removed
newpatches = editpatchwitheditor(self, item)
+ if newpatches is None:
+ if not test:
+ updateui(self)
+ return
header = item.header
editedhunkindex = header.hunks.index(item)
hunksbefore = header.hunks[:editedhunkindex]
@@ -1498,12 +1521,7 @@
self.currentselecteditem = header
if not test:
- self.numpadlines = self.getnumlinesdisplayed(ignorefolding=True) + 1
- self.chunkpad = curses.newpad(self.numpadlines, self.xscreensize)
- self.updatescroll()
- self.stdscr.refresh()
- self.statuswin.refresh()
- self.stdscr.keypad(1)
+ updateui(self)
def emptypatch(self):
item = self.headerlist
@@ -1551,6 +1569,8 @@
self.togglefolded(foldparent=True)
elif keypressed in ["?"]:
self.helpwindow()
+ self.stdscr.clear()
+ self.stdscr.refresh()
def main(self, stdscr):
"""
@@ -1594,6 +1614,9 @@
self.updatescreen()
try:
keypressed = self.statuswin.getkey()
+ if self.errorstr is not None:
+ self.errorstr = None
+ continue
except curses.error:
keypressed = "foobar"
if self.handlekeypressed(keypressed):
--- a/mercurial/dagparser.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/dagparser.py Mon Jun 15 13:31:22 2015 -0500
@@ -176,10 +176,7 @@
chiter = (c for c in desc)
def nextch():
- try:
- return chiter.next()
- except StopIteration:
- return '\0'
+ return next(chiter, '\0')
def nextrun(c, allow):
s = ''
--- a/mercurial/demandimport.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/demandimport.py Mon Jun 15 13:31:22 2015 -0500
@@ -25,6 +25,8 @@
'''
import __builtin__, os, sys
+from contextlib import contextmanager
+
_origimport = __import__
nothing = object()
@@ -179,3 +181,16 @@
def disable():
"disable global demand-loading of modules"
__builtin__.__import__ = _origimport
+
+@contextmanager
+def deactivated():
+ "context manager for disabling demandimport in 'with' blocks"
+ demandenabled = isenabled()
+ if demandenabled:
+ disable()
+
+ try:
+ yield
+ finally:
+ if demandenabled:
+ enable()
--- a/mercurial/dirs.c Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/dirs.c Mon Jun 15 13:31:22 2015 -0500
@@ -9,7 +9,6 @@
#define PY_SSIZE_T_CLEAN
#include <Python.h>
-#include <string.h>
#include "util.h"
/*
@@ -29,23 +28,25 @@
PyObject *dict;
} dirsObject;
-static inline Py_ssize_t _finddir(PyObject *path, Py_ssize_t pos)
+static inline Py_ssize_t _finddir(const char *path, Py_ssize_t pos)
{
- const char *s = PyString_AS_STRING(path);
+ while (pos != -1) {
+ if (path[pos] == '/')
+ break;
+ pos -= 1;
+ }
- const char *ret = strchr(s + pos, '/');
- return (ret != NULL) ? (ret - s) : -1;
+ return pos;
}
static int _addpath(PyObject *dirs, PyObject *path)
{
- char *cpath = PyString_AS_STRING(path);
- Py_ssize_t len = PyString_GET_SIZE(path);
- Py_ssize_t pos = -1;
+ const char *cpath = PyString_AS_STRING(path);
+ Py_ssize_t pos = PyString_GET_SIZE(path);
PyObject *key = NULL;
int ret = -1;
- while ((pos = _finddir(path, pos + 1)) != -1) {
+ while ((pos = _finddir(cpath, pos - 1)) != -1) {
PyObject *val;
/* It's likely that every prefix already has an entry
@@ -53,18 +54,10 @@
deallocating a string for each prefix we check. */
if (key != NULL)
((PyStringObject *)key)->ob_shash = -1;
- else if (pos != 0) {
- /* pos >= 1, which means that len >= 2. This is
- guaranteed to produce a non-interned string. */
- key = PyString_FromStringAndSize(cpath, len);
- if (key == NULL)
- goto bail;
- } else {
- /* pos == 0, which means we need to increment the dir
- count for the empty string. We need to make sure we
- don't muck around with interned strings, so throw it
- away later. */
- key = PyString_FromString("");
+ else {
+ /* Force Python to not reuse a small shared string. */
+ key = PyString_FromStringAndSize(cpath,
+ pos < 2 ? 2 : pos);
if (key == NULL)
goto bail;
}
@@ -74,11 +67,7 @@
val = PyDict_GetItem(dirs, key);
if (val != NULL) {
PyInt_AS_LONG(val) += 1;
- if (pos != 0)
- PyString_AS_STRING(key)[pos] = '/';
- else
- key = NULL;
- continue;
+ break;
}
/* Force Python to not reuse a small shared int. */
@@ -92,9 +81,6 @@
Py_DECREF(val);
if (ret == -1)
goto bail;
-
- /* Clear the key out since we've already exposed it to Python
- and can't mutate it further. */
Py_CLEAR(key);
}
ret = 0;
@@ -107,14 +93,15 @@
static int _delpath(PyObject *dirs, PyObject *path)
{
- Py_ssize_t pos = -1;
+ char *cpath = PyString_AS_STRING(path);
+ Py_ssize_t pos = PyString_GET_SIZE(path);
PyObject *key = NULL;
int ret = -1;
- while ((pos = _finddir(path, pos + 1)) != -1) {
+ while ((pos = _finddir(cpath, pos - 1)) != -1) {
PyObject *val;
- key = PyString_FromStringAndSize(PyString_AS_STRING(path), pos);
+ key = PyString_FromStringAndSize(cpath, pos);
if (key == NULL)
goto bail;
@@ -126,9 +113,11 @@
goto bail;
}
- if (--PyInt_AS_LONG(val) <= 0 &&
- PyDict_DelItem(dirs, key) == -1)
- goto bail;
+ if (--PyInt_AS_LONG(val) <= 0) {
+ if (PyDict_DelItem(dirs, key) == -1)
+ goto bail;
+ } else
+ break;
Py_CLEAR(key);
}
ret = 0;
--- a/mercurial/dirstate.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/dirstate.py Mon Jun 15 13:31:22 2015 -0500
@@ -7,8 +7,9 @@
from node import nullid
from i18n import _
-import scmutil, util, ignore, osutil, parsers, encoding, pathutil
+import scmutil, util, osutil, parsers, encoding, pathutil
import os, stat, errno
+import match as matchmod
propertycache = util.propertycache
filecache = scmutil.filecache
@@ -47,6 +48,7 @@
self._ui = ui
self._filecache = {}
self._parentwriters = 0
+ self._filename = 'dirstate'
def beginparentchange(self):
'''Marks the beginning of a set of changes that involve changing
@@ -121,7 +123,7 @@
@propertycache
def _pl(self):
try:
- fp = self._opener("dirstate")
+ fp = self._opener(self._filename)
st = fp.read(40)
fp.close()
l = len(st)
@@ -143,13 +145,20 @@
@rootcache('.hgignore')
def _ignore(self):
- files = [self._join('.hgignore')]
+ files = []
+ if os.path.exists(self._join('.hgignore')):
+ files.append(self._join('.hgignore'))
for name, path in self._ui.configitems("ui"):
if name == 'ignore' or name.startswith('ignore.'):
# we need to use os.path.join here rather than self._join
# because path is arbitrary and user-specified
files.append(os.path.join(self._rootdir, util.expandpath(path)))
- return ignore.ignore(self._root, files, self._ui.warn)
+
+ if not files:
+ return util.never
+
+ pats = ['include:%s' % f for f in files]
+ return matchmod.match(self._root, '', [], pats, warn=self._ui.warn)
@propertycache
def _slash(self):
@@ -317,7 +326,11 @@
self._map = {}
self._copymap = {}
try:
- st = self._opener.read("dirstate")
+ fp = self._opener.open(self._filename)
+ try:
+ st = fp.read()
+ finally:
+ fp.close()
except IOError, err:
if err.errno != errno.ENOENT:
raise
@@ -559,7 +572,8 @@
self._dirty = True
def rebuild(self, parent, allfiles, changedfiles=None):
- changedfiles = changedfiles or allfiles
+ if changedfiles is None:
+ changedfiles = allfiles
oldmap = self._map
self.clear()
for f in allfiles:
@@ -584,7 +598,7 @@
import time # to avoid useless import
time.sleep(delaywrite)
- st = self._opener("dirstate", "w", atomictemp=True)
+ st = self._opener(self._filename, "w", atomictemp=True)
# use the modification time of the newly created temporary file as the
# filesystem's notion of 'now'
now = util.fstat(st).st_mtime
@@ -746,7 +760,7 @@
if match.isexact(): # match.exact
exact = True
dirignore = util.always # skip step 2
- elif match.files() and not match.anypats(): # match.match, no patterns
+ elif match.prefix(): # match.match, no patterns
skipstep3 = True
if not exact and self._checkcase:
@@ -972,7 +986,7 @@
# fast path -- filter the other way around, since typically files is
# much smaller than dmap
return [f for f in files if f in dmap]
- if not match.anypats() and util.all(fn in dmap for fn in files):
+ if match.prefix() and all(fn in dmap for fn in files):
# fast path -- all the values are known to be files, so just return
# that
return list(files)
--- a/mercurial/dispatch.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/dispatch.py Mon Jun 15 13:31:22 2015 -0500
@@ -11,6 +11,7 @@
import util, commands, hg, fancyopts, extensions, hook, error
import cmdutil, encoding
import ui as uimod
+import demandimport
class request(object):
def __init__(self, args, ui=None, repo=None, fin=None, fout=None,
@@ -137,10 +138,11 @@
# This import can be slow for fancy debuggers, so only
# do it when absolutely necessary, i.e. when actual
# debugging has been requested
- try:
- debugmod = __import__(debugger)
- except ImportError:
- pass # Leave debugmod = pdb
+ with demandimport.deactivated():
+ try:
+ debugmod = __import__(debugger)
+ except ImportError:
+ pass # Leave debugmod = pdb
debugtrace[debugger] = debugmod.set_trace
debugmortem[debugger] = debugmod.post_mortem
@@ -193,8 +195,15 @@
ui.warn(_("hg: %s\n") % inst.args[1])
commands.help_(ui, 'shortlist')
except error.OutOfBandError, inst:
- ui.warn(_("abort: remote error:\n"))
- ui.warn(''.join(inst.args))
+ if inst.args:
+ msg = _("abort: remote error:\n")
+ else:
+ msg = _("abort: remote error\n")
+ ui.warn(msg)
+ if inst.args:
+ ui.warn(''.join(inst.args))
+ if inst.hint:
+ ui.warn('(%s)\n' % inst.hint)
except error.RepoError, inst:
ui.warn(_("abort: %s!\n") % inst)
if inst.hint:
@@ -891,7 +900,7 @@
format = ui.config('profiling', 'format', default='text')
field = ui.config('profiling', 'sort', default='inlinetime')
limit = ui.configint('profiling', 'limit', default=30)
- climit = ui.configint('profiling', 'nested', default=5)
+ climit = ui.configint('profiling', 'nested', default=0)
if format not in ['text', 'kcachegrind']:
ui.warn(_("unrecognized profiling format '%s'"
@@ -921,6 +930,30 @@
stats.sort(field)
stats.pprint(limit=limit, file=fp, climit=climit)
+def flameprofile(ui, func, fp):
+ try:
+ from flamegraph import flamegraph
+ except ImportError:
+ raise util.Abort(_(
+ 'flamegraph not available - install from '
+ 'https://github.com/evanhempel/python-flamegraph'))
+ freq = ui.configint('profiling', 'freq', default=1000)
+ filter_ = None
+ collapse_recursion = True
+ thread = flamegraph.ProfileThread(fp, 1.0 / freq,
+ filter_, collapse_recursion)
+ start_time = time.clock()
+ try:
+ thread.start()
+ func()
+ finally:
+ thread.stop()
+ thread.join()
+ print 'Collected %d stack frames (%d unique) in %2.2f seconds.' % (
+ time.clock() - start_time, thread.num_frames(),
+ thread.num_frames(unique=True))
+
+
def statprofile(ui, func, fp):
try:
import statprof
@@ -952,7 +985,7 @@
profiler = os.getenv('HGPROF')
if profiler is None:
profiler = ui.config('profiling', 'type', default='ls')
- if profiler not in ('ls', 'stat'):
+ if profiler not in ('ls', 'stat', 'flame'):
ui.warn(_("unrecognized profiler '%s' - ignored\n") % profiler)
profiler = 'ls'
@@ -967,6 +1000,8 @@
try:
if profiler == 'ls':
return lsprofile(ui, checkargs, fp)
+ elif profiler == 'flame':
+ return flameprofile(ui, checkargs, fp)
else:
return statprofile(ui, checkargs, fp)
finally:
--- a/mercurial/error.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/error.py Mon Jun 15 13:31:22 2015 -0500
@@ -13,7 +13,12 @@
# Do not import anything here, please
-class RevlogError(Exception):
+class HintException(Exception):
+ def __init__(self, *args, **kw):
+ Exception.__init__(self, *args)
+ self.hint = kw.get('hint')
+
+class RevlogError(HintException):
pass
class FilteredIndexError(IndexError):
@@ -46,11 +51,9 @@
class InterventionRequired(Exception):
"""Exception raised when a command requires human intervention."""
-class Abort(Exception):
+class Abort(HintException):
"""Raised if a command needs to print an error and exit."""
- def __init__(self, *args, **kw):
- Exception.__init__(self, *args)
- self.hint = kw.get('hint')
+ pass
class HookAbort(Abort):
"""raised when a validation hook fails, aborting an operation
@@ -64,6 +67,10 @@
class OutOfBandError(Exception):
"""Exception raised when a remote repo reports failure"""
+ def __init__(self, *args, **kw):
+ Exception.__init__(self, *args)
+ self.hint = kw.get('hint')
+
class ParseError(Exception):
"""Raised when parsing config files and {rev,file}sets (msg[, pos])"""
@@ -76,10 +83,8 @@
self.function = function
self.symbols = symbols
-class RepoError(Exception):
- def __init__(self, *args, **kw):
- Exception.__init__(self, *args)
- self.hint = kw.get('hint')
+class RepoError(HintException):
+ pass
class RepoLookupError(RepoError):
pass
@@ -146,6 +151,21 @@
"""error raised when code tries to alter a part being generated"""
pass
+class PushkeyFailed(Abort):
+ """error raised when a pushkey part failed to update a value"""
+
+ def __init__(self, partid, namespace=None, key=None, new=None, old=None,
+ ret=None):
+ self.partid = partid
+ self.namespace = namespace
+ self.key = key
+ self.new = new
+ self.old = old
+ self.ret = ret
+ # no i18n expected to be processed into a better message
+ Abort.__init__(self, 'failed to update value for "%s/%s"'
+ % (namespace, key))
+
class CensoredNodeError(RevlogError):
"""error raised when content verification fails on a censored node
--- a/mercurial/exchange.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/exchange.py Mon Jun 15 13:31:22 2015 -0500
@@ -5,12 +5,14 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+import time
from i18n import _
from node import hex, nullid
import errno, urllib
-import util, scmutil, changegroup, base85, error
+import util, scmutil, changegroup, base85, error, store
import discovery, phases, obsolete, bookmarks as bookmod, bundle2, pushkey
import lock as lockmod
+import tags
def readbundle(ui, fh, fname, vfs=None):
header = changegroup.readexactly(fh, 4)
@@ -57,7 +59,7 @@
"""return true if a pull/push can use bundle2
Feel free to nuke this function when we drop the experimental option"""
- return (op.repo.ui.configbool('experimental', 'bundle2-exp', False)
+ return (op.repo.ui.configbool('experimental', 'bundle2-exp', True)
and op.remote.capable('bundle2'))
@@ -115,6 +117,9 @@
self.outbookmarks = []
# transaction manager
self.trmanager = None
+ # map { pushkey partid -> callback handling failure}
+ # used to handle exception from mandatory pushkey part failure
+ self.pkfailcb = {}
@util.propertycache
def futureheads(self):
@@ -304,6 +309,20 @@
unfi = pushop.repo.unfiltered()
remotephases = pushop.remote.listkeys('phases')
publishing = remotephases.get('publishing', False)
+ if (pushop.ui.configbool('ui', '_usedassubrepo', False)
+ and remotephases # server supports phases
+ and not pushop.outgoing.missing # no changesets to be pushed
+ and publishing):
+ # When:
+ # - this is a subrepo push
+ # - and remote support phase
+ # - and no changeset are to be pushed
+ # - and remote is publishing
+ # We may be in issue 3871 case!
+ # We drop the possible phase synchronisation done by
+ # courtesy to publish changesets possibly locally draft
+ # on the remote.
+ remotephases = {'publishing': 'True'}
ana = phases.analyzeremotephases(pushop.repo,
pushop.fallbackheads,
remotephases)
@@ -505,6 +524,13 @@
return
pushop.stepsdone.add('phases')
part2node = []
+
+ def handlefailure(pushop, exc):
+ targetid = int(exc.partid)
+ for partid, node in part2node:
+ if partid == targetid:
+ raise error.Abort(_('updating %s to public failed') % node)
+
enc = pushkey.encode
for newremotehead in pushop.outdatedphases:
part = bundler.newpart('pushkey')
@@ -513,6 +539,8 @@
part.addparam('old', enc(str(phases.draft)))
part.addparam('new', enc(str(phases.public)))
part2node.append((part.id, newremotehead))
+ pushop.pkfailcb[part.id] = handlefailure
+
def handlereply(op):
for partid, node in part2node:
partrep = op.records.getreplies(partid)
@@ -536,7 +564,8 @@
return
pushop.stepsdone.add('obsmarkers')
if pushop.outobsmarkers:
- buildobsmarkerspart(bundler, pushop.outobsmarkers)
+ markers = sorted(pushop.outobsmarkers)
+ buildobsmarkerspart(bundler, markers)
@b2partsgenerator('bookmarks')
def _pushb2bookmarks(pushop, bundler):
@@ -549,6 +578,15 @@
pushop.stepsdone.add('bookmarks')
part2book = []
enc = pushkey.encode
+
+ def handlefailure(pushop, exc):
+ targetid = int(exc.partid)
+ for partid, book, action in part2book:
+ if partid == targetid:
+ raise error.Abort(bookmsgmap[action][1].rstrip() % book)
+ # we should not be called for part we did not generated
+ assert False
+
for book, old, new in pushop.outbookmarks:
part = bundler.newpart('pushkey')
part.addparam('namespace', enc('bookmarks'))
@@ -561,7 +599,7 @@
elif not new:
action = 'delete'
part2book.append((part.id, book, action))
-
+ pushop.pkfailcb[part.id] = handlefailure
def handlereply(op):
ui = pushop.ui
@@ -606,16 +644,22 @@
return
stream = util.chunkbuffer(bundler.getchunks())
try:
- reply = pushop.remote.unbundle(stream, ['force'], 'push')
- except error.BundleValueError, exc:
- raise util.Abort('missing support for %s' % exc)
- try:
- trgetter = None
- if pushback:
- trgetter = pushop.trmanager.transaction
- op = bundle2.processbundle(pushop.repo, reply, trgetter)
- except error.BundleValueError, exc:
- raise util.Abort('missing support for %s' % exc)
+ try:
+ reply = pushop.remote.unbundle(stream, ['force'], 'push')
+ except error.BundleValueError, exc:
+ raise util.Abort('missing support for %s' % exc)
+ try:
+ trgetter = None
+ if pushback:
+ trgetter = pushop.trmanager.transaction
+ op = bundle2.processbundle(pushop.repo, reply, trgetter)
+ except error.BundleValueError, exc:
+ raise util.Abort('missing support for %s' % exc)
+ except error.PushkeyFailed, exc:
+ partid = int(exc.partid)
+ if partid not in pushop.pkfailcb:
+ raise
+ pushop.pkfailcb[partid](pushop, exc)
for rephand in replyhandlers:
rephand(op)
@@ -745,13 +789,13 @@
"""utility function to push obsolete markers to a remote"""
if 'obsmarkers' in pushop.stepsdone:
return
- pushop.ui.debug('try to push obsolete markers to remote\n')
repo = pushop.repo
remote = pushop.remote
pushop.stepsdone.add('obsmarkers')
if pushop.outobsmarkers:
+ pushop.ui.debug('try to push obsolete markers to remote\n')
rslts = []
- remotedata = obsolete._pushkeyescape(pushop.outobsmarkers)
+ remotedata = obsolete._pushkeyescape(sorted(pushop.outobsmarkers))
for key in sorted(remotedata, reverse=True):
# reverse sort to ensure we end with dump0
data = remotedata[key]
@@ -791,7 +835,8 @@
afterward.
"""
- def __init__(self, repo, remote, heads=None, force=False, bookmarks=()):
+ def __init__(self, repo, remote, heads=None, force=False, bookmarks=(),
+ remotebookmarks=None):
# repo we pull into
self.repo = repo
# repo we pull from
@@ -811,7 +856,7 @@
# list of missing changeset to fetch remotely
self.fetch = None
# remote bookmarks data
- self.remotebookmarks = None
+ self.remotebookmarks = remotebookmarks
# result of changegroup pulling (used as return code by pull)
self.cgresult = None
# list of step already done
@@ -869,8 +914,11 @@
if self._tr is not None:
self._tr.release()
-def pull(repo, remote, heads=None, force=False, bookmarks=()):
- pullop = pulloperation(repo, remote, heads, force, bookmarks=bookmarks)
+def pull(repo, remote, heads=None, force=False, bookmarks=(), opargs=None):
+ if opargs is None:
+ opargs = {}
+ pullop = pulloperation(repo, remote, heads, force, bookmarks=bookmarks,
+ **opargs)
if pullop.remote.local():
missing = set(pullop.remote.requirements) - pullop.repo.supported
if missing:
@@ -879,7 +927,6 @@
" %s") % (', '.join(sorted(missing)))
raise util.Abort(msg)
- pullop.remotebookmarks = remote.listkeys('bookmarks')
lock = pullop.repo.lock()
try:
pullop.trmanager = transactionmanager(repo, 'pull', remote.url())
@@ -927,6 +974,22 @@
step = pulldiscoverymapping[stepname]
step(pullop)
+@pulldiscovery('b1:bookmarks')
+def _pullbookmarkbundle1(pullop):
+ """fetch bookmark data in bundle1 case
+
+ If not using bundle2, we have to fetch bookmarks before changeset
+ discovery to reduce the chance and impact of race conditions."""
+ if pullop.remotebookmarks is not None:
+ return
+ if (_canusebundle2(pullop)
+ and 'listkeys' in bundle2.bundle2caps(pullop.remote)):
+ # all known bundle2 servers now support listkeys, but lets be nice with
+ # new implementation.
+ return
+ pullop.remotebookmarks = pullop.remote.listkeys('bookmarks')
+
+
@pulldiscovery('changegroup')
def _pulldiscoverychangegroup(pullop):
"""discovery phase for the pull
@@ -978,7 +1041,11 @@
kwargs['heads'] = pullop.heads or pullop.rheads
kwargs['cg'] = pullop.fetch
if 'listkeys' in remotecaps:
- kwargs['listkeys'] = ['phase', 'bookmarks']
+ kwargs['listkeys'] = ['phase']
+ if pullop.remotebookmarks is None:
+ # make sure to always includes bookmark data when migrating
+ # `hg incoming --bundle` to using this function.
+ kwargs['listkeys'].append('bookmarks')
if not pullop.fetch:
pullop.repo.ui.status(_("no changes found\n"))
pullop.cgresult = 0
@@ -1010,7 +1077,10 @@
for namespace, value in op.records['listkeys']:
if namespace == 'bookmarks':
pullop.remotebookmarks = value
- _pullbookmarks(pullop)
+
+ # bookmark data were either already there or pulled in the bundle
+ if pullop.remotebookmarks is not None:
+ _pullbookmarks(pullop)
def _pullbundle2extraprepare(pullop, kwargs):
"""hook function so that extensions can extend the getbundle call"""
@@ -1180,7 +1250,7 @@
# bundle10 case
usebundle2 = False
if bundlecaps is not None:
- usebundle2 = util.any((cap.startswith('HG2') for cap in bundlecaps))
+ usebundle2 = any((cap.startswith('HG2') for cap in bundlecaps))
if not usebundle2:
if bundlecaps and not kwargs.get('cg', True):
raise ValueError(_('request for bundle10 must include changegroup'))
@@ -1218,24 +1288,22 @@
# build changegroup bundle here.
version = None
cgversions = b2caps.get('changegroup')
- if not cgversions: # 3.1 and 3.2 ship with an empty value
- cg = changegroup.getchangegroupraw(repo, source, heads=heads,
- common=common,
- bundlecaps=bundlecaps)
- else:
+ getcgkwargs = {}
+ if cgversions: # 3.1 and 3.2 ship with an empty value
cgversions = [v for v in cgversions if v in changegroup.packermap]
if not cgversions:
raise ValueError(_('no common changegroup version'))
- version = max(cgversions)
- cg = changegroup.getchangegroupraw(repo, source, heads=heads,
- common=common,
- bundlecaps=bundlecaps,
- version=version)
+ version = getcgkwargs['version'] = max(cgversions)
+ outgoing = changegroup.computeoutgoing(repo, heads, common)
+ cg = changegroup.getlocalchangegroupraw(repo, source, outgoing,
+ bundlecaps=bundlecaps,
+ **getcgkwargs)
if cg:
part = bundler.newpart('changegroup', data=cg)
if version is not None:
part.addparam('version', version)
+ part.addparam('nbchanges', str(len(outgoing.missing)), mandatory=False)
@getbundle2partsgenerator('listkeys')
def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
@@ -1257,8 +1325,52 @@
heads = repo.heads()
subset = [c.node() for c in repo.set('::%ln', heads)]
markers = repo.obsstore.relevantmarkers(subset)
+ markers = sorted(markers)
buildobsmarkerspart(bundler, markers)
+@getbundle2partsgenerator('hgtagsfnodes')
+def _getbundletagsfnodes(bundler, repo, source, bundlecaps=None,
+ b2caps=None, heads=None, common=None,
+ **kwargs):
+ """Transfer the .hgtags filenodes mapping.
+
+ Only values for heads in this bundle will be transferred.
+
+ The part data consists of pairs of 20 byte changeset node and .hgtags
+ filenodes raw values.
+ """
+ # Don't send unless:
+ # - changeset are being exchanged,
+ # - the client supports it.
+ if not (kwargs.get('cg', True) and 'hgtagsfnodes' in b2caps):
+ return
+
+ outgoing = changegroup.computeoutgoing(repo, heads, common)
+
+ if not outgoing.missingheads:
+ return
+
+ cache = tags.hgtagsfnodescache(repo.unfiltered())
+ chunks = []
+
+ # .hgtags fnodes are only relevant for head changesets. While we could
+ # transfer values for all known nodes, there will likely be little to
+ # no benefit.
+ #
+ # We don't bother using a generator to produce output data because
+ # a) we only have 40 bytes per head and even esoteric numbers of heads
+ # consume little memory (1M heads is 40MB) b) we don't want to send the
+ # part if we don't have entries and knowing if we have entries requires
+ # cache lookups.
+ for node in outgoing.missingheads:
+ # Don't compute missing, as this may slow down serving.
+ fnode = cache.getfnode(node, computemissing=False)
+ if fnode is not None:
+ chunks.extend([node, fnode])
+
+ if chunks:
+ bundler.newpart('hgtagsfnodes', data=''.join(chunks))
+
def check_heads(repo, their_heads, context):
"""check if the heads of a repo have been modified
@@ -1288,7 +1400,7 @@
# quick fix for output mismatch with bundle2 in 3.4
captureoutput = repo.ui.configbool('experimental', 'bundle2-output-capture',
False)
- if url.startswith('remote:'):
+ if url.startswith('remote:http:') or url.startswith('remote:https:'):
captureoutput = True
try:
check_heads(repo, heads, 'uploading changes')
@@ -1313,7 +1425,7 @@
def recordout(output):
r.newpart('output', data=output, mandatory=False)
tr.close()
- except Exception, exc:
+ except BaseException, exc:
exc.duringunbundle2 = True
if captureoutput and r is not None:
parts = exc._bundle2salvagedoutput = r.salvageoutput()
@@ -1330,3 +1442,131 @@
if recordout is not None:
recordout(repo.ui.popbuffer())
return r
+
+# This is it's own function so extensions can override it.
+def _walkstreamfiles(repo):
+ return repo.store.walk()
+
+def generatestreamclone(repo):
+ """Emit content for a streaming clone.
+
+ This is a generator of raw chunks that constitute a streaming clone.
+
+ The stream begins with a line of 2 space-delimited integers containing the
+ number of entries and total bytes size.
+
+ Next, are N entries for each file being transferred. Each file entry starts
+ as a line with the file name and integer size delimited by a null byte.
+ The raw file data follows. Following the raw file data is the next file
+ entry, or EOF.
+
+ When used on the wire protocol, an additional line indicating protocol
+ success will be prepended to the stream. This function is not responsible
+ for adding it.
+
+ This function will obtain a repository lock to ensure a consistent view of
+ the store is captured. It therefore may raise LockError.
+ """
+ entries = []
+ total_bytes = 0
+ # Get consistent snapshot of repo, lock during scan.
+ lock = repo.lock()
+ try:
+ repo.ui.debug('scanning\n')
+ for name, ename, size in _walkstreamfiles(repo):
+ if size:
+ entries.append((name, size))
+ total_bytes += size
+ finally:
+ lock.release()
+
+ repo.ui.debug('%d files, %d bytes to transfer\n' %
+ (len(entries), total_bytes))
+ yield '%d %d\n' % (len(entries), total_bytes)
+
+ sopener = repo.svfs
+ oldaudit = sopener.mustaudit
+ debugflag = repo.ui.debugflag
+ sopener.mustaudit = False
+
+ try:
+ for name, size in entries:
+ if debugflag:
+ repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
+ # partially encode name over the wire for backwards compat
+ yield '%s\0%d\n' % (store.encodedir(name), size)
+ if size <= 65536:
+ fp = sopener(name)
+ try:
+ data = fp.read(size)
+ finally:
+ fp.close()
+ yield data
+ else:
+ for chunk in util.filechunkiter(sopener(name), limit=size):
+ yield chunk
+ finally:
+ sopener.mustaudit = oldaudit
+
+def consumestreamclone(repo, fp):
+ """Apply the contents from a streaming clone file.
+
+ This takes the output from "streamout" and applies it to the specified
+ repository.
+
+ Like "streamout," the status line added by the wire protocol is not handled
+ by this function.
+ """
+ lock = repo.lock()
+ try:
+ repo.ui.status(_('streaming all changes\n'))
+ l = fp.readline()
+ try:
+ total_files, total_bytes = map(int, l.split(' ', 1))
+ except (ValueError, TypeError):
+ raise error.ResponseError(
+ _('unexpected response from remote server:'), l)
+ repo.ui.status(_('%d files to transfer, %s of data\n') %
+ (total_files, util.bytecount(total_bytes)))
+ handled_bytes = 0
+ repo.ui.progress(_('clone'), 0, total=total_bytes)
+ start = time.time()
+
+ tr = repo.transaction(_('clone'))
+ try:
+ for i in xrange(total_files):
+ # XXX doesn't support '\n' or '\r' in filenames
+ l = fp.readline()
+ try:
+ name, size = l.split('\0', 1)
+ size = int(size)
+ except (ValueError, TypeError):
+ raise error.ResponseError(
+ _('unexpected response from remote server:'), l)
+ if repo.ui.debugflag:
+ repo.ui.debug('adding %s (%s)\n' %
+ (name, util.bytecount(size)))
+ # for backwards compat, name was partially encoded
+ ofp = repo.svfs(store.decodedir(name), 'w')
+ for chunk in util.filechunkiter(fp, limit=size):
+ handled_bytes += len(chunk)
+ repo.ui.progress(_('clone'), handled_bytes,
+ total=total_bytes)
+ ofp.write(chunk)
+ ofp.close()
+ tr.close()
+ finally:
+ tr.release()
+
+ # Writing straight to files circumvented the inmemory caches
+ repo.invalidate()
+
+ elapsed = time.time() - start
+ if elapsed <= 0:
+ elapsed = 0.001
+ repo.ui.progress(_('clone'), None)
+ repo.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
+ (util.bytecount(total_bytes), elapsed,
+ util.bytecount(total_bytes / elapsed)))
+ finally:
+ lock.release()
--- a/mercurial/extensions.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/extensions.py Mon Jun 15 13:31:22 2015 -0500
@@ -85,6 +85,8 @@
except ImportError, err:
ui.debug('could not import hgext.%s (%s): trying %s\n'
% (name, err, name))
+ if ui.debugflag:
+ ui.traceback()
mod = importh(name)
_extensions[shortname] = mod
_order.append(shortname)
@@ -110,6 +112,7 @@
else:
ui.warn(_("*** failed to import extension %s: %s\n")
% (name, inst))
+ ui.traceback()
for name in _order[newindex:]:
uisetup = getattr(_extensions[name], 'uisetup', None)
--- a/mercurial/fancyopts.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/fancyopts.py Mon Jun 15 13:31:22 2015 -0500
@@ -103,8 +103,9 @@
# transfer result to state
for opt, val in opts:
name = argmap[opt]
- t = type(defmap[name])
- if t is type(fancyopts):
+ obj = defmap[name]
+ t = type(obj)
+ if callable(obj):
state[name] = defmap[name](val)
elif t is type(1):
try:
--- a/mercurial/filemerge.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/filemerge.py Mon Jun 15 13:31:22 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/fileset.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/fileset.py Mon Jun 15 13:31:22 2015 -0500
@@ -81,7 +81,10 @@
def parse(expr):
p = parser.parser(tokenize, elements)
- return p.parse(expr)
+ tree, pos = p.parse(expr)
+ if pos != len(expr):
+ raise error.ParseError(_("invalid token"), pos)
+ return tree
def getstring(x, err):
if x and (x[0] == 'string' or x[0] == 'symbol'):
@@ -491,9 +494,7 @@
]
def getfileset(ctx, expr):
- tree, pos = parse(expr)
- if (pos != len(expr)):
- raise error.ParseError(_("invalid token"), pos)
+ tree = parse(expr)
# do we need status info?
if (_intree(['modified', 'added', 'removed', 'deleted',
@@ -516,5 +517,8 @@
return getset(matchctx(ctx, subset, status), tree)
+def prettyformat(tree):
+ return parser.prettyformat(tree, ('string', 'symbol'))
+
# tell hggettext to extract docstrings from these functions:
i18nfunctions = symbols.values()
--- a/mercurial/formatter.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/formatter.py Mon Jun 15 13:31:22 2015 -0500
@@ -9,6 +9,8 @@
from node import hex, short
from i18n import _
import encoding, util
+import templater
+import os
class baseformatter(object):
def __init__(self, ui, topic, opts):
@@ -133,6 +135,58 @@
baseformatter.end(self)
self._ui.write("\n]\n")
+class templateformatter(baseformatter):
+ def __init__(self, ui, topic, opts):
+ baseformatter.__init__(self, ui, topic, opts)
+ self._topic = topic
+ self._t = gettemplater(ui, topic, opts.get('template', ''))
+ def _showitem(self):
+ g = self._t(self._topic, **self._item)
+ self._ui.write(templater.stringify(g))
+
+def lookuptemplate(ui, topic, tmpl):
+ # looks like a literal template?
+ if '{' in tmpl:
+ return tmpl, None
+
+ # perhaps a stock style?
+ if not os.path.split(tmpl)[0]:
+ mapname = (templater.templatepath('map-cmdline.' + tmpl)
+ or templater.templatepath(tmpl))
+ if mapname and os.path.isfile(mapname):
+ return None, mapname
+
+ # perhaps it's a reference to [templates]
+ t = ui.config('templates', tmpl)
+ if t:
+ try:
+ tmpl = templater.unquotestring(t)
+ except SyntaxError:
+ tmpl = t
+ return tmpl, None
+
+ if tmpl == 'list':
+ ui.write(_("available styles: %s\n") % templater.stylelist())
+ raise util.Abort(_("specify a template"))
+
+ # perhaps it's a path to a map or a template
+ if ('/' in tmpl or '\\' in tmpl) and os.path.isfile(tmpl):
+ # is it a mapfile for a style?
+ if os.path.basename(tmpl).startswith("map-"):
+ return None, os.path.realpath(tmpl)
+ tmpl = open(tmpl).read()
+ return tmpl, None
+
+ # constant string?
+ return tmpl, None
+
+def gettemplater(ui, topic, spec):
+ tmpl, mapfile = lookuptemplate(ui, topic, spec)
+ t = templater.templater(mapfile, {})
+ if tmpl:
+ t.cache[topic] = tmpl
+ return t
+
def formatter(ui, topic, opts):
template = opts.get("template", "")
if template == "json":
@@ -142,7 +196,7 @@
elif template == "debug":
return debugformatter(ui, topic, opts)
elif template != "":
- raise util.Abort(_("custom templates not yet supported"))
+ return templateformatter(ui, topic, opts)
elif ui.configbool('ui', 'formatdebug'):
return debugformatter(ui, topic, opts)
elif ui.configbool('ui', 'formatjson'):
--- a/mercurial/hbisect.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/hbisect.py Mon Jun 15 13:31:22 2015 -0500
@@ -8,6 +8,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+import collections
import os
import error
from i18n import _
@@ -71,7 +72,7 @@
# build children dict
children = {}
- visit = util.deque([badrev])
+ visit = collections.deque([badrev])
candidates = []
while visit:
rev = visit.popleft()
--- a/mercurial/help/config.txt Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/help/config.txt Mon Jun 15 13:31:22 2015 -0500
@@ -376,8 +376,8 @@
HG: --
HG: user: {author}\n{ifeq(p2rev, "-1", "",
"HG: branch merge\n")
- }HG: branch '{branch}'\n{if(currentbookmark,
- "HG: bookmark '{currentbookmark}'\n") }{subrepos %
+ }HG: branch '{branch}'\n{if(activebookmark,
+ "HG: bookmark '{activebookmark}'\n") }{subrepos %
"HG: subrepo {subrepo}\n" }{file_adds %
"HG: added {file}\n" }{file_mods %
"HG: changed {file}\n" }{file_dels %
@@ -641,8 +641,8 @@
Example for ``~/.hgrc``::
[extensions]
- # (the progress extension will get loaded from Mercurial's path)
- progress =
+ # (the color extension will get loaded from Mercurial's path)
+ color =
# (this extension will get loaded from the file specified)
myfeature = ~/.hgext/myfeature.py
@@ -1214,6 +1214,47 @@
Specific to the ``ls`` instrumenting profiler.
Default: 5.
+``progress``
+------------
+
+Mercurial commands can draw progress bars that are as informative as
+possible. Some progress bars only offer indeterminate information, while others
+have a definite end point.
+
+``delay``
+ Number of seconds (float) before showing the progress bar. (default: 3)
+
+``changedelay``
+ Minimum delay before showing a new topic. When set to less than 3 * refresh,
+ that value will be used instead. (default: 1)
+
+``refresh``
+ Time in seconds between refreshes of the progress bar. (default: 0.1)
+
+``format``
+ Format of the progress bar.
+
+ Valid entries for the format field are ``topic``, ``bar``, ``number``,
+ ``unit``, ``estimate``, speed, and item. item defaults to the last 20
+ characters of the item, but this can be changed by adding either ``-<num>``
+ which would take the last num characters, or ``+<num>`` for the first num
+ characters.
+
+ (default: Topic bar number estimate)
+
+``width``
+ If set, the maximum width of the progress information (that is, min(width,
+ term width) will be used)
+
+``clear-complete``
+ clear the progress bar after it's done (default to True)
+
+``disable``
+ If true, don't show a progress bar
+
+``assume-tty``
+ If true, ALWAYS show a progress bar, unless disable is given
+
``revsetalias``
---------------
@@ -1423,10 +1464,6 @@
``remotecmd``
remote command to use for clone/push/pull operations. Default is ``hg``.
-``reportoldssl``
- Warn if an SSL certificate is unable to be used due to using Python
- 2.5 or earlier. True or False. Default is True.
-
``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.
--- a/mercurial/help/hgignore.txt Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/help/hgignore.txt Mon Jun 15 13:31:22 2015 -0500
@@ -68,6 +68,10 @@
and a regexp pattern of the form ``\.c$`` will do the same. To root a
regexp pattern, start it with ``^``.
+Subdirectories can have their own .hgignore settings by adding
+``subinclude:path/to/subdir/.hgignore`` to the root ``.hgignore``. See
+:hg:`help patterns` for details on ``subinclude:`` and ``include:``.
+
.. note::
Patterns specified in other than ``.hgignore`` are always rooted.
--- a/mercurial/help/patterns.txt Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/help/patterns.txt Mon Jun 15 13:31:22 2015 -0500
@@ -30,6 +30,12 @@
feeds. Each string read from the file is itself treated as a file
pattern.
+To read a set of patterns from a file, use ``include:`` or ``subinclude:``.
+``include:`` will use all the patterns from the given file and treat them as if
+they had been passed in manually. ``subinclude:`` will only apply the patterns
+against files that are under the subinclude file's directory. See :hg:`help
+hgignore` for details on the format of these files.
+
All patterns, except for ``glob:`` specified in command line (not for
``-I`` or ``-X`` options), can match also against directories: files
under matched directories are treated as matched.
@@ -60,3 +66,9 @@
listfile0:list.txt read list from list.txt with null byte delimiters
See also :hg:`help filesets`.
+
+Include examples::
+
+ include:path/to/mypatternfile reads patterns to be applied to all paths
+ subinclude:path/to/subignorefile reads patterns specifically for paths in the
+ subdirectory
--- a/mercurial/help/subrepos.txt Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/help/subrepos.txt Mon Jun 15 13:31:22 2015 -0500
@@ -109,8 +109,10 @@
elements. Subversion subrepositories are currently silently ignored.
:files: files does not recurse into subrepos unless -S/--subrepos is
- specified. Git and Subversion subrepositories are currently
- silently ignored.
+ specified. However, if you specify the full path of a file or
+ directory in a subrepo, it will be displayed even without
+ -S/--subrepos being specified. Git and Subversion subrepositories
+ are currently silently ignored.
:forget: forget currently only handles exact file matches in subrepos.
Git and Subversion subrepositories are currently silently ignored.
--- a/mercurial/help/templates.txt Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/help/templates.txt Mon Jun 15 13:31:22 2015 -0500
@@ -67,7 +67,7 @@
- Output the description set to a fill-width of 30::
- $ hg log -r 0 --template "{fill(desc, '30')}"
+ $ hg log -r 0 --template "{fill(desc, 30)}"
- Use a conditional to test for the default branch::
@@ -90,9 +90,9 @@
$ hg log -r 0 --template "{join(extras, '\n')}\n"
-- Mark the current bookmark with '*'::
+- Mark the active bookmark with '*'::
- $ hg log --template "{bookmarks % '{bookmark}{ifeq(bookmark, current, \"*\")} '}\n"
+ $ hg log --template "{bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
- Mark the working copy parent with '@'::
@@ -104,4 +104,4 @@
- Print the first word of each line of a commit message::
- $ hg log --template "{word(\"0\", desc)}\n"
+ $ hg log --template "{word(0, desc)}\n"
--- a/mercurial/hg.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/hg.py Mon Jun 15 13:31:22 2015 -0500
@@ -92,6 +92,10 @@
try:
return thing(path)
except TypeError:
+ # we can't test callable(thing) because 'thing' can be an unloaded
+ # module that implements __call__
+ if not util.safehasattr(thing, 'instance'):
+ raise
return thing
def islocal(repo):
@@ -497,7 +501,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/hgweb/hgweb_mod.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/hgweb/hgweb_mod.py Mon Jun 15 13:31:22 2015 -0500
@@ -69,6 +69,10 @@
r.baseui.setconfig('ui', 'report_untrusted', 'off', 'hgweb')
r.ui.setconfig('ui', 'nontty', 'true', 'hgweb')
r.baseui.setconfig('ui', 'nontty', 'true', 'hgweb')
+ # displaying bundling progress bar while serving feel wrong and may
+ # break some wsgi implementation.
+ r.ui.setconfig('progress', 'disable', 'true', 'hgweb')
+ r.baseui.setconfig('progress', 'disable', 'true', 'hgweb')
self.repo = r
hook.redirect(True)
self.repostate = ((-1, -1), (-1, -1))
@@ -96,6 +100,16 @@
untrusted=untrusted)
def _getview(self, repo):
+ """The 'web.view' config controls changeset filter to hgweb. Possible
+ values are ``served``, ``visible`` and ``all``. Default is ``served``.
+ The ``served`` filter only shows changesets that can be pulled from the
+ hgweb instance. The``visible`` filter includes secret changesets but
+ still excludes "hidden" one.
+
+ See the repoview module for details.
+
+ The option has been around undocumented since Mercurial 2.5, but no
+ user ever asked about it. So we better keep it undocumented for now."""
viewconfig = repo.ui.config('web', 'view', 'served',
untrusted=True)
if viewconfig == 'all':
--- a/mercurial/hgweb/hgwebdir_mod.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/hgweb/hgwebdir_mod.py Mon Jun 15 13:31:22 2015 -0500
@@ -98,6 +98,9 @@
u = ui.ui()
u.setconfig('ui', 'report_untrusted', 'off', 'hgwebdir')
u.setconfig('ui', 'nontty', 'true', 'hgwebdir')
+ # displaying bundling progress bar while serving feels wrong and may
+ # break some wsgi implementations.
+ u.setconfig('progress', 'disable', 'true', 'hgweb')
if not isinstance(self.conf, (dict, list, tuple)):
map = {'paths': 'hgweb-paths'}
@@ -176,71 +179,70 @@
def run_wsgi(self, req):
try:
- try:
- self.refresh()
+ self.refresh()
- virtual = req.env.get("PATH_INFO", "").strip('/')
- tmpl = self.templater(req)
- ctype = tmpl('mimetype', encoding=encoding.encoding)
- ctype = templater.stringify(ctype)
+ virtual = req.env.get("PATH_INFO", "").strip('/')
+ tmpl = self.templater(req)
+ ctype = tmpl('mimetype', encoding=encoding.encoding)
+ ctype = templater.stringify(ctype)
- # a static file
- if virtual.startswith('static/') or 'static' in req.form:
- if virtual.startswith('static/'):
- fname = virtual[7:]
- else:
- fname = req.form['static'][0]
- static = self.ui.config("web", "static", None,
- untrusted=False)
- if not static:
- tp = self.templatepath or templater.templatepaths()
- if isinstance(tp, str):
- tp = [tp]
- static = [os.path.join(p, 'static') for p in tp]
- staticfile(static, fname, req)
- return []
+ # a static file
+ if virtual.startswith('static/') or 'static' in req.form:
+ if virtual.startswith('static/'):
+ fname = virtual[7:]
+ else:
+ fname = req.form['static'][0]
+ static = self.ui.config("web", "static", None,
+ untrusted=False)
+ if not static:
+ tp = self.templatepath or templater.templatepaths()
+ if isinstance(tp, str):
+ tp = [tp]
+ static = [os.path.join(p, 'static') for p in tp]
+ staticfile(static, fname, req)
+ return []
- # top-level index
- elif not virtual:
- req.respond(HTTP_OK, ctype)
- return self.makeindex(req, tmpl)
+ # top-level index
+ elif not virtual:
+ req.respond(HTTP_OK, ctype)
+ return self.makeindex(req, tmpl)
- # nested indexes and hgwebs
+ # nested indexes and hgwebs
- repos = dict(self.repos)
- virtualrepo = virtual
- while virtualrepo:
- real = repos.get(virtualrepo)
- if real:
- req.env['REPO_NAME'] = virtualrepo
- try:
- # ensure caller gets private copy of ui
- repo = hg.repository(self.ui.copy(), real)
- return hgweb(repo).run_wsgi(req)
- except IOError, inst:
- msg = inst.strerror
- raise ErrorResponse(HTTP_SERVER_ERROR, msg)
- except error.RepoError, inst:
- raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
+ repos = dict(self.repos)
+ virtualrepo = virtual
+ while virtualrepo:
+ real = repos.get(virtualrepo)
+ if real:
+ req.env['REPO_NAME'] = virtualrepo
+ try:
+ # ensure caller gets private copy of ui
+ repo = hg.repository(self.ui.copy(), real)
+ return hgweb(repo).run_wsgi(req)
+ except IOError, inst:
+ msg = inst.strerror
+ raise ErrorResponse(HTTP_SERVER_ERROR, msg)
+ except error.RepoError, inst:
+ raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
- up = virtualrepo.rfind('/')
- if up < 0:
- break
- virtualrepo = virtualrepo[:up]
+ up = virtualrepo.rfind('/')
+ if up < 0:
+ break
+ virtualrepo = virtualrepo[:up]
- # browse subdirectories
- subdir = virtual + '/'
- if [r for r in repos if r.startswith(subdir)]:
- req.respond(HTTP_OK, ctype)
- return self.makeindex(req, tmpl, subdir)
+ # browse subdirectories
+ subdir = virtual + '/'
+ if [r for r in repos if r.startswith(subdir)]:
+ req.respond(HTTP_OK, ctype)
+ return self.makeindex(req, tmpl, subdir)
- # prefixes not found
- req.respond(HTTP_NOT_FOUND, ctype)
- return tmpl("notfound", repo=virtual)
+ # prefixes not found
+ req.respond(HTTP_NOT_FOUND, ctype)
+ return tmpl("notfound", repo=virtual)
- except ErrorResponse, err:
- req.respond(err, ctype)
- return tmpl('error', error=err.message or '')
+ except ErrorResponse, err:
+ req.respond(err, ctype)
+ return tmpl('error', error=err.message or '')
finally:
tmpl = None
--- a/mercurial/hgweb/webcommands.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/hgweb/webcommands.py Mon Jun 15 13:31:22 2015 -0500
@@ -130,6 +130,8 @@
parent=webutil.parents(fctx),
child=webutil.children(fctx),
rename=webutil.renamelink(fctx),
+ tags=webutil.nodetagsdict(web.repo, fctx.node()),
+ bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
permissions=fctx.manifest().flags(f))
@webcommand('file')
@@ -221,7 +223,7 @@
revdef = 'reverse(%s)' % query
try:
- tree, pos = revset.parse(revdef)
+ tree = revset.parse(revdef)
except ParseError:
# can't parse to a revset tree
return MODE_KEYWORD, query
@@ -230,7 +232,7 @@
# no revset syntax used
return MODE_KEYWORD, query
- if util.any((token, (value or '')[:3]) == ('string', 're:')
+ if any((token, (value or '')[:3]) == ('string', 're:')
for token, value, pos in revset.tokenize(revdef)):
return MODE_KEYWORD, query
@@ -546,6 +548,7 @@
archives=web.archivelist(hex(node)),
tags=webutil.nodetagsdict(web.repo, node),
bookmarks=webutil.nodebookmarksdict(web.repo, node),
+ branch=webutil.nodebranchnodefault(ctx),
inbranch=webutil.nodeinbranch(web.repo, ctx),
branches=webutil.nodebranchdict(web.repo, ctx))
@@ -808,6 +811,8 @@
branch=webutil.nodebranchnodefault(ctx),
parent=webutil.parents(ctx),
child=webutil.children(ctx),
+ tags=webutil.nodetagsdict(web.repo, n),
+ bookmarks=webutil.nodebookmarksdict(web.repo, n),
diff=diffs)
diff = webcommand('diff')(filediff)
@@ -880,6 +885,8 @@
branch=webutil.nodebranchnodefault(ctx),
parent=webutil.parents(fctx),
child=webutil.children(fctx),
+ tags=webutil.nodetagsdict(web.repo, ctx.node()),
+ bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
leftrev=leftrev,
leftnode=hex(leftnode),
rightrev=rightrev,
@@ -946,6 +953,8 @@
branch=webutil.nodebranchnodefault(fctx),
parent=webutil.parents(fctx),
child=webutil.children(fctx),
+ tags=webutil.nodetagsdict(web.repo, fctx.node()),
+ bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
permissions=fctx.manifest().flags(f))
@webcommand('filelog')
--- a/mercurial/hgweb/webutil.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/hgweb/webutil.py Mon Jun 15 13:31:22 2015 -0500
@@ -331,7 +331,7 @@
archives=web.archivelist(ctx.hex()),
tags=nodetagsdict(web.repo, ctx.node()),
bookmarks=nodebookmarksdict(web.repo, ctx.node()),
- branch=nodebranchnodefault(ctx),
+ branch=showbranch,
inbranch=nodeinbranch(web.repo, ctx),
branches=nodebranchdict(web.repo, ctx))
--- a/mercurial/hook.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/hook.py Mon Jun 15 13:31:22 2015 -0500
@@ -35,10 +35,7 @@
if modpath and modfile:
sys.path = sys.path[:] + [modpath]
modname = modfile
- demandimportenabled = demandimport.isenabled()
- if demandimportenabled:
- demandimport.disable()
- try:
+ with demandimport.deactivated():
try:
obj = __import__(modname)
except ImportError:
@@ -59,9 +56,6 @@
raise util.Abort(_('%s hook is invalid '
'(import of "%s" failed)') %
(hname, modname))
- finally:
- if demandimportenabled:
- demandimport.enable()
sys.path = oldpaths
try:
for p in funcname.split('.')[1:]:
@@ -79,27 +73,24 @@
starttime = time.time()
try:
- try:
- # redirect IO descriptors to the ui descriptors so hooks
- # that write directly to these don't mess up the command
- # protocol when running through the command server
- old = sys.stdout, sys.stderr, sys.stdin
- sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
+ # redirect IO descriptors to the ui descriptors so hooks
+ # that write directly to these don't mess up the command
+ # protocol when running through the command server
+ old = sys.stdout, sys.stderr, sys.stdin
+ sys.stdout, sys.stderr, sys.stdin = ui.fout, ui.ferr, ui.fin
- r = obj(ui=ui, repo=repo, hooktype=name, **args)
- except KeyboardInterrupt:
+ r = obj(ui=ui, repo=repo, hooktype=name, **args)
+ except Exception, exc:
+ if isinstance(exc, util.Abort):
+ ui.warn(_('error: %s hook failed: %s\n') %
+ (hname, exc.args[0]))
+ else:
+ ui.warn(_('error: %s hook raised an exception: '
+ '%s\n') % (hname, exc))
+ if throw:
raise
- except Exception, exc:
- if isinstance(exc, util.Abort):
- ui.warn(_('error: %s hook failed: %s\n') %
- (hname, exc.args[0]))
- else:
- ui.warn(_('error: %s hook raised an exception: '
- '%s\n') % (hname, exc))
- if throw:
- raise
- ui.traceback()
- return True
+ ui.traceback()
+ return True
finally:
sys.stdout, sys.stderr, sys.stdin = old
duration = time.time() - starttime
--- a/mercurial/httpconnection.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/httpconnection.py Mon Jun 15 13:31:22 2015 -0500
@@ -70,11 +70,7 @@
gdict[setting] = val
# Find the best match
- if '://' in uri:
- scheme, hostpath = uri.split('://', 1)
- else:
- # Python 2.4.1 doesn't provide the full URI
- scheme, hostpath = 'http', uri
+ scheme, hostpath = uri.split('://', 1)
bestuser = None
bestlen = 0
bestauth = None
@@ -281,7 +277,7 @@
kwargs.update(sslutil.sslkwargs(self.ui, host))
con = HTTPConnection(host, port, use_ssl=True,
- ssl_wrap_socket=sslutil.ssl_wrap_socket,
+ ssl_wrap_socket=sslutil.wrapsocket,
ssl_validator=sslutil.validator(self.ui, host),
**kwargs)
return con
--- a/mercurial/httppeer.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/httppeer.py Mon Jun 15 13:31:22 2015 -0500
@@ -30,6 +30,7 @@
self.caps = None
self.handler = None
self.urlopener = None
+ self.requestbuilder = None
u = util.url(path)
if u.query or u.fragment:
raise util.Abort(_('unsupported URL component: "%s"') %
@@ -42,6 +43,7 @@
self.ui.debug('using %s\n' % self._url)
self.urlopener = url.opener(ui, authinfo)
+ self.requestbuilder = urllib2.Request
def __del__(self):
if self.urlopener:
@@ -111,7 +113,7 @@
q += sorted(args.items())
qs = '?%s' % urllib.urlencode(q)
cu = "%s%s" % (self._url, qs)
- req = urllib2.Request(cu, data, headers)
+ req = self.requestbuilder(cu, data, headers)
if data is not None:
self.ui.debug("sending %s bytes\n" % size)
req.add_unredirected_header('Content-Length', '%d' % size)
@@ -198,16 +200,15 @@
headers = {'Content-Type': 'application/mercurial-0.1'}
try:
- try:
- r = self._call(cmd, data=fp, headers=headers, **args)
- vals = r.split('\n', 1)
- if len(vals) < 2:
- raise error.ResponseError(_("unexpected response:"), r)
- return vals
- except socket.error, err:
- if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
- raise util.Abort(_('push failed: %s') % err.args[1])
- raise util.Abort(err.args[1])
+ r = self._call(cmd, data=fp, headers=headers, **args)
+ vals = r.split('\n', 1)
+ if len(vals) < 2:
+ raise error.ResponseError(_("unexpected response:"), r)
+ return vals
+ except socket.error, err:
+ if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
+ raise util.Abort(_('push failed: %s') % err.args[1])
+ raise util.Abort(err.args[1])
finally:
fp.close()
os.unlink(tempname)
--- a/mercurial/ignore.py Sat Jun 13 20:14:22 2015 +0900
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-# ignore.py - ignored file handling for mercurial
-#
-# Copyright 2007 Matt Mackall <mpm@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-from i18n import _
-import util, match
-import re
-
-_commentre = None
-
-def ignorepats(lines):
- '''parse lines (iterable) of .hgignore text, returning a tuple of
- (patterns, parse errors). These patterns should be given to compile()
- to be validated and converted into a match function.'''
- syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
- syntax = 'relre:'
- patterns = []
- warnings = []
-
- for line in lines:
- if "#" in line:
- global _commentre
- if not _commentre:
- _commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
- # remove comments prefixed by an even number of escapes
- line = _commentre.sub(r'\1', line)
- # fixup properly escaped comments that survived the above
- line = line.replace("\\#", "#")
- line = line.rstrip()
- if not line:
- continue
-
- if line.startswith('syntax:'):
- s = line[7:].strip()
- try:
- syntax = syntaxes[s]
- except KeyError:
- warnings.append(_("ignoring invalid syntax '%s'") % s)
- continue
- pat = syntax + line
- for s, rels in syntaxes.iteritems():
- if line.startswith(rels):
- pat = line
- break
- elif line.startswith(s+':'):
- pat = rels + line[len(s) + 1:]
- break
- patterns.append(pat)
-
- return patterns, warnings
-
-def readpats(root, files, warn):
- '''return a dict mapping ignore-file-name to list-of-patterns'''
-
- pats = {}
- for f in files:
- if f in pats:
- continue
- try:
- pats[f] = []
- fp = open(f)
- pats[f], warnings = ignorepats(fp)
- fp.close()
- for warning in warnings:
- warn("%s: %s\n" % (f, warning))
- except IOError, inst:
- if f != files[0]:
- warn(_("skipping unreadable ignore file '%s': %s\n") %
- (f, inst.strerror))
- return [(f, pats[f]) for f in files if f in pats]
-
-def ignore(root, files, warn):
- '''return matcher covering patterns in 'files'.
-
- the files parsed for patterns include:
- .hgignore in the repository root
- any additional files specified in the [ui] section of ~/.hgrc
-
- trailing white space is dropped.
- the escape character is backslash.
- comments start with #.
- empty lines are skipped.
-
- lines can be of the following formats:
-
- syntax: regexp # defaults following lines to non-rooted regexps
- syntax: glob # defaults following lines to non-rooted globs
- re:pattern # non-rooted regular expression
- glob:pattern # non-rooted glob
- pattern # pattern of the current default type'''
-
- pats = readpats(root, files, warn)
-
- allpats = []
- for f, patlist in pats:
- allpats.extend(patlist)
- if not allpats:
- return util.never
-
- try:
- ignorefunc = match.match(root, '', [], allpats)
- except util.Abort:
- # Re-raise an exception where the src is the right file
- for f, patlist in pats:
- try:
- match.match(root, '', [], patlist)
- except util.Abort, inst:
- raise util.Abort('%s: %s' % (f, inst[0]))
-
- return ignorefunc
--- a/mercurial/localrepo.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/localrepo.py Mon Jun 15 13:31:22 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]
@@ -464,6 +460,9 @@
def manifest(self):
return manifest.manifest(self.svfs)
+ def dirlog(self, dir):
+ return self.manifest.dirlog(dir)
+
@repofilecache('dirstate')
def dirstate(self):
warned = [0]
@@ -628,7 +627,7 @@
if not local:
m = matchmod.exact(self.root, '', ['.hgtags'])
- if util.any(self.status(match=m, unknown=True, ignored=True)):
+ if any(self.status(match=m, unknown=True, ignored=True)):
raise util.Abort(_('working copy of .hgtags is changed'),
hint=_('please commit .hgtags manually'))
@@ -945,7 +944,7 @@
return None
def transaction(self, desc, report=None):
- if (self.ui.configbool('devel', 'all')
+ if (self.ui.configbool('devel', 'all-warnings')
or self.ui.configbool('devel', 'check-locks')):
l = self._lockref and self._lockref()
if l is None or not l.held:
@@ -1250,7 +1249,7 @@
# We do not need to check for non-waiting lock aquisition. Such
# acquisition would not cause dead-lock as they would just fail.
- if wait and (self.ui.configbool('devel', 'all')
+ if wait and (self.ui.configbool('devel', 'all-warnings')
or self.ui.configbool('devel', 'check-locks')):
l = self._lockref and self._lockref()
if l is not None and l.held:
@@ -1382,7 +1381,7 @@
wctx = self[None]
merge = len(wctx.parents()) > 1
- if not force and merge and not match.always():
+ if not force and merge and match.ispartial():
raise util.Abort(_('cannot partially commit a merge '
'(do not specify files or patterns)'))
@@ -1445,7 +1444,7 @@
status.removed.insert(0, '.hgsubstate')
# make sure all explicit patterns are matched
- if not force and match.files():
+ if not force and (match.isexact() or match.prefix()):
matched = set(status.modified + status.added + status.removed)
for f in match.files():
@@ -1467,9 +1466,10 @@
cctx = context.workingcommitctx(self, status,
text, user, date, extra)
- if (not force and not extra.get("close") and not merge
- and not cctx.files()
- and wctx.branch() == wctx.p1().branch()):
+ allowemptycommit = (wctx.branch() != wctx.p1().branch()
+ or extra.get('close') or merge or cctx.files()
+ or self.ui.configbool('ui', 'allowemptycommit'))
+ if not allowemptycommit:
return None
if merge and cctx.deleted():
@@ -1522,7 +1522,7 @@
def commithook(node=hex(ret), parent1=hookp1, parent2=hookp2):
# hack for command that use a temporary commit (eg: histedit)
# temporary commit got stripped before hook release
- if node in self:
+ if self.changelog.hasnode(ret):
self.hook("commit", node=node, parent1=parent1,
parent2=parent2)
self._afterlock(commithook)
@@ -1755,89 +1755,55 @@
"""
return util.hooks()
- def stream_in(self, remote, requirements):
+ def stream_in(self, remote, remotereqs):
+ # Save remote branchmap. We will use it later
+ # to speed up branchcache creation
+ rbranchmap = None
+ if remote.capable("branchmap"):
+ rbranchmap = remote.branchmap()
+
+ fp = remote.stream_out()
+ l = fp.readline()
+ try:
+ resp = int(l)
+ except ValueError:
+ raise error.ResponseError(
+ _('unexpected response from remote server:'), l)
+ if resp == 1:
+ raise util.Abort(_('operation forbidden by server'))
+ elif resp == 2:
+ raise util.Abort(_('locking the remote repository failed'))
+ elif resp != 0:
+ raise util.Abort(_('the server sent an unknown error code'))
+
+ self.applystreamclone(remotereqs, rbranchmap, fp)
+ return len(self.heads()) + 1
+
+ def applystreamclone(self, remotereqs, remotebranchmap, fp):
+ """Apply stream clone data to this repository.
+
+ "remotereqs" is a set of requirements to handle the incoming data.
+ "remotebranchmap" is the result of a branchmap lookup on the remote. It
+ can be None.
+ "fp" is a file object containing the raw stream data, suitable for
+ feeding into exchange.consumestreamclone.
+ """
lock = self.lock()
try:
- # Save remote branchmap. We will use it later
- # to speed up branchcache creation
- rbranchmap = None
- if remote.capable("branchmap"):
- rbranchmap = remote.branchmap()
-
- fp = remote.stream_out()
- l = fp.readline()
- try:
- resp = int(l)
- except ValueError:
- raise error.ResponseError(
- _('unexpected response from remote server:'), l)
- if resp == 1:
- raise util.Abort(_('operation forbidden by server'))
- elif resp == 2:
- raise util.Abort(_('locking the remote repository failed'))
- elif resp != 0:
- raise util.Abort(_('the server sent an unknown error code'))
- self.ui.status(_('streaming all changes\n'))
- l = fp.readline()
- try:
- total_files, total_bytes = map(int, l.split(' ', 1))
- except (ValueError, TypeError):
- raise error.ResponseError(
- _('unexpected response from remote server:'), l)
- self.ui.status(_('%d files to transfer, %s of data\n') %
- (total_files, util.bytecount(total_bytes)))
- handled_bytes = 0
- self.ui.progress(_('clone'), 0, total=total_bytes)
- start = time.time()
-
- tr = self.transaction(_('clone'))
- try:
- for i in xrange(total_files):
- # XXX doesn't support '\n' or '\r' in filenames
- l = fp.readline()
- try:
- name, size = l.split('\0', 1)
- size = int(size)
- except (ValueError, TypeError):
- raise error.ResponseError(
- _('unexpected response from remote server:'), l)
- if self.ui.debugflag:
- self.ui.debug('adding %s (%s)\n' %
- (name, util.bytecount(size)))
- # for backwards compat, name was partially encoded
- ofp = self.svfs(store.decodedir(name), 'w')
- for chunk in util.filechunkiter(fp, limit=size):
- handled_bytes += len(chunk)
- self.ui.progress(_('clone'), handled_bytes,
- total=total_bytes)
- ofp.write(chunk)
- ofp.close()
- tr.close()
- finally:
- tr.release()
-
- # Writing straight to files circumvented the inmemory caches
- self.invalidate()
-
- elapsed = time.time() - start
- if elapsed <= 0:
- elapsed = 0.001
- self.ui.progress(_('clone'), None)
- self.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
- (util.bytecount(total_bytes), elapsed,
- util.bytecount(total_bytes / elapsed)))
+ exchange.consumestreamclone(self, fp)
# 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:
+ if remotebranchmap:
rbheads = []
closed = []
- for bheads in rbranchmap.itervalues():
+ for bheads in remotebranchmap.itervalues():
rbheads.extend(bheads)
for h in bheads:
r = self.changelog.rev(h)
@@ -1848,7 +1814,7 @@
if rbheads:
rtiprev = max((int(self.changelog.rev(node))
for node in rbheads))
- cache = branchmap.branchcache(rbranchmap,
+ cache = branchmap.branchcache(remotebranchmap,
self[rtiprev].node(),
rtiprev,
closednodes=closed)
@@ -1861,7 +1827,6 @@
cache.write(rview)
break
self.invalidate()
- return len(self.heads()) + 1
finally:
lock.release()
--- a/mercurial/mail.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/mail.py Mon Jun 15 13:31:22 2015 -0500
@@ -9,10 +9,6 @@
import util, encoding, sslutil
import os, smtplib, socket, quopri, time, sys
import email
-# On python2.4 you have to import these by name or they fail to
-# load. This was not a problem on Python 2.7.
-import email.Header
-import email.MIMEText
_oldheaderinit = email.Header.Header.__init__
def _unifiedheaderinit(self, *args, **kw):
@@ -49,8 +45,8 @@
raise smtplib.SMTPException(msg)
(resp, reply) = self.docmd("STARTTLS")
if resp == 220:
- self.sock = sslutil.ssl_wrap_socket(self.sock, keyfile, certfile,
- **self._sslkwargs)
+ self.sock = sslutil.wrapsocket(self.sock, keyfile, certfile,
+ **self._sslkwargs)
if not util.safehasattr(self.sock, "read"):
# using httplib.FakeSocket with Python 2.5.x or earlier
self.sock.read = self.sock.recv
@@ -78,9 +74,9 @@
if self.debuglevel > 0:
print >> sys.stderr, 'connect:', (host, port)
new_socket = socket.create_connection((host, port), timeout)
- new_socket = sslutil.ssl_wrap_socket(new_socket,
- self.keyfile, self.certfile,
- **self._sslkwargs)
+ new_socket = sslutil.wrapsocket(new_socket,
+ self.keyfile, self.certfile,
+ **self._sslkwargs)
self.file = smtplib.SSLFakeFile(new_socket)
return new_socket
else:
@@ -108,7 +104,8 @@
if (starttls or smtps) and verifycert:
sslkwargs = sslutil.sslkwargs(ui, mailhost)
else:
- sslkwargs = {}
+ # 'ui' is required by sslutil.wrapsocket() and set by sslkwargs()
+ sslkwargs = {'ui': ui}
if smtps:
ui.note(_('(using smtps)\n'))
s = SMTPS(sslkwargs, local_hostname=local_hostname)
--- a/mercurial/manifest.c Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/manifest.c Mon Jun 15 13:31:22 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 Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/manifest.py Mon Jun 15 13:31:22 2015 -0500
@@ -219,7 +219,7 @@
files instead of over manifest files.'''
files = match.files()
return (len(files) < 100 and (match.isexact() or
- (not match.anypats() and util.all(fn in self for fn in files))))
+ (match.prefix() and all(fn in self for fn in files))))
def walk(self, match):
'''Generates matching file names.
@@ -441,32 +441,64 @@
else:
return '', f
+_noop = lambda: None
+
class treemanifest(object):
def __init__(self, dir='', text=''):
self._dir = dir
+ self._node = revlog.nullid
+ self._load = _noop
+ self._dirty = False
self._dirs = {}
# Using _lazymanifest here is a little slower than plain old dicts
self._files = {}
self._flags = {}
- self.parse(text)
+ if text:
+ def readsubtree(subdir, subm):
+ raise AssertionError('treemanifest constructor only accepts '
+ 'flat manifests')
+ self.parse(text, readsubtree)
+ self._dirty = True # Mark flat manifest dirty after parsing
def _subpath(self, path):
return self._dir + path
def __len__(self):
+ self._load()
size = len(self._files)
for m in self._dirs.values():
size += m.__len__()
return size
def _isempty(self):
+ self._load() # for consistency; already loaded by all callers
return (not self._files and (not self._dirs or
- util.all(m._isempty() for m in self._dirs.values())))
+ all(m._isempty() for m in self._dirs.values())))
def __str__(self):
- return '<treemanifest dir=%s>' % self._dir
+ return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s>' %
+ (self._dir, revlog.hex(self._node),
+ bool(self._load is _noop),
+ self._dirty))
+
+ def dir(self):
+ '''The directory that this tree manifest represents, including a
+ trailing '/'. Empty string for the repo root directory.'''
+ return self._dir
+
+ def node(self):
+ '''This node of this instance. nullid for unsaved instances. Should
+ be updated when the instance is read or written from a revlog.
+ '''
+ assert not self._dirty
+ return self._node
+
+ def setnode(self, node):
+ self._node = node
+ self._dirty = False
def iteritems(self):
+ self._load()
for p, n in sorted(self._dirs.items() + self._files.items()):
if p in self._files:
yield self._subpath(p), n
@@ -475,6 +507,7 @@
yield f, sn
def iterkeys(self):
+ self._load()
for p in sorted(self._dirs.keys() + self._files.keys()):
if p in self._files:
yield self._subpath(p)
@@ -491,6 +524,7 @@
def __contains__(self, f):
if f is None:
return False
+ self._load()
dir, subpath = _splittopdir(f)
if dir:
if dir not in self._dirs:
@@ -500,6 +534,7 @@
return f in self._files
def get(self, f, default=None):
+ self._load()
dir, subpath = _splittopdir(f)
if dir:
if dir not in self._dirs:
@@ -509,6 +544,7 @@
return self._files.get(f, default)
def __getitem__(self, f):
+ self._load()
dir, subpath = _splittopdir(f)
if dir:
return self._dirs[dir].__getitem__(subpath)
@@ -516,6 +552,7 @@
return self._files[f]
def flags(self, f):
+ self._load()
dir, subpath = _splittopdir(f)
if dir:
if dir not in self._dirs:
@@ -527,6 +564,7 @@
return self._flags.get(f, '')
def find(self, f):
+ self._load()
dir, subpath = _splittopdir(f)
if dir:
return self._dirs[dir].find(subpath)
@@ -534,6 +572,7 @@
return self._files[f], self._flags.get(f, '')
def __delitem__(self, f):
+ self._load()
dir, subpath = _splittopdir(f)
if dir:
self._dirs[dir].__delitem__(subpath)
@@ -544,9 +583,11 @@
del self._files[f]
if f in self._flags:
del self._flags[f]
+ self._dirty = True
def __setitem__(self, f, n):
assert n is not None
+ self._load()
dir, subpath = _splittopdir(f)
if dir:
if dir not in self._dirs:
@@ -554,9 +595,12 @@
self._dirs[dir].__setitem__(subpath, n)
else:
self._files[f] = n[:21] # to match manifestdict's behavior
+ self._dirty = True
def setflag(self, f, flags):
"""Set the flags (symlink, executable) for path f."""
+ assert 'd' not in flags
+ self._load()
dir, subpath = _splittopdir(f)
if dir:
if dir not in self._dirs:
@@ -564,19 +608,35 @@
self._dirs[dir].setflag(subpath, flags)
else:
self._flags[f] = flags
+ self._dirty = True
def copy(self):
copy = treemanifest(self._dir)
- for d in self._dirs:
- copy._dirs[d] = self._dirs[d].copy()
- copy._files = dict.copy(self._files)
- copy._flags = dict.copy(self._flags)
+ copy._node = self._node
+ copy._dirty = self._dirty
+ def _load():
+ self._load()
+ for d in self._dirs:
+ copy._dirs[d] = self._dirs[d].copy()
+ copy._files = dict.copy(self._files)
+ copy._flags = dict.copy(self._flags)
+ copy._load = _noop
+ copy._load = _load
+ if self._load == _noop:
+ # Chaining _load if it's _noop is functionally correct, but the
+ # chain may end up excessively long (stack overflow), and
+ # will prevent garbage collection of 'self'.
+ copy._load()
return copy
def filesnotin(self, m2):
'''Set of files in this manifest that are not in the other'''
files = set()
def _filesnotin(t1, t2):
+ if t1._node == t2._node and not t1._dirty and not t2._dirty:
+ return
+ t1._load()
+ t2._load()
for d, m1 in t1._dirs.iteritems():
if d in t2._dirs:
m2 = t2._dirs[d]
@@ -599,6 +659,7 @@
return self._alldirs
def hasdir(self, dir):
+ self._load()
topdir, subdir = _splittopdir(dir)
if topdir:
if topdir in self._dirs:
@@ -635,27 +696,20 @@
if not self.hasdir(fn):
match.bad(fn, None)
- def _walk(self, match, alldirs=False):
- '''Recursively generates matching file names for walk().
-
- Will visit all subdirectories if alldirs is True, otherwise it will
- only visit subdirectories for which match.visitdir is True.'''
-
- if not alldirs:
- # substring to strip trailing slash
- visit = match.visitdir(self._dir[:-1] or '.')
- if not visit:
- return
- alldirs = (visit == 'all')
+ def _walk(self, match):
+ '''Recursively generates matching file names for walk().'''
+ if not match.visitdir(self._dir[:-1] or '.'):
+ return
# yield this dir's files and walk its submanifests
+ self._load()
for p in sorted(self._dirs.keys() + self._files.keys()):
if p in self._files:
fullp = self._subpath(p)
if match(fullp):
yield fullp
else:
- for f in self._dirs[p]._walk(match, alldirs):
+ for f in self._dirs[p]._walk(match):
yield f
def matches(self, match):
@@ -665,20 +719,15 @@
return self._matches(match)
- def _matches(self, match, alldirs=False):
+ def _matches(self, match):
'''recursively generate a new manifest filtered by the match argument.
-
- Will visit all subdirectories if alldirs is True, otherwise it will
- only visit subdirectories for which match.visitdir is True.'''
-
+ '''
ret = treemanifest(self._dir)
- if not alldirs:
- # substring to strip trailing slash
- visit = match.visitdir(self._dir[:-1] or '.')
- if not visit:
- return ret
- alldirs = (visit == 'all')
+ if not match.visitdir(self._dir[:-1] or '.'):
+ return ret
+
+ self._load()
for fn in self._files:
fullp = self._subpath(fn)
if not match(fullp):
@@ -688,10 +737,12 @@
ret._flags[fn] = self._flags[fn]
for dir, subm in self._dirs.iteritems():
- m = subm._matches(match, alldirs)
+ m = subm._matches(match)
if not m._isempty():
ret._dirs[dir] = m
+ if not ret._isempty():
+ ret._dirty = True
return ret
def diff(self, m2, clean=False):
@@ -712,6 +763,10 @@
result = {}
emptytree = treemanifest()
def _diff(t1, t2):
+ if t1._node == t2._node and not t1._dirty and not t2._dirty:
+ return
+ t1._load()
+ t2._load()
for d, m1 in t1._dirs.iteritems():
m2 = t2._dirs.get(d, emptytree)
_diff(m1, m2)
@@ -737,20 +792,71 @@
_diff(self, m2)
return result
- def parse(self, text):
+ def unmodifiedsince(self, m2):
+ return not self._dirty and not m2._dirty and self._node == m2._node
+
+ def parse(self, text, readsubtree):
for f, n, fl in _parse(text):
- self[f] = n
- if fl:
- self.setflag(f, fl)
+ if fl == 'd':
+ f = f + '/'
+ self._dirs[f] = readsubtree(self._subpath(f), n)
+ elif '/' in f:
+ # This is a flat manifest, so use __setitem__ and setflag rather
+ # than assigning directly to _files and _flags, so we can
+ # assign a path in a subdirectory, and to mark dirty (compared
+ # to nullid).
+ self[f] = n
+ if fl:
+ self.setflag(f, fl)
+ else:
+ # Assigning to _files and _flags avoids marking as dirty,
+ # and should be a little faster.
+ self._files[f] = n
+ if fl:
+ self._flags[f] = fl
def text(self, usemanifestv2=False):
"""Get the full data of this manifest as a bytestring."""
+ self._load()
flags = self.flags
return _text(((f, self[f], flags(f)) for f in self.keys()),
usemanifestv2)
+ def dirtext(self, usemanifestv2=False):
+ """Get the full data of this directory as a bytestring. Make sure that
+ any submanifests have been written first, so their nodeids are correct.
+ """
+ self._load()
+ flags = self.flags
+ dirs = [(d[:-1], self._dirs[d]._node, 'd') for d in self._dirs]
+ files = [(f, self._files[f], flags(f)) for f in self._files]
+ return _text(sorted(dirs + files), usemanifestv2)
+
+ def read(self, gettext, readsubtree):
+ def _load():
+ # Mark as loaded already here, so __setitem__ and setflag() don't
+ # cause infinite loops when they try to load.
+ self._load = _noop
+ self.parse(gettext(), readsubtree)
+ self._dirty = False
+ self._load = _load
+
+ def writesubtrees(self, m1, m2, writesubtree):
+ self._load() # for consistency; should never have any effect here
+ emptytree = treemanifest()
+ for d, subm in self._dirs.iteritems():
+ subp1 = m1._dirs.get(d, emptytree)._node
+ subp2 = m2._dirs.get(d, emptytree)._node
+ if subp1 == revlog.nullid:
+ subp1, subp2 = subp2, subp1
+ writesubtree(subm, subp1, subp2)
+
class manifest(revlog.revlog):
- def __init__(self, opener):
+ def __init__(self, opener, dir='', dirlogcache=None):
+ '''The 'dir' and 'dirlogcache' arguments are for internal use by
+ manifest.manifest only. External users should create a root manifest
+ log with manifest.manifest(opener) and call dirlog() on it.
+ '''
# During normal operations, we expect to deal with not more than four
# revs at a time (such as during commit --amend). When rebasing large
# stacks of commits, the number can go up, hence the config knob below.
@@ -760,19 +866,38 @@
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")
self._treeinmem = usetreemanifest
self._treeondisk = usetreemanifest
self._usemanifestv2 = usemanifestv2
+ indexfile = "00manifest.i"
+ if dir:
+ assert self._treeondisk
+ if not dir.endswith('/'):
+ dir = dir + '/'
+ indexfile = "meta/" + dir + "00manifest.i"
+ revlog.revlog.__init__(self, opener, indexfile)
+ self._dir = dir
+ # The dirlogcache is kept on the root manifest log
+ if dir:
+ self._dirlogcache = dirlogcache
+ else:
+ self._dirlogcache = {'': self}
def _newmanifest(self, data=''):
if self._treeinmem:
- return treemanifest('', data)
+ return treemanifest(self._dir, data)
return manifestdict(data)
+ def dirlog(self, dir):
+ assert self._treeondisk
+ if dir not in self._dirlogcache:
+ self._dirlogcache[dir] = manifest(self.opener, dir,
+ self._dirlogcache)
+ return self._dirlogcache[dir]
+
def _slowreaddelta(self, node):
r0 = self.deltaparent(self.rev(node))
m0 = self.read(self.node(r0))
@@ -793,7 +918,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):
@@ -805,9 +936,19 @@
return self._newmanifest() # don't upset local cache
if node in self._mancache:
return self._mancache[node][0]
- text = self.revision(node)
- arraytext = array.array('c', text)
- m = self._newmanifest(text)
+ if self._treeondisk:
+ def gettext():
+ return self.revision(node)
+ def readsubtree(dir, subm):
+ return self.dirlog(dir).read(subm)
+ m = self._newmanifest()
+ m.read(gettext, readsubtree)
+ m.setnode(node)
+ arraytext = None
+ else:
+ text = self.revision(node)
+ m = self._newmanifest(text)
+ arraytext = array.array('c', text)
self._mancache[node] = (m, arraytext)
return m
@@ -845,10 +986,37 @@
# just encode a fulltext of the manifest and pass that
# through to the revlog layer, and let it handle the delta
# process.
- text = m.text(self._usemanifestv2)
- arraytext = array.array('c', text)
- n = self.addrevision(text, transaction, link, p1, p2)
+ if self._treeondisk:
+ m1 = self.read(p1)
+ m2 = self.read(p2)
+ n = self._addtree(m, transaction, link, m1, m2)
+ arraytext = None
+ else:
+ text = m.text(self._usemanifestv2)
+ n = self.addrevision(text, transaction, link, p1, p2)
+ arraytext = array.array('c', text)
self._mancache[n] = (m, arraytext)
return n
+
+ def _addtree(self, m, transaction, link, m1, m2):
+ # If the manifest is unchanged compared to one parent,
+ # don't write a new revision
+ if m.unmodifiedsince(m1) or m.unmodifiedsince(m2):
+ return m.node()
+ def writesubtree(subm, subp1, subp2):
+ sublog = self.dirlog(subm.dir())
+ sublog.add(subm, transaction, link, subp1, subp2, None, None)
+ m.writesubtrees(m1, m2, writesubtree)
+ text = m.dirtext(self._usemanifestv2)
+ # Double-check whether contents are unchanged to one parent
+ if text == m1.dirtext(self._usemanifestv2):
+ n = m1.node()
+ elif text == m2.dirtext(self._usemanifestv2):
+ n = m2.node()
+ else:
+ n = self.addrevision(text, transaction, link, m1.node(), m2.node())
+ # Save nodeid so parent manifest can calculate its nodeid
+ m.setnode(n)
+ return n
--- a/mercurial/match.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/match.py Mon Jun 15 13:31:22 2015 -0500
@@ -5,7 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import re
+import copy, re
import util, pathutil
from i18n import _
@@ -21,33 +21,64 @@
except AttributeError:
return m.match
-def _expandsets(kindpats, ctx):
+def _expandsets(kindpats, ctx, listsubrepos):
'''Returns the kindpats list with the 'set' patterns expanded.'''
fset = set()
other = []
- for kind, pat in kindpats:
+ for kind, pat, source in kindpats:
if kind == 'set':
if not ctx:
raise util.Abort("fileset expression with no context")
s = ctx.getfileset(pat)
fset.update(s)
+
+ if listsubrepos:
+ for subpath in ctx.substate:
+ s = ctx.sub(subpath).getfileset(pat)
+ fset.update(subpath + '/' + f for f in s)
+
continue
- other.append((kind, pat))
+ other.append((kind, pat, source))
return fset, other
+def _expandsubinclude(kindpats, root):
+ '''Returns the list of subinclude matchers and the kindpats without the
+ subincludes in it.'''
+ relmatchers = []
+ other = []
+
+ for kind, pat, source in kindpats:
+ if kind == 'subinclude':
+ sourceroot = pathutil.dirname(util.normpath(source))
+ pat = util.pconvert(pat)
+ path = pathutil.join(sourceroot, pat)
+
+ newroot = pathutil.dirname(path)
+ relmatcher = match(newroot, '', [], ['include:%s' % path])
+
+ prefix = pathutil.canonpath(root, root, newroot)
+ if prefix:
+ prefix += '/'
+ relmatchers.append((prefix, relmatcher))
+ else:
+ other.append((kind, pat, source))
+
+ return relmatchers, other
+
def _kindpatsalwaysmatch(kindpats):
""""Checks whether the kindspats match everything, as e.g.
'relpath:.' does.
"""
- for kind, pat in kindpats:
+ for kind, pat, source in kindpats:
if pat != '' or kind not in ['relpath', 'glob']:
return False
return True
class match(object):
def __init__(self, root, cwd, patterns, include=[], exclude=[],
- default='glob', exact=False, auditor=None, ctx=None):
+ default='glob', exact=False, auditor=None, ctx=None,
+ listsubrepos=False, warn=None, badfn=None):
"""build an object to match a set of file patterns
arguments:
@@ -58,6 +89,8 @@
exclude - patterns to exclude (even if they are included)
default - if a pattern in patterns has no explicit type, assume this one
exact - patterns are actually filenames (include/exclude still apply)
+ warn - optional function used for printing warnings
+ badfn - optional bad() callback for this matcher instead of the default
a pattern is one of:
'glob:<glob>' - a glob relative to cwd
@@ -67,6 +100,9 @@
'relpath:<path>' - a path relative to cwd
'relre:<regexp>' - a regexp that needn't match the start of a name
'set:<fileset>' - a fileset expression
+ 'include:<path>' - a file of patterns to read and include
+ 'subinclude:<path>' - a file of patterns to match against files under
+ the same directory
'<something>' - a pattern of the specified default type
"""
@@ -76,15 +112,28 @@
self._anypats = bool(include or exclude)
self._always = False
self._pathrestricted = bool(include or exclude or patterns)
+ self._warn = warn
+ self._includeroots = set()
+ self._includedirs = set(['.'])
+ self._excluderoots = set()
+
+ if badfn is not None:
+ self.bad = badfn
matchfns = []
if include:
kindpats = self._normalize(include, 'glob', root, cwd, auditor)
- self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)')
+ self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)',
+ listsubrepos, root)
+ self._includeroots.update(_roots(kindpats))
+ self._includedirs.update(util.dirs(self._includeroots))
matchfns.append(im)
if exclude:
kindpats = self._normalize(exclude, 'glob', root, cwd, auditor)
- self.excludepat, em = _buildmatch(ctx, kindpats, '(?:/|$)')
+ self.excludepat, em = _buildmatch(ctx, kindpats, '(?:/|$)',
+ listsubrepos, root)
+ if not _anypats(kindpats):
+ self._excluderoots.update(_roots(kindpats))
matchfns.append(lambda f: not em(f))
if exact:
if isinstance(patterns, list):
@@ -97,7 +146,8 @@
if not _kindpatsalwaysmatch(kindpats):
self._files = _roots(kindpats)
self._anypats = self._anypats or _anypats(kindpats)
- self.patternspat, pm = _buildmatch(ctx, kindpats, '$')
+ self.patternspat, pm = _buildmatch(ctx, kindpats, '$',
+ listsubrepos, root)
matchfns.append(pm)
if not matchfns:
@@ -113,7 +163,7 @@
return True
self.matchfn = m
- self._fmap = set(self._files)
+ self._fileroots = set(self._files)
def __call__(self, fn):
return self.matchfn(fn)
@@ -161,21 +211,35 @@
@propertycache
def _dirs(self):
- return set(util.dirs(self._fmap)) | set(['.'])
+ return set(util.dirs(self._fileroots)) | set(['.'])
def visitdir(self, dir):
- '''Helps while traversing a directory tree. Returns the string 'all' if
- the given directory and all subdirectories should be visited. Otherwise
- returns True or False indicating whether the given directory should be
- visited. If 'all' is returned, calling this method on a subdirectory
- gives an undefined result.'''
- if not self._fmap or self.exact(dir):
- return 'all'
- return dir in self._dirs
+ '''Decides whether a directory should be visited based on whether it
+ has potential matches in it or one of its subdirectories. This is
+ based on the match's primary, included, and excluded patterns.
+
+ This function's behavior is undefined if it has returned False for
+ one of the dir's parent directories.
+ '''
+ if dir in self._excluderoots:
+ return False
+ if (self._includeroots and
+ '.' not in self._includeroots and
+ dir not in self._includeroots and
+ dir not in self._includedirs and
+ not any(parent in self._includeroots
+ for parent in util.finddirs(dir))):
+ return False
+ return (not self._fileroots or
+ '.' in self._fileroots or
+ dir in self._fileroots or
+ dir in self._dirs or
+ any(parentdir in self._fileroots
+ for parentdir in util.finddirs(dir)))
def exact(self, f):
'''Returns True if f is in .files().'''
- return f in self._fmap
+ return f in self._fileroots
def anypats(self):
'''Matcher uses patterns or include/exclude.'''
@@ -186,9 +250,20 @@
- optimization might be possible and necessary.'''
return self._always
+ def ispartial(self):
+ '''True if the matcher won't always match.
+
+ Although it's just the inverse of _always in this implementation,
+ an extenion such as narrowhg might make it return something
+ slightly different.'''
+ return not self._always
+
def isexact(self):
return self.matchfn == self.exact
+ def prefix(self):
+ return not self.always() and not self.isexact() and not self.anypats()
+
def _normalize(self, patterns, default, root, cwd, auditor):
'''Convert 'kind:pat' from the patterns list to tuples with kind and
normalized and rooted patterns and with listfiles expanded.'''
@@ -208,18 +283,41 @@
files = [f for f in files if f]
except EnvironmentError:
raise util.Abort(_("unable to read file list (%s)") % pat)
- kindpats += self._normalize(files, default, root, cwd, auditor)
+ for k, p, source in self._normalize(files, default, root, cwd,
+ auditor):
+ kindpats.append((k, p, pat))
+ continue
+ elif kind == 'include':
+ try:
+ includepats = readpatternfile(pat, self._warn)
+ for k, p, source in self._normalize(includepats, default,
+ root, cwd, auditor):
+ kindpats.append((k, p, source or pat))
+ except util.Abort, inst:
+ raise util.Abort('%s: %s' % (pat, inst[0]))
+ except IOError, inst:
+ if self._warn:
+ self._warn(_("skipping unreadable pattern file "
+ "'%s': %s\n") % (pat, inst.strerror))
continue
# else: re or relre - which cannot be normalized
- kindpats.append((kind, pat))
+ kindpats.append((kind, pat, ''))
return kindpats
-def exact(root, cwd, files):
- return match(root, cwd, files, exact=True)
+def exact(root, cwd, files, badfn=None):
+ return match(root, cwd, files, exact=True, badfn=badfn)
def always(root, cwd):
return match(root, cwd, [])
+def badmatch(match, badfn):
+ """Make a copy of the given matcher, replacing its bad method with the given
+ one.
+ """
+ m = copy.copy(match)
+ m.bad = badfn
+ return m
+
class narrowmatcher(match):
"""Adapt a matcher to work on a subdirectory only.
@@ -264,11 +362,11 @@
# If the parent repo had a path to this subrepo and no patterns are
# specified, this submatcher always matches.
if not self._always and not matcher._anypats:
- self._always = util.any(f == path for f in matcher._files)
+ self._always = any(f == path for f in matcher._files)
self._anypats = matcher._anypats
self.matchfn = lambda fn: matcher.matchfn(self._path + "/" + fn)
- self._fmap = set(self._files)
+ self._fileroots = set(self._files)
def abs(self, f):
return self._matcher.abs(self._path + "/" + f)
@@ -285,26 +383,26 @@
"""
def __init__(self, root, cwd, patterns, include, exclude, default, auditor,
- ctx):
+ ctx, listsubrepos=False, badfn=None):
init = super(icasefsmatcher, self).__init__
self._dsnormalize = ctx.repo().dirstate.normalize
init(root, cwd, patterns, include, exclude, default, auditor=auditor,
- ctx=ctx)
+ ctx=ctx, listsubrepos=listsubrepos, badfn=badfn)
# m.exact(file) must be based off of the actual user input, otherwise
# inexact case matches are treated as exact, and not noted without -v.
if self._files:
- self._fmap = set(_roots(self._kp))
+ self._fileroots = set(_roots(self._kp))
def _normalize(self, patterns, default, root, cwd, auditor):
self._kp = super(icasefsmatcher, self)._normalize(patterns, default,
root, cwd, auditor)
kindpats = []
- for kind, pats in self._kp:
+ for kind, pats, source in self._kp:
if kind not in ('re', 'relre'): # regex can't be normalized
pats = self._dsnormalize(pats)
- kindpats.append((kind, pats))
+ kindpats.append((kind, pats, source))
return kindpats
def patkind(pattern, default=None):
@@ -317,7 +415,7 @@
if ':' in pattern:
kind, pat = pattern.split(':', 1)
if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
- 'listfile', 'listfile0', 'set'):
+ 'listfile', 'listfile0', 'set', 'include', 'subinclude'):
return kind, pat
return default, pattern
@@ -418,24 +516,40 @@
return '.*' + pat
return _globre(pat) + globsuffix
-def _buildmatch(ctx, kindpats, globsuffix):
+def _buildmatch(ctx, kindpats, globsuffix, listsubrepos, root):
'''Return regexp string and a matcher function for kindpats.
globsuffix is appended to the regexp of globs.'''
- fset, kindpats = _expandsets(kindpats, ctx)
- if not kindpats:
- return "", fset.__contains__
+ matchfuncs = []
+
+ subincludes, kindpats = _expandsubinclude(kindpats, root)
+ if subincludes:
+ def matchsubinclude(f):
+ for prefix, mf in subincludes:
+ if f.startswith(prefix) and mf(f[len(prefix):]):
+ return True
+ return False
+ matchfuncs.append(matchsubinclude)
- regex, mf = _buildregexmatch(kindpats, globsuffix)
+ fset, kindpats = _expandsets(kindpats, ctx, listsubrepos)
if fset:
- return regex, lambda f: f in fset or mf(f)
- return regex, mf
+ matchfuncs.append(fset.__contains__)
+
+ regex = ''
+ if kindpats:
+ regex, mf = _buildregexmatch(kindpats, globsuffix)
+ matchfuncs.append(mf)
+
+ if len(matchfuncs) == 1:
+ return regex, matchfuncs[0]
+ else:
+ return regex, lambda f: any(mf(f) for mf in matchfuncs)
def _buildregexmatch(kindpats, globsuffix):
"""Build a match function from a list of kinds and kindpats,
return regexp string and a matcher function."""
try:
regex = '(?:%s)' % '|'.join([_regex(k, p, globsuffix)
- for (k, p) in kindpats])
+ for (k, p, s) in kindpats])
if len(regex) > 20000:
raise OverflowError
return regex, _rematcher(regex)
@@ -450,25 +564,29 @@
regexb, b = _buildregexmatch(kindpats[l//2:], globsuffix)
return regex, lambda s: a(s) or b(s)
except re.error:
- for k, p in kindpats:
+ for k, p, s in kindpats:
try:
_rematcher('(?:%s)' % _regex(k, p, globsuffix))
except re.error:
- raise util.Abort(_("invalid pattern (%s): %s") % (k, p))
+ if s:
+ raise util.Abort(_("%s: invalid pattern (%s): %s") %
+ (s, k, p))
+ else:
+ raise util.Abort(_("invalid pattern (%s): %s") % (k, p))
raise util.Abort(_("invalid pattern"))
def _roots(kindpats):
'''return roots and exact explicitly listed files from patterns
- >>> _roots([('glob', 'g/*'), ('glob', 'g'), ('glob', 'g*')])
+ >>> _roots([('glob', 'g/*', ''), ('glob', 'g', ''), ('glob', 'g*', '')])
['g', 'g', '.']
- >>> _roots([('relpath', 'r'), ('path', 'p/p'), ('path', '')])
+ >>> _roots([('relpath', 'r', ''), ('path', 'p/p', ''), ('path', '', '')])
['r', 'p/p', '.']
- >>> _roots([('relglob', 'rg*'), ('re', 're/'), ('relre', 'rr')])
+ >>> _roots([('relglob', 'rg*', ''), ('re', 're/', ''), ('relre', 'rr', '')])
['.', '.', '.']
'''
r = []
- for kind, pat in kindpats:
+ for kind, pat, source in kindpats:
if kind == 'glob': # find the non-glob prefix
root = []
for p in pat.split('/'):
@@ -483,6 +601,69 @@
return r
def _anypats(kindpats):
- for kind, pat in kindpats:
+ for kind, pat, source in kindpats:
if kind in ('glob', 're', 'relglob', 'relre', 'set'):
return True
+
+_commentre = None
+
+def readpatternfile(filepath, warn):
+ '''parse a pattern file, returning a list of
+ patterns. These patterns should be given to compile()
+ to be validated and converted into a match function.
+
+ trailing white space is dropped.
+ the escape character is backslash.
+ comments start with #.
+ empty lines are skipped.
+
+ lines can be of the following formats:
+
+ syntax: regexp # defaults following lines to non-rooted regexps
+ syntax: glob # defaults following lines to non-rooted globs
+ re:pattern # non-rooted regular expression
+ glob:pattern # non-rooted glob
+ pattern # pattern of the current default type'''
+
+ syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:',
+ 'include': 'include', 'subinclude': 'subinclude'}
+ syntax = 'relre:'
+ patterns = []
+
+ fp = open(filepath)
+ for line in fp:
+ if "#" in line:
+ global _commentre
+ if not _commentre:
+ _commentre = re.compile(r'((^|[^\\])(\\\\)*)#.*')
+ # remove comments prefixed by an even number of escapes
+ line = _commentre.sub(r'\1', line)
+ # fixup properly escaped comments that survived the above
+ line = line.replace("\\#", "#")
+ line = line.rstrip()
+ if not line:
+ continue
+
+ if line.startswith('syntax:'):
+ s = line[7:].strip()
+ try:
+ syntax = syntaxes[s]
+ except KeyError:
+ if warn:
+ warn(_("%s: ignoring invalid syntax '%s'\n") %
+ (filepath, s))
+ continue
+
+ linesyntax = syntax
+ for s, rels in syntaxes.iteritems():
+ if line.startswith(rels):
+ linesyntax = rels
+ line = line[len(rels):]
+ break
+ elif line.startswith(s+':'):
+ linesyntax = rels
+ line = line[len(s) + 1:]
+ break
+ patterns.append(linesyntax + line)
+ fp.close()
+ return patterns
--- a/mercurial/merge.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/merge.py Mon Jun 15 13:31:22 2015 -0500
@@ -605,7 +605,7 @@
# Consensus?
if len(bids) == 1: # all bids are the same kind of method
m, l = bids.items()[0]
- if util.all(a == l[0] for a in l[1:]): # len(bids) is > 1
+ if all(a == l[0] for a in l[1:]): # len(bids) is > 1
repo.ui.note(" %s: consensus for %s\n" % (f, m))
actions[f] = l[0]
continue
@@ -617,7 +617,7 @@
# If there are gets and they all agree [how could they not?], do it.
if 'g' in bids:
ga0 = bids['g'][0]
- if util.all(a == ga0 for a in bids['g'][1:]):
+ if all(a == ga0 for a in bids['g'][1:]):
repo.ui.note(" %s: picking 'get' action\n" % f)
actions[f] = ga0
continue
--- a/mercurial/obsolete.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/obsolete.py Mon Jun 15 13:31:22 2015 -0500
@@ -299,7 +299,7 @@
# Loop on markers
stop = len(data) - _fm1fsize
- ufixed = util.unpacker(_fm1fixed)
+ ufixed = struct.Struct(_fm1fixed).unpack
while off <= stop:
# read fixed part
@@ -718,7 +718,7 @@
"""List markers over pushkey"""
if not repo.obsstore:
return {}
- return _pushkeyescape(repo.obsstore)
+ return _pushkeyescape(sorted(repo.obsstore))
def pushmarker(repo, key, old, new):
"""Push markers over pushkey"""
@@ -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 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')
@@ -1211,8 +1214,9 @@
localmetadata.update(rel[2])
if not prec.mutable():
- raise util.Abort("cannot obsolete immutable changeset: %s"
- % prec)
+ raise util.Abort("cannot obsolete public changeset: %s"
+ % prec,
+ hint='see "hg help phases" for details')
nprec = prec.node()
nsucs = tuple(s.node() for s in sucs)
npare = None
--- a/mercurial/parser.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/parser.py Mon Jun 15 13:31:22 2015 -0500
@@ -27,10 +27,7 @@
def _advance(self):
'advance the tokenizer'
t = self.current
- try:
- self.current = self._iter.next()
- except StopIteration:
- pass
+ self.current = next(self._iter, None)
return t
def _match(self, m, pos):
'make sure the tokenizer matches an end condition'
@@ -96,3 +93,95 @@
if self._methods:
return self.eval(t)
return t
+
+def _prettyformat(tree, leafnodes, level, lines):
+ if not isinstance(tree, tuple) or tree[0] in leafnodes:
+ lines.append((level, str(tree)))
+ else:
+ lines.append((level, '(%s' % tree[0]))
+ for s in tree[1:]:
+ _prettyformat(s, leafnodes, level + 1, lines)
+ lines[-1:] = [(lines[-1][0], lines[-1][1] + ')')]
+
+def prettyformat(tree, leafnodes):
+ lines = []
+ _prettyformat(tree, leafnodes, 0, lines)
+ output = '\n'.join((' ' * l + s) for l, s in lines)
+ return output
+
+def simplifyinfixops(tree, targetnodes):
+ """Flatten chained infix operations to reduce usage of Python stack
+
+ >>> def f(tree):
+ ... print prettyformat(simplifyinfixops(tree, ('or',)), ('symbol',))
+ >>> f(('or',
+ ... ('or',
+ ... ('symbol', '1'),
+ ... ('symbol', '2')),
+ ... ('symbol', '3')))
+ (or
+ ('symbol', '1')
+ ('symbol', '2')
+ ('symbol', '3'))
+ >>> f(('func',
+ ... ('symbol', 'p1'),
+ ... ('or',
+ ... ('or',
+ ... ('func',
+ ... ('symbol', 'sort'),
+ ... ('list',
+ ... ('or',
+ ... ('or',
+ ... ('symbol', '1'),
+ ... ('symbol', '2')),
+ ... ('symbol', '3')),
+ ... ('negate',
+ ... ('symbol', 'rev')))),
+ ... ('and',
+ ... ('symbol', '4'),
+ ... ('group',
+ ... ('or',
+ ... ('or',
+ ... ('symbol', '5'),
+ ... ('symbol', '6')),
+ ... ('symbol', '7'))))),
+ ... ('symbol', '8'))))
+ (func
+ ('symbol', 'p1')
+ (or
+ (func
+ ('symbol', 'sort')
+ (list
+ (or
+ ('symbol', '1')
+ ('symbol', '2')
+ ('symbol', '3'))
+ (negate
+ ('symbol', 'rev'))))
+ (and
+ ('symbol', '4')
+ (group
+ (or
+ ('symbol', '5')
+ ('symbol', '6')
+ ('symbol', '7'))))
+ ('symbol', '8')))
+ """
+ if not isinstance(tree, tuple):
+ return tree
+ op = tree[0]
+ if op not in targetnodes:
+ return (op,) + tuple(simplifyinfixops(x, targetnodes) for x in tree[1:])
+
+ # walk down left nodes taking each right node. no recursion to left nodes
+ # because infix operators are left-associative, i.e. left tree is deep.
+ # e.g. '1 + 2 + 3' -> (+ (+ 1 2) 3) -> (+ 1 2 3)
+ simplified = []
+ x = tree
+ while x[0] == op:
+ l, r = x[1:]
+ simplified.append(simplifyinfixops(r, targetnodes))
+ x = l
+ simplified.append(simplifyinfixops(x, targetnodes))
+ simplified.append(op)
+ return tuple(reversed(simplified))
--- a/mercurial/parsers.c Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/parsers.c Mon Jun 15 13:31:22 2015 -0500
@@ -741,6 +741,22 @@
return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
}
+static inline void index_get_parents(indexObject *self, Py_ssize_t rev,
+ int *ps)
+{
+ if (rev >= self->length - 1) {
+ PyObject *tuple = PyList_GET_ITEM(self->added,
+ rev - self->length + 1);
+ ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
+ ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
+ } else {
+ const char *data = index_deref(self, rev);
+ ps[0] = getbe32(data + 24);
+ ps[1] = getbe32(data + 28);
+ }
+}
+
+
/*
* RevlogNG format (all in big endian, data may be inlined):
* 6 bytes: offset
@@ -1071,23 +1087,21 @@
phases[i] = phases[parent_2];
}
-static PyObject *compute_phases(indexObject *self, PyObject *args)
+static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
{
PyObject *roots = Py_None;
+ PyObject *ret = NULL;
PyObject *phaseslist = NULL;
PyObject *phaseroots = NULL;
- PyObject *rev = NULL;
- PyObject *p1 = NULL;
- PyObject *p2 = NULL;
- Py_ssize_t addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
+ PyObject *phaseset = NULL;
+ PyObject *phasessetlist = NULL;
Py_ssize_t len = index_length(self) - 1;
Py_ssize_t numphase = 0;
Py_ssize_t minrevallphases = 0;
Py_ssize_t minrevphase = 0;
Py_ssize_t i = 0;
- int parent_1, parent_2;
char *phases = NULL;
- const char *data;
+ long phase;
if (!PyArg_ParseTuple(args, "O", &roots))
goto release_none;
@@ -1100,50 +1114,71 @@
/* Put the phase information of all the roots in phases */
numphase = PyList_GET_SIZE(roots)+1;
minrevallphases = len + 1;
+ phasessetlist = PyList_New(numphase);
+ if (phasessetlist == NULL)
+ goto release_none;
+
+ PyList_SET_ITEM(phasessetlist, 0, Py_None);
+ Py_INCREF(Py_None);
+
for (i = 0; i < numphase-1; i++) {
phaseroots = PyList_GET_ITEM(roots, i);
+ phaseset = PySet_New(NULL);
+ if (phaseset == NULL)
+ goto release_phasesetlist;
+ PyList_SET_ITEM(phasessetlist, i+1, phaseset);
if (!PyList_Check(phaseroots))
- goto release_phases;
+ goto release_phasesetlist;
minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
if (minrevphase == -2) /* Error from add_roots_get_min */
- goto release_phases;
+ goto release_phasesetlist;
minrevallphases = MIN(minrevallphases, minrevphase);
}
/* Propagate the phase information from the roots to the revs */
if (minrevallphases != -1) {
- for (i = minrevallphases; i < self->raw_length; i++) {
- data = index_deref(self, i);
- set_phase_from_parents(phases, getbe32(data+24), getbe32(data+28), i);
- }
- for (i = 0; i < addlen; i++) {
- rev = PyList_GET_ITEM(self->added, i);
- p1 = PyTuple_GET_ITEM(rev, 5);
- p2 = PyTuple_GET_ITEM(rev, 6);
- if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
- PyErr_SetString(PyExc_TypeError, "revlog parents are invalid");
- goto release_phases;
- }
- parent_1 = (int)PyInt_AS_LONG(p1);
- parent_2 = (int)PyInt_AS_LONG(p2);
- set_phase_from_parents(phases, parent_1, parent_2, i+self->raw_length);
+ int parents[2];
+ for (i = minrevallphases; i < len; i++) {
+ index_get_parents(self, i, parents);
+ set_phase_from_parents(phases, parents[0], parents[1], i);
}
}
/* Transform phase list to a python list */
phaseslist = PyList_New(len);
if (phaseslist == NULL)
- goto release_phases;
- for (i = 0; i < len; i++)
- PyList_SET_ITEM(phaseslist, i, PyInt_FromLong(phases[i]));
+ goto release_phasesetlist;
+ for (i = 0; i < len; i++) {
+ phase = phases[i];
+ /* We only store the sets of phase for non public phase, the public phase
+ * is computed as a difference */
+ if (phase != 0) {
+ phaseset = PyList_GET_ITEM(phasessetlist, phase);
+ PySet_Add(phaseset, PyInt_FromLong(i));
+ }
+ PyList_SET_ITEM(phaseslist, i, PyInt_FromLong(phase));
+ }
+ ret = PyList_New(2);
+ if (ret == NULL)
+ goto release_phaseslist;
+ PyList_SET_ITEM(ret, 0, phaseslist);
+ PyList_SET_ITEM(ret, 1, phasessetlist);
+ /* We don't release phaseslist and phasessetlist as we return them to
+ * python */
+ goto release_phases;
+
+release_phaseslist:
+ Py_XDECREF(phaseslist);
+release_phasesetlist:
+ Py_XDECREF(phasessetlist);
release_phases:
free(phases);
release_none:
- return phaseslist;
+ return ret;
}
static PyObject *index_headrevs(indexObject *self, PyObject *args)
{
- Py_ssize_t i, len, addlen;
+ Py_ssize_t i, j, len;
char *nothead = NULL;
PyObject *heads = NULL;
PyObject *filter = NULL;
@@ -1186,9 +1221,9 @@
if (nothead == NULL)
goto bail;
- for (i = 0; i < self->raw_length; i++) {
- const char *data;
- int parent_1, parent_2, isfiltered;
+ for (i = 0; i < len; i++) {
+ int isfiltered;
+ int parents[2];
isfiltered = check_filter(filter, i);
if (isfiltered == -1) {
@@ -1202,49 +1237,11 @@
continue;
}
- data = index_deref(self, i);
- parent_1 = getbe32(data + 24);
- parent_2 = getbe32(data + 28);
-
- if (parent_1 >= 0)
- nothead[parent_1] = 1;
- if (parent_2 >= 0)
- nothead[parent_2] = 1;
- }
-
- addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
-
- for (i = 0; i < addlen; i++) {
- PyObject *rev = PyList_GET_ITEM(self->added, i);
- PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
- PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
- long parent_1, parent_2;
- int isfiltered;
-
- if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
- PyErr_SetString(PyExc_TypeError,
- "revlog parents are invalid");
- goto bail;
+ index_get_parents(self, i, parents);
+ for (j = 0; j < 2; j++) {
+ if (parents[j] >= 0)
+ nothead[parents[j]] = 1;
}
-
- isfiltered = check_filter(filter, i);
- if (isfiltered == -1) {
- PyErr_SetString(PyExc_TypeError,
- "unable to check filter");
- goto bail;
- }
-
- if (isfiltered) {
- nothead[i] = 1;
- continue;
- }
-
- parent_1 = PyInt_AS_LONG(p1);
- parent_2 = PyInt_AS_LONG(p2);
- if (parent_1 >= 0)
- nothead[parent_1] = 1;
- if (parent_2 >= 0)
- nothead[parent_2] = 1;
}
for (i = 0; i < len; i++) {
@@ -1647,20 +1644,6 @@
}
}
-static inline void index_get_parents(indexObject *self, int rev, int *ps)
-{
- if (rev >= self->length - 1) {
- PyObject *tuple = PyList_GET_ITEM(self->added,
- rev - self->length + 1);
- ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
- ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
- } else {
- const char *data = index_deref(self, rev);
- ps[0] = getbe32(data + 24);
- ps[1] = getbe32(data + 28);
- }
-}
-
typedef uint64_t bitmask;
/*
@@ -2271,8 +2254,8 @@
"clear the index caches"},
{"get", (PyCFunction)index_m_get, METH_VARARGS,
"get an index entry"},
- {"computephases", (PyCFunction)compute_phases, METH_VARARGS,
- "compute phases"},
+ {"computephasesmapsets", (PyCFunction)compute_phases_map_sets,
+ METH_VARARGS, "compute phases"},
{"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
"get head revisions"}, /* Can do filtering since 3.2 */
{"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
--- a/mercurial/patch.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/patch.py Mon Jun 15 13:31:22 2015 -0500
@@ -6,6 +6,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+import collections
import cStringIO, email, os, errno, re, posixpath, copy
import tempfile, zlib, shutil
# On python2.4 you have to import these by name or they fail to
@@ -15,7 +16,6 @@
from i18n import _
from node import hex, short
-import cStringIO
import base85, mdiff, scmutil, util, diffhelpers, copies, encoding, error
import pathutil
@@ -830,7 +830,7 @@
self.hunks = []
def binary(self):
- return util.any(h.startswith('index ') for h in self.header)
+ return any(h.startswith('index ') for h in self.header)
def pretty(self, fp):
for h in self.header:
@@ -853,7 +853,7 @@
fp.write(''.join(self.header))
def allhunks(self):
- return util.any(self.allhunks_re.match(h) for h in self.header)
+ return any(self.allhunks_re.match(h) for h in self.header)
def files(self):
match = self.diffgit_re.match(self.header[0])
@@ -872,7 +872,7 @@
return '<header %s>' % (' '.join(map(repr, self.files())))
def isnewfile(self):
- return util.any(self.newfile_re.match(h) for h in self.header)
+ return any(self.newfile_re.match(h) for h in self.header)
def special(self):
# Special files are shown only at the header level and not at the hunk
@@ -885,7 +885,7 @@
nocontent = len(self.header) == 2
emptynewfile = self.isnewfile() and nocontent
return emptynewfile or \
- util.any(self.special_re.match(h) for h in self.header)
+ any(self.special_re.match(h) for h in self.header)
class recordhunk(object):
"""patch hunk
@@ -948,8 +948,10 @@
def __repr__(self):
return '<hunk %r@%d>' % (self.filename(), self.fromline)
-def filterpatch(ui, headers):
+def filterpatch(ui, headers, operation=None):
"""Interactively filter patch chunks into applied-only chunks"""
+ if operation is None:
+ operation = _('record')
def prompt(skipfile, skipall, query, chunk):
"""prompt query, and process base inputs
@@ -1021,9 +1023,11 @@
f.close()
# Start the editor and wait for it to complete
editor = ui.geteditor()
- ui.system("%s \"%s\"" % (editor, patchfn),
- environ={'HGUSER': ui.username()},
- onerr=util.Abort, errprefix=_("edit failed"))
+ ret = ui.system("%s \"%s\"" % (editor, patchfn),
+ environ={'HGUSER': ui.username()})
+ if ret != 0:
+ ui.warn(_("editor exited with exit code %d\n") % ret)
+ continue
# Remove comment lines
patchfp = open(patchfn)
ncpatchfp = cStringIO.StringIO()
@@ -1383,6 +1387,77 @@
return s
return s[:i]
+def reversehunks(hunks):
+ '''reverse the signs in the hunks given as argument
+
+ This function operates on hunks coming out of patch.filterpatch, that is
+ a list of the form: [header1, hunk1, hunk2, header2...]. Example usage:
+
+ >>> rawpatch = """diff --git a/folder1/g b/folder1/g
+ ... --- a/folder1/g
+ ... +++ b/folder1/g
+ ... @@ -1,7 +1,7 @@
+ ... +firstline
+ ... c
+ ... 1
+ ... 2
+ ... + 3
+ ... -4
+ ... 5
+ ... d
+ ... +lastline"""
+ >>> hunks = parsepatch(rawpatch)
+ >>> hunkscomingfromfilterpatch = []
+ >>> for h in hunks:
+ ... hunkscomingfromfilterpatch.append(h)
+ ... hunkscomingfromfilterpatch.extend(h.hunks)
+
+ >>> reversedhunks = reversehunks(hunkscomingfromfilterpatch)
+ >>> fp = cStringIO.StringIO()
+ >>> for c in reversedhunks:
+ ... c.write(fp)
+ >>> fp.seek(0)
+ >>> reversedpatch = fp.read()
+ >>> print reversedpatch
+ diff --git a/folder1/g b/folder1/g
+ --- a/folder1/g
+ +++ b/folder1/g
+ @@ -1,4 +1,3 @@
+ -firstline
+ c
+ 1
+ 2
+ @@ -1,6 +2,6 @@
+ c
+ 1
+ 2
+ - 3
+ +4
+ 5
+ d
+ @@ -5,3 +6,2 @@
+ 5
+ d
+ -lastline
+
+ '''
+
+ import crecord as crecordmod
+ newhunks = []
+ for c in hunks:
+ if isinstance(c, crecordmod.uihunk):
+ # curses hunks encapsulate the record hunk in _hunk
+ c = c._hunk
+ if isinstance(c, recordhunk):
+ for j, line in enumerate(c.hunk):
+ if line.startswith("-"):
+ c.hunk[j] = "+" + c.hunk[j][1:]
+ elif line.startswith("+"):
+ c.hunk[j] = "-" + c.hunk[j][1:]
+ c.added, c.removed = c.removed, c.added
+ newhunks.append(c)
+ return newhunks
+
def parsepatch(originalchunks):
"""patch -> [] of headers -> [] of hunks """
class parser(object):
@@ -2102,7 +2177,7 @@
def lrugetfilectx():
cache = {}
- order = util.deque()
+ order = collections.deque()
def getfilectx(f, ctx):
fctx = ctx.filectx(f, filelog=cache.get(f))
if f not in cache:
--- a/mercurial/pathutil.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/pathutil.py Mon Jun 15 13:31:22 2015 -0500
@@ -1,4 +1,4 @@
-import os, errno, stat
+import os, errno, stat, posixpath
import encoding
import util
@@ -152,7 +152,19 @@
break
name = dirname
- raise util.Abort(_("%s not under root '%s'") % (myname, root))
+ # A common mistake is to use -R, but specify a file relative to the repo
+ # instead of cwd. Detect that case, and provide a hint to the user.
+ hint = None
+ try:
+ if cwd != root:
+ canonpath(root, root, myname, auditor)
+ hint = (_("consider using '--cwd %s'")
+ % os.path.relpath(root, cwd))
+ except util.Abort:
+ pass
+
+ raise util.Abort(_("%s not under root '%s'") % (myname, root),
+ hint=hint)
def normasprefix(path):
'''normalize the specified path as path prefix
@@ -175,3 +187,9 @@
return path + os.sep
else:
return path
+
+# forward two methods from posixpath that do what we need, but we'd
+# rather not let our internals know that we're thinking in posix terms
+# - instead we'll let them be oblivious.
+join = posixpath.join
+dirname = posixpath.dirname
--- a/mercurial/phases.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/phases.py Mon Jun 15 13:31:22 2015 -0500
@@ -155,6 +155,7 @@
# Cheap trick to allow shallow-copy without copy module
self.phaseroots, self.dirty = _readroots(repo, phasedefaults)
self._phaserevs = None
+ self._phasesets = None
self.filterunknown(repo)
self.opener = repo.svfs
@@ -199,7 +200,8 @@
'nativephaseskillswitch'):
self._computephaserevspure(repo)
else:
- self._phaserevs = self._getphaserevsnative(repo)
+ res = self._getphaserevsnative(repo)
+ self._phaserevs, self._phasesets = res
except AttributeError:
self._computephaserevspure(repo)
return self._phaserevs
--- a/mercurial/posix.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/posix.py Mon Jun 15 13:31:22 2015 -0500
@@ -8,6 +8,7 @@
from i18n import _
import encoding
import os, sys, errno, stat, getpass, pwd, grp, socket, tempfile, unicodedata
+import select
import fcntl, re
posixfile = open
@@ -594,6 +595,19 @@
'''check whether a stat result is an executable file'''
return st and (st.st_mode & 0100 != 0)
+def poll(fds):
+ """block until something happens on any file descriptor
+
+ This is a generic helper that will check for any activity
+ (read, write. exception) and return the list of touched files.
+
+ In unsupported cases, it will raise a NotImplementedError"""
+ try:
+ res = select.select(fds, fds, fds)
+ except ValueError: # out of range file descriptor
+ raise NotImplementedError()
+ return sorted(list(set(sum(res, []))))
+
def readpipe(pipe):
"""Read all available data from a pipe."""
# We can't fstat() a pipe because Linux will always report 0.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/progress.py Mon Jun 15 13:31:22 2015 -0500
@@ -0,0 +1,252 @@
+# progress.py progress bars related code
+#
+# Copyright (C) 2010 Augie Fackler <durin42@gmail.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+import sys
+import time
+import threading
+from mercurial import encoding
+
+from mercurial.i18n import _
+
+
+def spacejoin(*args):
+ return ' '.join(s for s in args if s)
+
+def shouldprint(ui):
+ return not ui.plain() and (ui._isatty(sys.stderr) or
+ ui.configbool('progress', 'assume-tty'))
+
+def fmtremaining(seconds):
+ """format a number of remaining seconds in humain readable way
+
+ This will properly display seconds, minutes, hours, days if needed"""
+ if seconds < 60:
+ # i18n: format XX seconds as "XXs"
+ return _("%02ds") % (seconds)
+ minutes = seconds // 60
+ if minutes < 60:
+ seconds -= minutes * 60
+ # i18n: format X minutes and YY seconds as "XmYYs"
+ return _("%dm%02ds") % (minutes, seconds)
+ # we're going to ignore seconds in this case
+ minutes += 1
+ hours = minutes // 60
+ minutes -= hours * 60
+ if hours < 30:
+ # i18n: format X hours and YY minutes as "XhYYm"
+ return _("%dh%02dm") % (hours, minutes)
+ # we're going to ignore minutes in this case
+ hours += 1
+ days = hours // 24
+ hours -= days * 24
+ if days < 15:
+ # i18n: format X days and YY hours as "XdYYh"
+ return _("%dd%02dh") % (days, hours)
+ # we're going to ignore hours in this case
+ days += 1
+ weeks = days // 7
+ days -= weeks * 7
+ if weeks < 55:
+ # i18n: format X weeks and YY days as "XwYYd"
+ return _("%dw%02dd") % (weeks, days)
+ # we're going to ignore days and treat a year as 52 weeks
+ weeks += 1
+ years = weeks // 52
+ weeks -= years * 52
+ # i18n: format X years and YY weeks as "XyYYw"
+ return _("%dy%02dw") % (years, weeks)
+
+class progbar(object):
+ def __init__(self, ui):
+ self.ui = ui
+ self._refreshlock = threading.Lock()
+ self.resetstate()
+
+ def resetstate(self):
+ self.topics = []
+ self.topicstates = {}
+ self.starttimes = {}
+ self.startvals = {}
+ self.printed = False
+ self.lastprint = time.time() + float(self.ui.config(
+ 'progress', 'delay', default=3))
+ self.curtopic = None
+ self.lasttopic = None
+ self.indetcount = 0
+ self.refresh = float(self.ui.config(
+ 'progress', 'refresh', default=0.1))
+ self.changedelay = max(3 * self.refresh,
+ float(self.ui.config(
+ 'progress', 'changedelay', default=1)))
+ self.order = self.ui.configlist(
+ 'progress', 'format',
+ default=['topic', 'bar', 'number', 'estimate'])
+
+ def show(self, now, topic, pos, item, unit, total):
+ if not shouldprint(self.ui):
+ return
+ termwidth = self.width()
+ self.printed = True
+ head = ''
+ needprogress = False
+ tail = ''
+ for indicator in self.order:
+ add = ''
+ if indicator == 'topic':
+ add = topic
+ elif indicator == 'number':
+ if total:
+ add = ('% ' + str(len(str(total))) +
+ 's/%s') % (pos, total)
+ else:
+ add = str(pos)
+ elif indicator.startswith('item') and item:
+ slice = 'end'
+ if '-' in indicator:
+ wid = int(indicator.split('-')[1])
+ elif '+' in indicator:
+ slice = 'beginning'
+ wid = int(indicator.split('+')[1])
+ else:
+ wid = 20
+ if slice == 'end':
+ add = encoding.trim(item, wid, leftside=True)
+ else:
+ add = encoding.trim(item, wid)
+ add += (wid - encoding.colwidth(add)) * ' '
+ elif indicator == 'bar':
+ add = ''
+ needprogress = True
+ elif indicator == 'unit' and unit:
+ add = unit
+ elif indicator == 'estimate':
+ add = self.estimate(topic, pos, total, now)
+ elif indicator == 'speed':
+ add = self.speed(topic, pos, unit, now)
+ if not needprogress:
+ head = spacejoin(head, add)
+ else:
+ tail = spacejoin(tail, add)
+ if needprogress:
+ used = 0
+ if head:
+ used += encoding.colwidth(head) + 1
+ if tail:
+ used += encoding.colwidth(tail) + 1
+ progwidth = termwidth - used - 3
+ if total and pos <= total:
+ amt = pos * progwidth // total
+ bar = '=' * (amt - 1)
+ if amt > 0:
+ bar += '>'
+ bar += ' ' * (progwidth - amt)
+ else:
+ progwidth -= 3
+ self.indetcount += 1
+ # mod the count by twice the width so we can make the
+ # cursor bounce between the right and left sides
+ amt = self.indetcount % (2 * progwidth)
+ amt -= progwidth
+ bar = (' ' * int(progwidth - abs(amt)) + '<=>' +
+ ' ' * int(abs(amt)))
+ prog = ''.join(('[', bar , ']'))
+ out = spacejoin(head, prog, tail)
+ else:
+ out = spacejoin(head, tail)
+ sys.stderr.write('\r' + encoding.trim(out, termwidth))
+ self.lasttopic = topic
+ sys.stderr.flush()
+
+ def clear(self):
+ if not shouldprint(self.ui):
+ return
+ sys.stderr.write('\r%s\r' % (' ' * self.width()))
+
+ def complete(self):
+ if not shouldprint(self.ui):
+ return
+ if self.ui.configbool('progress', 'clear-complete', default=True):
+ self.clear()
+ else:
+ sys.stderr.write('\n')
+ sys.stderr.flush()
+
+ def width(self):
+ tw = self.ui.termwidth()
+ return min(int(self.ui.config('progress', 'width', default=tw)), tw)
+
+ def estimate(self, topic, pos, total, now):
+ if total is None:
+ return ''
+ initialpos = self.startvals[topic]
+ target = total - initialpos
+ delta = pos - initialpos
+ if delta > 0:
+ elapsed = now - self.starttimes[topic]
+ if elapsed > float(
+ self.ui.config('progress', 'estimate', default=2)):
+ seconds = (elapsed * (target - delta)) // delta + 1
+ return fmtremaining(seconds)
+ return ''
+
+ def speed(self, topic, pos, unit, now):
+ initialpos = self.startvals[topic]
+ delta = pos - initialpos
+ elapsed = now - self.starttimes[topic]
+ if elapsed > float(
+ self.ui.config('progress', 'estimate', default=2)):
+ return _('%d %s/sec') % (delta / elapsed, unit)
+ return ''
+
+ def _oktoprint(self, now):
+ '''Check if conditions are met to print - e.g. changedelay elapsed'''
+ if (self.lasttopic is None # first time we printed
+ # not a topic change
+ or self.curtopic == self.lasttopic
+ # it's been long enough we should print anyway
+ or now - self.lastprint >= self.changedelay):
+ return True
+ else:
+ return False
+
+ def progress(self, topic, pos, item='', unit='', total=None):
+ now = time.time()
+ self._refreshlock.acquire()
+ try:
+ if pos is None:
+ self.starttimes.pop(topic, None)
+ self.startvals.pop(topic, None)
+ self.topicstates.pop(topic, None)
+ # reset the progress bar if this is the outermost topic
+ if self.topics and self.topics[0] == topic and self.printed:
+ self.complete()
+ self.resetstate()
+ # truncate the list of topics assuming all topics within
+ # this one are also closed
+ if topic in self.topics:
+ self.topics = self.topics[:self.topics.index(topic)]
+ # reset the last topic to the one we just unwound to,
+ # so that higher-level topics will be stickier than
+ # lower-level topics
+ if self.topics:
+ self.lasttopic = self.topics[-1]
+ else:
+ self.lasttopic = None
+ else:
+ if topic not in self.topics:
+ self.starttimes[topic] = now
+ self.startvals[topic] = pos
+ self.topics.append(topic)
+ self.topicstates[topic] = pos, item, unit, total
+ self.curtopic = topic
+ if now - self.lastprint >= self.refresh and self.topics:
+ if self._oktoprint(now):
+ self.lastprint = now
+ self.show(now, topic, *self.topicstates[topic])
+ finally:
+ self._refreshlock.release()
+
--- a/mercurial/repair.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/repair.py Mon Jun 15 13:31:22 2015 -0500
@@ -7,13 +7,13 @@
# GNU General Public License version 2 or any later version.
from mercurial import changegroup, exchange, util, bundle2
-from mercurial.node import short, hex
+from mercurial.node import short
from mercurial.i18n import _
import errno
def _bundle(repo, bases, heads, node, suffix, compress=True):
"""create a bundle with the specified revisions as a backup"""
- usebundle2 = (repo.ui.config('experimental', 'bundle2-exp') and
+ usebundle2 = (repo.ui.config('experimental', 'bundle2-exp', True) and
repo.ui.config('experimental', 'strip-bundle2-version'))
if usebundle2:
cgversion = repo.ui.config('experimental', 'strip-bundle2-version')
@@ -34,9 +34,7 @@
vfs.mkdir(backupdir)
# Include a hash of all the nodes in the filename for uniqueness
- hexbases = (hex(n) for n in bases)
- hexheads = (hex(n) for n in heads)
- allcommits = repo.set('%ls::%ls', hexbases, hexheads)
+ allcommits = repo.set('%ln::%ln', bases, heads)
allhashes = sorted(c.hex() for c in allcommits)
totalhash = util.sha1(''.join(allhashes)).hexdigest()
name = "%s/%s-%s-%s.hg" % (backupdir, short(node), totalhash[:8], suffix)
@@ -151,6 +149,12 @@
mfst = repo.manifest
+ curtr = repo.currenttransaction()
+ if curtr is not None:
+ del curtr # avoid carrying reference to transaction for nothing
+ msg = _('programming error: cannot strip from inside a transaction')
+ raise util.Abort(msg, hint=_('contact your extension maintainer'))
+
tr = repo.transaction("strip")
offset = len(tr.entries)
--- a/mercurial/repoview.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/repoview.py Mon Jun 15 13:31:22 2015 -0500
@@ -115,16 +115,15 @@
"""
wlock = fh = None
try:
- try:
- wlock = repo.wlock(wait=False)
- # write cache to file
- newhash = cachehash(repo, hideable)
- fh = repo.vfs.open(cachefile, 'w+b', atomictemp=True)
- _writehiddencache(fh, newhash, hidden)
- except (IOError, OSError):
- repo.ui.debug('error writing hidden changesets cache')
- except error.LockHeld:
- repo.ui.debug('cannot obtain lock to write hidden changesets cache')
+ wlock = repo.wlock(wait=False)
+ # write cache to file
+ newhash = cachehash(repo, hideable)
+ fh = repo.vfs.open(cachefile, 'w+b', atomictemp=True)
+ _writehiddencache(fh, newhash, hidden)
+ except (IOError, OSError):
+ repo.ui.debug('error writing hidden changesets cache')
+ except error.LockHeld:
+ repo.ui.debug('cannot obtain lock to write hidden changesets cache')
finally:
if fh:
fh.close()
@@ -197,7 +196,7 @@
Secret and hidden changeset should not pretend to be here."""
assert not repo.changelog.filteredrevs
# fast check to avoid revset call on huge repo
- if util.any(repo._phasecache.phaseroots[1:]):
+ if any(repo._phasecache.phaseroots[1:]):
getphase = repo._phasecache.phase
maymutable = filterrevs(repo, 'base')
return frozenset(r for r in maymutable if getphase(repo, r))
--- a/mercurial/revlog.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/revlog.py Mon Jun 15 13:31:22 2015 -0500
@@ -12,6 +12,7 @@
"""
# import stuff from node for others to import from revlog
+import collections
from node import bin, hex, nullid, nullrev
from i18n import _
import ancestor, mdiff, parsers, error, util, templatefilters
@@ -152,6 +153,10 @@
ngshaoffset = 32
versionformat = ">I"
+# corresponds to uncompressed length of indexformatng (2 gigs, 4-byte
+# signed integer)
+_maxentrysize = 0x7fffffff
+
class revlogio(object):
def __init__(self):
self.size = struct.calcsize(indexformatng)
@@ -485,7 +490,7 @@
# take all ancestors from heads that aren't in has
missing = set()
- visit = util.deque(r for r in heads if r not in has)
+ visit = collections.deque(r for r in heads if r not in has)
while visit:
r = visit.popleft()
if r in missing:
@@ -725,7 +730,7 @@
return self._headrevs()
def computephases(self, roots):
- return self.index.computephases(roots)
+ return self.index.computephasesmapsets(roots)
def _headrevs(self):
count = len(self)
@@ -1179,6 +1184,12 @@
if link == nullrev:
raise RevlogError(_("attempted to add linkrev -1 to %s")
% self.indexfile)
+
+ if len(text) > _maxentrysize:
+ raise RevlogError(
+ _("%s: size of %d bytes exceeds maximum revlog storage of 2GiB")
+ % (self.indexfile, len(text)))
+
node = node or self.hash(text, p1, p2)
if node in self.nodemap:
return node
--- a/mercurial/revset.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/revset.py Mon Jun 15 13:31:22 2015 -0500
@@ -25,23 +25,22 @@
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)
+ inputrev = next(irevs, None)
+ if inputrev is not None:
+ heapq.heappush(h, -inputrev)
seen = set()
while h:
current = -heapq.heappop(h)
+ if current == inputrev:
+ inputrev = next(irevs, None)
+ if inputrev is not None:
+ heapq.heappush(h, -inputrev)
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]:
@@ -59,6 +58,8 @@
def iterate():
cl = repo.changelog
+ # XXX this should be 'parentset.min()' assuming 'parentset' is a
+ # smartset (and if it is not, it should.)
first = min(revs)
nullrev = node.nullrev
if first == nullrev:
@@ -86,25 +87,31 @@
visit = list(heads)
reachable = set()
seen = {}
+ # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
+ # (and if it is not, it should.)
minroot = min(roots)
roots = set(roots)
+ # prefetch all the things! (because python is slow)
+ reached = reachable.add
+ dovisit = visit.append
+ nextvisit = visit.pop
# open-code the post-order traversal due to the tiny size of
# sys.getrecursionlimit()
while visit:
- rev = visit.pop()
+ rev = nextvisit()
if rev in roots:
- reachable.add(rev)
+ reached(rev)
parents = parentrevs(rev)
seen[rev] = parents
for parent in parents:
if parent >= minroot and parent not in seen:
- visit.append(parent)
+ dovisit(parent)
if not reachable:
return baseset()
for rev in sorted(seen):
for parent in seen[rev]:
if parent in reachable:
- reachable.add(rev)
+ reached(rev)
return baseset(sorted(reachable))
elements = {
@@ -335,11 +342,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)
@@ -352,20 +354,26 @@
r = spanset(repo, m, n + 1)
else:
r = spanset(repo, m, n - 1)
+ # XXX We should combine with subset first: 'subset & baseset(...)'. This is
+ # necessary to ensure we preserve the order in subset.
+ #
+ # This has performance implication, carrying the sorting over when possible
+ # would be more efficient.
return r & subset
def dagrange(repo, subset, x, y):
r = fullreposet(repo)
xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
+ # XXX We should combine with subset first: 'subset & baseset(...)'. This is
+ # necessary to ensure we preserve the order in subset.
return xs & subset
def andset(repo, subset, x, y):
return getset(repo, getset(repo, subset, x), y)
-def orset(repo, subset, x, y):
- xl = getset(repo, subset, x)
- yl = getset(repo, subset - xl, y)
- return xl + yl
+def orset(repo, subset, *xs):
+ rs = [getset(repo, subset, x) for x in xs]
+ return _combinesets(rs)
def notset(repo, subset, x):
return subset - getset(repo, subset, x)
@@ -610,17 +618,19 @@
return subset.filter(matches)
def _children(repo, narrow, parentset):
+ if not parentset:
+ return baseset()
cs = set()
- if not parentset:
- return baseset(cs)
pr = repo.changelog.parentrevs
- minrev = min(parentset)
+ minrev = parentset.min()
for r in narrow:
if r <= minrev:
continue
for p in pr(r):
if p in parentset:
cs.add(r)
+ # XXX using a set to feed the baseset is wrong. Sets are not ordered.
+ # This does not break because of other fullreposet misbehavior.
return baseset(cs)
def children(repo, subset, x):
@@ -1099,6 +1109,11 @@
hs = set()
for b, ls in repo.branchmap().iteritems():
hs.update(repo[h].rev() for h in ls)
+ # XXX using a set to feed the baseset is wrong. Sets are not ordered.
+ # This does not break because of other fullreposet misbehavior.
+ # XXX We should not be using '.filter' here, but combines subset with '&'
+ # XXX We should combine with subset first: 'subset & baseset(...)'. This is
+ # necessary to ensure we preserve the order in subset.
return baseset(hs).filter(subset.__contains__)
def heads(repo, subset, x):
@@ -1128,8 +1143,8 @@
def matches(r):
c = repo[r]
- return util.any(kw in encoding.lower(t) for t in c.files() + [c.user(),
- c.description()])
+ return any(kw in encoding.lower(t)
+ for t in c.files() + [c.user(), c.description()])
return subset.filter(matches)
@@ -1152,12 +1167,11 @@
result = []
it = iter(os)
for x in xrange(lim):
- try:
- y = it.next()
- if y in ss:
- result.append(y)
- except (StopIteration):
+ y = next(it, None)
+ if y is None:
break
+ elif y in ss:
+ result.append(y)
return baseset(result)
def last(repo, subset, x):
@@ -1180,12 +1194,11 @@
result = []
it = iter(os)
for x in xrange(lim):
- try:
- y = it.next()
- if y in ss:
- result.append(y)
- except (StopIteration):
+ y = next(it, None)
+ if y is None:
break
+ elif y in ss:
+ result.append(y)
return baseset(result)
def maxrev(repo, subset, x):
@@ -1217,6 +1230,8 @@
cl = repo.changelog
if not subset:
return baseset()
+ # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
+ # (and if it is not, it should.)
baserev = min(subset)
parentscount = [0]*(len(repo) - baserev)
for r in cl.revs(start=baserev + 1):
@@ -1340,6 +1355,8 @@
exclude = getset(repo, fullreposet(repo), args[1])
results = set(cl.findmissingrevs(common=exclude, heads=include))
+ # XXX we should turn this into a baseset instead of a set, smartset may do
+ # some optimisations from the fact this is a baseset.
return subset & results
def origin(repo, subset, x):
@@ -1369,6 +1386,8 @@
o = set([_firstsrc(r) for r in dests])
o -= set([None])
+ # XXX we should turn this into a baseset instead of a set, smartset may do
+ # some optimisations from the fact this is a baseset.
return subset & o
def outgoing(repo, subset, x):
@@ -1411,6 +1430,8 @@
for r in getset(repo, fullreposet(repo), x):
ps.add(cl.parentrevs(r)[0])
ps -= set([node.nullrev])
+ # XXX we should turn this into a baseset instead of a set, smartset may do
+ # some optimisations from the fact this is a baseset.
return subset & ps
def p2(repo, subset, x):
@@ -1432,6 +1453,8 @@
for r in getset(repo, fullreposet(repo), x):
ps.add(cl.parentrevs(r)[1])
ps -= set([node.nullrev])
+ # XXX we should turn this into a baseset instead of a set, smartset may do
+ # some optimisations from the fact this is a baseset.
return subset & ps
def parents(repo, subset, x):
@@ -1487,6 +1510,22 @@
except error.RepoLookupError:
return baseset()
+# for internal use
+def _notpublic(repo, subset, x):
+ getargs(x, 0, 0, "_notpublic takes no arguments")
+ if repo._phasecache._phasesets:
+ s = set()
+ for u in repo._phasecache._phasesets[1:]:
+ s.update(u)
+ # XXX we should turn this into a baseset instead of a set, smartset may
+ # do some optimisations from the fact this is a baseset.
+ return subset & s
+ else:
+ phase = repo._phasecache.phase
+ target = phases.public
+ condition = lambda r: phase(repo, r) != target
+ return subset.filter(condition, cache=False)
+
def public(repo, subset, x):
"""``public()``
Changeset in public phase."""
@@ -1685,7 +1724,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
@@ -1788,7 +1827,7 @@
return s.added or s.modified or s.removed
if s.added:
- return util.any(submatches(c.substate.keys()))
+ return any(submatches(c.substate.keys()))
if s.modified:
subs = set(c.p1().substate.keys())
@@ -1799,7 +1838,7 @@
return True
if s.removed:
- return util.any(submatches(c.p1().substate.keys()))
+ return any(submatches(c.p1().substate.keys()))
return False
@@ -1915,9 +1954,26 @@
s = getstring(x, "internal error")
if not s:
return baseset()
- ls = [repo[r].rev() for r in s.split('\0')]
- s = subset
- return baseset([r for r in ls if r in s])
+ # remove duplicates here. it's difficult for caller to deduplicate sets
+ # because different symbols can point to the same rev.
+ cl = repo.changelog
+ ls = []
+ seen = set()
+ for t in s.split('\0'):
+ try:
+ # fast path for integer revision
+ r = int(t)
+ if str(r) != t or r not in cl:
+ raise ValueError
+ except ValueError:
+ r = repo[t].rev()
+ if r in seen:
+ continue
+ if (r in subset
+ or r == node.nullrev and isinstance(subset, fullreposet)):
+ ls.append(r)
+ seen.add(r)
+ return baseset(ls)
# for internal use
def _intlist(repo, subset, x):
@@ -1993,6 +2049,7 @@
"parents": parents,
"present": present,
"public": public,
+ "_notpublic": _notpublic,
"remote": remote,
"removes": removes,
"rev": rev,
@@ -2067,6 +2124,7 @@
"parents",
"present",
"public",
+ "_notpublic",
"remote",
"removes",
"rev",
@@ -2089,7 +2147,7 @@
"range": rangeset,
"dagrange": dagrange,
"string": stringset,
- "symbol": symbolset,
+ "symbol": stringset,
"and": andset,
"or": orset,
"not": notset,
@@ -2098,7 +2156,6 @@
"ancestor": ancestorspec,
"parent": parentspec,
"parentpost": p1,
- "only": only,
}
def optimize(x, small):
@@ -2153,14 +2210,45 @@
return w, (op, tb, ta)
return w, (op, ta, tb)
elif op == 'or':
- wa, ta = optimize(x[1], False)
- wb, tb = optimize(x[2], False)
- if wb < wa:
- wb, wa = wa, wb
- return max(wa, wb), (op, ta, tb)
+ # fast path for machine-generated expression, that is likely to have
+ # lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()'
+ ws, ts, ss = [], [], []
+ def flushss():
+ if not ss:
+ return
+ if len(ss) == 1:
+ w, t = ss[0]
+ else:
+ s = '\0'.join(t[1] for w, t in ss)
+ y = ('func', ('symbol', '_list'), ('string', s))
+ w, t = optimize(y, False)
+ ws.append(w)
+ ts.append(t)
+ del ss[:]
+ for y in x[1:]:
+ w, t = optimize(y, False)
+ if t[0] == 'string' or t[0] == 'symbol':
+ ss.append((w, t))
+ continue
+ flushss()
+ ws.append(w)
+ ts.append(t)
+ flushss()
+ if len(ts) == 1:
+ return ws[0], ts[0] # 'or' operation is fully optimized out
+ # we can't reorder trees by weight because it would change the order.
+ # ("sort(a + b)" == "sort(b + a)", but "a + b" != "b + a")
+ # ts = tuple(t for w, t in sorted(zip(ws, ts), key=lambda wt: wt[0]))
+ return max(ws), (op,) + tuple(ts)
elif op == 'not':
- o = optimize(x[1], not small)
- return o[0], (op, o[1])
+ # Optimize not public() to _notpublic() because we have a fast version
+ if x[1] == ('func', ('symbol', 'public'), None):
+ newsym = ('func', ('symbol', '_notpublic'), None)
+ o = optimize(newsym, not small)
+ return o[0], o[1]
+ else:
+ o = optimize(x[1], not small)
+ return o[0], (op, o[1])
elif op == 'parentpost':
o = optimize(x[1], small)
return o[0], (op, o[1])
@@ -2369,7 +2457,7 @@
tree, pos = p.parse(defn)
if pos != len(defn):
raise error.ParseError(_('invalid token'), pos)
- return tree
+ return parser.simplifyinfixops(tree, ('or',))
class revsetalias(object):
# whether own `error` information is already shown or not.
@@ -2497,7 +2585,10 @@
def parse(spec, lookup=None):
p = parser.parser(tokenize, elements)
- return p.parse(spec, lookup=lookup)
+ tree, pos = p.parse(spec, lookup=lookup)
+ if pos != len(spec):
+ raise error.ParseError(_("invalid token"), pos)
+ return parser.simplifyinfixops(tree, ('or',))
def posttreebuilthook(tree, repo):
# hook for extensions to execute code on the optimized tree
@@ -2509,9 +2600,7 @@
lookup = None
if repo:
lookup = repo.__contains__
- tree, pos = parse(spec, lookup)
- if (pos != len(spec)):
- raise error.ParseError(_("invalid token"), pos)
+ tree = parse(spec, lookup)
if ui:
tree = findaliases(ui, tree, showwarning=ui.warn)
tree = foldconcat(tree)
@@ -2622,19 +2711,7 @@
return ret
def prettyformat(tree):
- def _prettyformat(tree, level, lines):
- if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
- lines.append((level, str(tree)))
- else:
- lines.append((level, '(%s' % tree[0]))
- for s in tree[1:]:
- _prettyformat(s, level + 1, lines)
- lines[-1:] = [(lines[-1][0], lines[-1][1] + ')')]
-
- lines = []
- _prettyformat(tree, 0, lines)
- output = '\n'.join((' '*l + s) for l, s in lines)
- return output
+ return parser.prettyformat(tree, ('string', 'symbol'))
def depth(tree):
if isinstance(tree, tuple):
@@ -2940,6 +3017,56 @@
def __repr__(self):
return '<%s %r>' % (type(self).__name__, self._subset)
+# this function will be removed, or merged to addset or orset, when
+# - scmutil.revrange() can be rewritten to not combine calculated smartsets
+# - or addset can handle more than two sets without balanced tree
+def _combinesets(subsets):
+ """Create balanced tree of addsets representing union of given sets"""
+ if not subsets:
+ return baseset()
+ if len(subsets) == 1:
+ return subsets[0]
+ p = len(subsets) // 2
+ xs = _combinesets(subsets[:p])
+ ys = _combinesets(subsets[p:])
+ return addset(xs, ys)
+
+def _iterordered(ascending, iter1, iter2):
+ """produce an ordered iteration from two iterators with the same order
+
+ The ascending is used to indicated the iteration direction.
+ """
+ choice = max
+ if ascending:
+ choice = min
+
+ val1 = None
+ val2 = None
+ try:
+ # Consume both iterators in an ordered way until one is empty
+ while True:
+ if val1 is None:
+ val1 = iter1.next()
+ if val2 is None:
+ val2 = iter2.next()
+ next = choice(val1, val2)
+ yield next
+ if val1 == next:
+ val1 = None
+ if val2 == next:
+ val2 = None
+ except StopIteration:
+ # Flush any remaining values and consume the other one
+ it = iter2
+ if val1 is not None:
+ yield val1
+ it = iter1
+ elif val2 is not None:
+ # might have been equality and both are empty
+ yield val2
+ for val in it:
+ yield val
+
class addset(abstractsmartset):
"""Represent the addition of two sets
@@ -2949,6 +3076,64 @@
If the ascending attribute is set, that means the two structures are
ordered in either an ascending or descending way. Therefore, we can add
them maintaining the order by iterating over both at the same time
+
+ >>> xs = baseset([0, 3, 2])
+ >>> ys = baseset([5, 2, 4])
+
+ >>> rs = addset(xs, ys)
+ >>> bool(rs), 0 in rs, 1 in rs, 5 in rs, rs.first(), rs.last()
+ (True, True, False, True, 0, 4)
+ >>> rs = addset(xs, baseset([]))
+ >>> bool(rs), 0 in rs, 1 in rs, rs.first(), rs.last()
+ (True, True, False, 0, 2)
+ >>> rs = addset(baseset([]), baseset([]))
+ >>> bool(rs), 0 in rs, rs.first(), rs.last()
+ (False, False, None, None)
+
+ iterate unsorted:
+ >>> rs = addset(xs, ys)
+ >>> [x for x in rs] # without _genlist
+ [0, 3, 2, 5, 4]
+ >>> assert not rs._genlist
+ >>> len(rs)
+ 5
+ >>> [x for x in rs] # with _genlist
+ [0, 3, 2, 5, 4]
+ >>> assert rs._genlist
+
+ iterate ascending:
+ >>> rs = addset(xs, ys, ascending=True)
+ >>> [x for x in rs], [x for x in rs.fastasc()] # without _asclist
+ ([0, 2, 3, 4, 5], [0, 2, 3, 4, 5])
+ >>> assert not rs._asclist
+ >>> len(rs)
+ 5
+ >>> [x for x in rs], [x for x in rs.fastasc()]
+ ([0, 2, 3, 4, 5], [0, 2, 3, 4, 5])
+ >>> assert rs._asclist
+
+ iterate descending:
+ >>> rs = addset(xs, ys, ascending=False)
+ >>> [x for x in rs], [x for x in rs.fastdesc()] # without _asclist
+ ([5, 4, 3, 2, 0], [5, 4, 3, 2, 0])
+ >>> assert not rs._asclist
+ >>> len(rs)
+ 5
+ >>> [x for x in rs], [x for x in rs.fastdesc()]
+ ([5, 4, 3, 2, 0], [5, 4, 3, 2, 0])
+ >>> assert rs._asclist
+
+ iterate ascending without fastasc:
+ >>> rs = addset(xs, generatorset(ys), ascending=True)
+ >>> assert rs.fastasc is None
+ >>> [x for x in rs]
+ [0, 2, 3, 4, 5]
+
+ iterate descending without fastdesc:
+ >>> rs = addset(generatorset(xs), ys, ascending=False)
+ >>> assert rs.fastdesc is None
+ >>> [x for x in rs]
+ [5, 4, 3, 2, 0]
"""
def __init__(self, revs1, revs2, ascending=None):
self._r1 = revs1
@@ -2967,10 +3152,10 @@
@util.propertycache
def _list(self):
if not self._genlist:
- self._genlist = baseset(self._iterator())
+ self._genlist = baseset(iter(self))
return self._genlist
- def _iterator(self):
+ def __iter__(self):
"""Iterate over both collections without repeating elements
If the ascending attribute is not set, iterate over the first one and
@@ -2981,35 +3166,41 @@
same time, yielding only one value at a time in the given order.
"""
if self._ascending is None:
- def gen():
+ if self._genlist:
+ return iter(self._genlist)
+ def arbitraryordergen():
for r in self._r1:
yield r
inr1 = self._r1.__contains__
for r in self._r2:
if not inr1(r):
yield r
- gen = gen()
- else:
- iter1 = iter(self._r1)
- iter2 = iter(self._r2)
- gen = self._iterordered(self._ascending, iter1, iter2)
- return gen
-
- def __iter__(self):
- if self._ascending is None:
- if self._genlist:
- return iter(self._genlist)
- return iter(self._iterator())
+ return arbitraryordergen()
+ # try to use our own fast iterator if it exists
self._trysetasclist()
if self._ascending:
- it = self.fastasc
+ attr = 'fastasc'
else:
- it = self.fastdesc
- if it is None:
- # consume the gen and try again
- self._list
- return iter(self)
- return it()
+ attr = 'fastdesc'
+ it = getattr(self, attr)
+ if it is not None:
+ return it()
+ # maybe half of the component supports fast
+ # get iterator for _r1
+ iter1 = getattr(self._r1, attr)
+ if iter1 is None:
+ # let's avoid side effect (not sure it matters)
+ iter1 = iter(sorted(self._r1, reverse=not self._ascending))
+ else:
+ iter1 = iter1()
+ # get iterator for _r2
+ iter2 = getattr(self._r2, attr)
+ if iter2 is None:
+ # let's avoid side effect (not sure it matters)
+ iter2 = iter(sorted(self._r2, reverse=not self._ascending))
+ else:
+ iter2 = iter2()
+ return _iterordered(self._ascending, iter1, iter2)
def _trysetasclist(self):
"""populate the _asclist attribute if possible and necessary"""
@@ -3025,7 +3216,7 @@
iter2 = self._r2.fastasc
if None in (iter1, iter2):
return None
- return lambda: self._iterordered(True, iter1(), iter2())
+ return lambda: _iterordered(True, iter1(), iter2())
@property
def fastdesc(self):
@@ -3036,48 +3227,7 @@
iter2 = self._r2.fastdesc
if None in (iter1, iter2):
return None
- return lambda: self._iterordered(False, iter1(), iter2())
-
- def _iterordered(self, ascending, iter1, iter2):
- """produce an ordered iteration from two iterators with the same order
-
- The ascending is used to indicated the iteration direction.
- """
- choice = max
- if ascending:
- choice = min
-
- val1 = None
- val2 = None
-
- choice = max
- if ascending:
- choice = min
- try:
- # Consume both iterators in an ordered way until one is
- # empty
- while True:
- if val1 is None:
- val1 = iter1.next()
- if val2 is None:
- val2 = iter2.next()
- next = choice(val1, val2)
- yield next
- if val1 == next:
- val1 = None
- if val2 == next:
- val2 = None
- except StopIteration:
- # Flush any remaining values and consume the other one
- it = iter2
- if val1 is not None:
- yield val1
- it = iter1
- elif val2 is not None:
- # might have been equality and both are empty
- yield val2
- for val in it:
- yield val
+ return lambda: _iterordered(False, iter1(), iter2())
def __contains__(self, x):
return x in self._r1 or x in self._r2
@@ -3144,7 +3294,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
@@ -3268,9 +3423,7 @@
for x in self._consumegen():
pass
return self.first()
- if self:
- return it().next()
- return None
+ return next(it(), None)
def last(self):
if self._ascending:
@@ -3282,9 +3435,7 @@
for x in self._consumegen():
pass
return self.first()
- if self:
- return it().next()
- return None
+ return next(it(), None)
def __repr__(self):
d = {False: '-', True: '+'}[self._ascending]
@@ -3424,6 +3575,17 @@
# object.
other = baseset(other - self._hiddenrevs)
+ # XXX As fullreposet is also used as bootstrap, this is wrong.
+ #
+ # With a giveme312() revset returning [3,1,2], this makes
+ # 'hg log -r "giveme312()"' -> 1, 2, 3 (wrong)
+ # We cannot just drop it because other usage still need to sort it:
+ # 'hg log -r "all() and giveme312()"' -> 1, 2, 3 (right)
+ #
+ # There is also some faulty revset implementations that rely on it
+ # (eg: children as of its state in e8075329c5fb)
+ #
+ # When we fix the two points above we can move this into the if clause
other.sort(reverse=self.isdescending())
return other
--- a/mercurial/scmutil.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/scmutil.py Mon Jun 15 13:31:22 2015 -0500
@@ -80,9 +80,24 @@
# has been modified (in ctx2) but not yet committed (in ctx1).
subpaths = dict.fromkeys(ctx2.substate, ctx2)
subpaths.update(dict.fromkeys(ctx1.substate, ctx1))
+
+ missing = set()
+
+ for subpath in ctx2.substate:
+ if subpath not in ctx1.substate:
+ del subpaths[subpath]
+ missing.add(subpath)
+
for subpath, ctx in sorted(subpaths.iteritems()):
yield subpath, ctx.sub(subpath)
+ # Yield an empty subrepo based on ctx1 for anything only in ctx2. That way,
+ # status and diff will have an accurate result when it does
+ # 'sub.{status|diff}(rev2)'. Otherwise, the ctx2 subrepo is compared
+ # against itself.
+ for subpath in missing:
+ yield subpath, ctx2.nullsub(subpath, ctx1)
+
def nochangesfound(ui, repo, excluded=None):
'''Report no changes for push/pull, excluded is None or a list of
nodes excluded from the push/pull.
@@ -709,14 +724,12 @@
return defval
return repo[val].rev()
- seen, l = set(), revset.baseset([])
+ subsets = []
revsetaliases = [alias for (alias, _) in
repo.ui.configitems("revsetalias")]
for spec in revs:
- if l and not seen:
- seen = set(l)
# attempt to parse old-style ranges first to deal with
# things like old-tag which contain query metacharacters
try:
@@ -727,8 +740,7 @@
raise error.RepoLookupError
if isinstance(spec, int):
- seen.add(spec)
- l = l + revset.baseset([spec])
+ subsets.append(revset.baseset([spec]))
continue
if _revrangesep in spec:
@@ -740,40 +752,24 @@
end = revfix(repo, end, len(repo) - 1)
if end == nullrev and start < 0:
start = nullrev
- rangeiter = repo.changelog.revs(start, end)
- if not seen and not l:
- # by far the most common case: revs = ["-1:0"]
- l = revset.baseset(rangeiter)
- # defer syncing seen until next iteration
- continue
- newrevs = set(rangeiter)
- if seen:
- newrevs.difference_update(seen)
- seen.update(newrevs)
+ if start < end:
+ l = revset.spanset(repo, start, end + 1)
else:
- seen = newrevs
- l = l + revset.baseset(sorted(newrevs, reverse=start > end))
+ l = revset.spanset(repo, start, end - 1)
+ subsets.append(l)
continue
elif spec and spec in repo: # single unquoted rev
rev = revfix(repo, spec, None)
- if rev in seen:
- continue
- seen.add(rev)
- l = l + revset.baseset([rev])
+ subsets.append(revset.baseset([rev]))
continue
except error.RepoLookupError:
pass
# fall through to new-style queries if old-style fails
m = revset.match(repo.ui, spec, repo)
- if seen or l:
- dl = [r for r in m(repo) if r not in seen]
- l = l + revset.baseset(dl)
- seen.update(dl)
- else:
- l = m(repo)
+ subsets.append(m(repo))
- return l
+ return revset._combinesets(subsets)
def expandpats(pats):
'''Expand bare globs when running on windows.
@@ -794,34 +790,40 @@
ret.append(kindpat)
return ret
-def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath'):
+def matchandpats(ctx, pats=[], opts={}, globbed=False, default='relpath',
+ badfn=None):
'''Return a matcher and the patterns that were used.
- The matcher will warn about bad matches.'''
+ The matcher will warn about bad matches, unless an alternate badfn callback
+ is provided.'''
if pats == ("",):
pats = []
if not globbed and default == 'relpath':
pats = expandpats(pats or [])
+ def bad(f, msg):
+ ctx.repo().ui.warn("%s: %s\n" % (m.rel(f), msg))
+
+ if badfn is None:
+ badfn = bad
+
m = ctx.match(pats, opts.get('include'), opts.get('exclude'),
- default)
- def badfn(f, msg):
- ctx.repo().ui.warn("%s: %s\n" % (m.rel(f), msg))
- m.bad = badfn
+ default, listsubrepos=opts.get('subrepos'), badfn=badfn)
+
if m.always():
pats = []
return m, pats
-def match(ctx, pats=[], opts={}, globbed=False, default='relpath'):
+def match(ctx, pats=[], opts={}, globbed=False, default='relpath', badfn=None):
'''Return a matcher that will warn about bad matches.'''
- return matchandpats(ctx, pats, opts, globbed, default)[0]
+ return matchandpats(ctx, pats, opts, globbed, default, badfn=badfn)[0]
def matchall(repo):
'''Return a matcher that will efficiently match everything.'''
return matchmod.always(repo.root, repo.getcwd())
-def matchfiles(repo, files):
+def matchfiles(repo, files, badfn=None):
'''Return a matcher that will efficiently match exactly these files.'''
- return matchmod.exact(repo.root, repo.getcwd(), files)
+ return matchmod.exact(repo.root, repo.getcwd(), files, badfn=badfn)
def addremove(repo, matcher, prefix, opts={}, dry_run=None, similarity=None):
m = matcher
@@ -854,15 +856,14 @@
% join(subpath))
rejected = []
- origbad = m.bad
def badfn(f, msg):
if f in m.files():
- origbad(f, msg)
+ m.bad(f, msg)
rejected.append(f)
- m.bad = badfn
- added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
- m.bad = origbad
+ badmatch = matchmod.badmatch(m, badfn)
+ added, unknown, deleted, removed, forgotten = _interestingfiles(repo,
+ badmatch)
unknownset = set(unknown + forgotten)
toprint = unknownset.copy()
@@ -889,9 +890,8 @@
def marktouched(repo, files, similarity=0.0):
'''Assert that files have somehow been operated upon. files are relative to
the repo root.'''
- m = matchfiles(repo, files)
+ m = matchfiles(repo, files, badfn=lambda x, y: rejected.append(x))
rejected = []
- m.bad = lambda x, y: rejected.append(x)
added, unknown, deleted, removed, forgotten = _interestingfiles(repo, m)
@@ -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/setdiscovery.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/setdiscovery.py Mon Jun 15 13:31:22 2015 -0500
@@ -40,6 +40,7 @@
classified with it (since all ancestors or descendants will be marked as well).
"""
+import collections
from node import nullid, nullrev
from i18n import _
import random
@@ -65,7 +66,7 @@
else:
heads = dag.heads()
dist = {}
- visit = util.deque(heads)
+ visit = collections.deque(heads)
seen = set()
factor = 1
while visit:
@@ -168,7 +169,7 @@
ui.debug("all remote heads known locally\n")
return (srvheadhashes, False, srvheadhashes,)
- if sample and len(ownheads) <= initialsamplesize and util.all(yesno):
+ if sample and len(ownheads) <= initialsamplesize and all(yesno):
ui.note(_("all local heads known remotely\n"))
ownheadhashes = dag.externalizeall(ownheads)
return (ownheadhashes, True, srvheadhashes,)
--- a/mercurial/sshpeer.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/sshpeer.py Mon Jun 15 13:31:22 2015 -0500
@@ -27,6 +27,87 @@
return s
return "'%s'" % s.replace("'", "'\\''")
+def _forwardoutput(ui, pipe):
+ """display all data currently available on pipe as remote output.
+
+ This is non blocking."""
+ s = util.readpipe(pipe)
+ if s:
+ for l in s.splitlines():
+ ui.status(_("remote: "), l, '\n')
+
+class doublepipe(object):
+ """Operate a side-channel pipe in addition of a main one
+
+ The side-channel pipe contains server output to be forwarded to the user
+ input. The double pipe will behave as the "main" pipe, but will ensure the
+ content of the "side" pipe is properly processed while we wait for blocking
+ call on the "main" pipe.
+
+ If large amounts of data are read from "main", the forward will cease after
+ the first bytes start to appear. This simplifies the implementation
+ without affecting actual output of sshpeer too much as we rarely issue
+ large read for data not yet emitted by the server.
+
+ The main pipe is expected to be a 'bufferedinputpipe' from the util module
+ that handle all the os specific bites. This class lives in this module
+ because it focus on behavior specifig to the ssh protocol."""
+
+ def __init__(self, ui, main, side):
+ self._ui = ui
+ self._main = main
+ self._side = side
+
+ def _wait(self):
+ """wait until some data are available on main or side
+
+ return a pair of boolean (ismainready, issideready)
+
+ (This will only wait for data if the setup is supported by `util.poll`)
+ """
+ if getattr(self._main, 'hasbuffer', False): # getattr for classic pipe
+ return (True, True) # main has data, assume side is worth poking at.
+ fds = [self._main.fileno(), self._side.fileno()]
+ try:
+ act = util.poll(fds)
+ except NotImplementedError:
+ # non supported yet case, assume all have data.
+ act = fds
+ return (self._main.fileno() in act, self._side.fileno() in act)
+
+ def write(self, data):
+ return self._call('write', data)
+
+ def read(self, size):
+ return self._call('read', size)
+
+ def readline(self):
+ return self._call('readline')
+
+ def _call(self, methname, data=None):
+ """call <methname> on "main", forward output of "side" while blocking
+ """
+ # data can be '' or 0
+ if (data is not None and not data) or self._main.closed:
+ _forwardoutput(self._ui, self._side)
+ return ''
+ while True:
+ mainready, sideready = self._wait()
+ if sideready:
+ _forwardoutput(self._ui, self._side)
+ if mainready:
+ meth = getattr(self._main, methname)
+ if data is None:
+ return meth()
+ else:
+ return meth(data)
+
+ def close(self):
+ return self._main.close()
+
+ def flush(self):
+ return self._main.flush()
+
class sshpeer(wireproto.wirepeer):
def __init__(self, ui, path, create=False):
self._url = path
@@ -78,7 +159,16 @@
# while self.subprocess isn't used, having it allows the subprocess to
# to clean up correctly later
- self.pipeo, self.pipei, self.pipee, self.subprocess = util.popen4(cmd)
+ #
+ # no buffer allow the use of 'select'
+ # feel free to remove buffering and select usage when we ultimately
+ # move to threading.
+ sub = util.popen4(cmd, bufsize=0)
+ self.pipeo, self.pipei, self.pipee, self.subprocess = sub
+
+ self.pipei = util.bufferedinputpipe(self.pipei)
+ self.pipei = doublepipe(self.ui, self.pipei, self.pipee)
+ self.pipeo = doublepipe(self.ui, self.pipeo, self.pipee)
# skip any noise generated by remote shell
self._callstream("hello")
@@ -108,10 +198,7 @@
return self._caps
def readerr(self):
- s = util.readpipe(self.pipee)
- if s:
- for l in s.splitlines():
- self.ui.status(_("remote: "), l, '\n')
+ _forwardoutput(self.ui, self.pipee)
def _abort(self, exception):
self.cleanup()
@@ -195,16 +282,9 @@
def _recv(self):
l = self.pipei.readline()
if l == '\n':
- err = []
- while True:
- line = self.pipee.readline()
- if line == '-\n':
- break
- err.extend([line])
- if len(err) > 0:
- # strip the trailing newline added to the last line server-side
- err[-1] = err[-1][:-1]
- self._abort(error.OutOfBandError(*err))
+ self.readerr()
+ msg = _('check previous remote output')
+ self._abort(error.OutOfBandError(hint=msg))
self.readerr()
try:
l = int(l)
--- a/mercurial/sslutil.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/sslutil.py Mon Jun 15 13:31:22 2015 -0500
@@ -6,77 +6,59 @@
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import os, sys
+import os, sys, ssl
from mercurial import util
from mercurial.i18n import _
_canloaddefaultcerts = False
try:
- # avoid using deprecated/broken FakeSocket in python 2.6
- import ssl
- CERT_REQUIRED = ssl.CERT_REQUIRED
- try:
- ssl_context = ssl.SSLContext
- _canloaddefaultcerts = util.safehasattr(ssl_context,
- 'load_default_certs')
-
- def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=ssl.CERT_NONE,
- ca_certs=None, serverhostname=None):
- # Allow any version of SSL starting with TLSv1 and
- # up. Note that specifying TLSv1 here prohibits use of
- # newer standards (like TLSv1_2), so this is the right way
- # to do this. Note that in the future it'd be better to
- # support using ssl.create_default_context(), which sets
- # up a bunch of things in smart ways (strong ciphers,
- # protocol versions, etc) and is upgraded by Python
- # maintainers for us, but that breaks too many things to
- # do it in a hurry.
- sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- sslcontext.options &= ssl.OP_NO_SSLv2 & ssl.OP_NO_SSLv3
- if certfile is not None:
- sslcontext.load_cert_chain(certfile, keyfile)
- sslcontext.verify_mode = cert_reqs
- if ca_certs is not None:
- sslcontext.load_verify_locations(cafile=ca_certs)
- elif _canloaddefaultcerts:
- sslcontext.load_default_certs()
+ ssl_context = ssl.SSLContext
+ _canloaddefaultcerts = util.safehasattr(ssl_context, 'load_default_certs')
- sslsocket = sslcontext.wrap_socket(sock,
- server_hostname=serverhostname)
- # check if wrap_socket failed silently because socket had been
- # closed
- # - see http://bugs.python.org/issue13721
- if not sslsocket.cipher():
- raise util.Abort(_('ssl connection failed'))
- return sslsocket
- except AttributeError:
- def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=ssl.CERT_NONE,
- ca_certs=None, serverhostname=None):
- sslsocket = ssl.wrap_socket(sock, keyfile, certfile,
- cert_reqs=cert_reqs, ca_certs=ca_certs,
- ssl_version=ssl.PROTOCOL_TLSv1)
- # check if wrap_socket failed silently because socket had been
- # closed
- # - see http://bugs.python.org/issue13721
- if not sslsocket.cipher():
- raise util.Abort(_('ssl connection failed'))
- return sslsocket
-except ImportError:
- CERT_REQUIRED = 2
+ def wrapsocket(sock, keyfile, certfile, ui, cert_reqs=ssl.CERT_NONE,
+ ca_certs=None, serverhostname=None):
+ # Allow any version of SSL starting with TLSv1 and
+ # up. Note that specifying TLSv1 here prohibits use of
+ # newer standards (like TLSv1_2), so this is the right way
+ # to do this. Note that in the future it'd be better to
+ # support using ssl.create_default_context(), which sets
+ # up a bunch of things in smart ways (strong ciphers,
+ # protocol versions, etc) and is upgraded by Python
+ # maintainers for us, but that breaks too many things to
+ # do it in a hurry.
+ sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
+ sslcontext.options &= ssl.OP_NO_SSLv2 & ssl.OP_NO_SSLv3
+ if certfile is not None:
+ def password():
+ f = keyfile or certfile
+ return ui.getpass(_('passphrase for %s: ') % f, '')
+ sslcontext.load_cert_chain(certfile, keyfile, password)
+ sslcontext.verify_mode = cert_reqs
+ if ca_certs is not None:
+ sslcontext.load_verify_locations(cafile=ca_certs)
+ elif _canloaddefaultcerts:
+ sslcontext.load_default_certs()
- import socket, httplib
-
- def ssl_wrap_socket(sock, keyfile, certfile, cert_reqs=CERT_REQUIRED,
- ca_certs=None, serverhostname=None):
- if not util.safehasattr(socket, 'ssl'):
- raise util.Abort(_('Python SSL support not found'))
- if ca_certs:
- raise util.Abort(_(
- 'certificate checking requires Python 2.6'))
-
- ssl = socket.ssl(sock, keyfile, certfile)
- return httplib.FakeSocket(sock, ssl)
+ sslsocket = sslcontext.wrap_socket(sock, server_hostname=serverhostname)
+ # check if wrap_socket failed silently because socket had been
+ # closed
+ # - see http://bugs.python.org/issue13721
+ if not sslsocket.cipher():
+ raise util.Abort(_('ssl connection failed'))
+ return sslsocket
+except AttributeError:
+ def wrapsocket(sock, keyfile, certfile, ui, cert_reqs=ssl.CERT_NONE,
+ ca_certs=None, serverhostname=None):
+ sslsocket = ssl.wrap_socket(sock, keyfile, certfile,
+ cert_reqs=cert_reqs, ca_certs=ca_certs,
+ ssl_version=ssl.PROTOCOL_TLSv1)
+ # check if wrap_socket failed silently because socket had been
+ # closed
+ # - see http://bugs.python.org/issue13721
+ if not sslsocket.cipher():
+ raise util.Abort(_('ssl connection failed'))
+ return sslsocket
def _verifycert(cert, hostname):
'''Verify that cert (in socket.getpeercert() format) matches hostname.
@@ -117,9 +99,6 @@
# CERT_REQUIRED means fetch the cert from the server all the time AND
# validate it against the CA store provided in web.cacerts.
-#
-# We COMPLETELY ignore CERT_REQUIRED on Python <= 2.5, as it's totally
-# busted on those versions.
def _plainapplepython():
"""return true if this seems to be a pure Apple Python that
@@ -146,7 +125,7 @@
return '!'
def sslkwargs(ui, host):
- kws = {}
+ kws = {'ui': ui}
hostfingerprint = ui.config('hostfingerprints', host)
if hostfingerprint:
return kws
@@ -164,7 +143,7 @@
ui.setconfig('web', 'cacerts', cacerts, 'defaultcacerts')
if cacerts != '!':
kws.update({'ca_certs': cacerts,
- 'cert_reqs': CERT_REQUIRED,
+ 'cert_reqs': ssl.CERT_REQUIRED,
})
return kws
@@ -177,17 +156,6 @@
host = self.host
cacerts = self.ui.config('web', 'cacerts')
hostfingerprint = self.ui.config('hostfingerprints', host)
- if not getattr(sock, 'getpeercert', False): # python 2.5 ?
- if hostfingerprint:
- raise util.Abort(_("host fingerprint for %s can't be "
- "verified (Python too old)") % host)
- if strict:
- raise util.Abort(_("certificate for %s can't be verified "
- "(Python too old)") % host)
- if self.ui.configbool('ui', 'reportoldssl', True):
- self.ui.warn(_("warning: certificate for %s can't be verified "
- "(Python too old)\n") % host)
- return
if not sock.cipher(): # work around http://bugs.python.org/issue13721
raise util.Abort(_('%s ssl connection error') % host)
--- a/mercurial/statichttprepo.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/statichttprepo.py Mon Jun 15 13:31:22 2015 -0500
@@ -32,11 +32,7 @@
try:
f = self.opener.open(req)
data = f.read()
- # Python 2.6+ defines a getcode() function, and 2.4 and
- # 2.5 appear to always have an undocumented code attribute
- # set. If we can't read either of those, fall back to 206
- # and hope for the best.
- code = getattr(f, 'getcode', lambda : getattr(f, 'code', 206))()
+ code = f.code
except urllib2.HTTPError, inst:
num = inst.code == 404 and errno.ENOENT or None
raise IOError(num, inst)
--- a/mercurial/store.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/store.py Mon Jun 15 13:31:22 2015 -0500
@@ -187,7 +187,7 @@
def _hashencode(path, dotencode):
digest = _sha(path).hexdigest()
- le = lowerencode(path).split('/')[1:]
+ le = lowerencode(path[5:]).split('/') # skips prefix 'data/' or 'meta/'
parts = _auxencode(le, dotencode)
basename = parts[-1]
_root, ext = os.path.splitext(basename)
--- a/mercurial/subrepo.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/subrepo.py Mon Jun 15 13:31:22 2015 -0500
@@ -340,6 +340,25 @@
raise util.Abort(_('unknown subrepo type %s') % state[2])
return types[state[2]](ctx, path, state[:2])
+def nullsubrepo(ctx, path, pctx):
+ """return an empty subrepo in pctx for the extant subrepo in ctx"""
+ # subrepo inherently violates our import layering rules
+ # because it wants to make repo objects from deep inside the stack
+ # so we manually delay the circular imports to not break
+ # scripts that don't use our demand-loading
+ global hg
+ import hg as h
+ hg = h
+
+ pathutil.pathauditor(ctx.repo().root)(path)
+ state = ctx.substate[path]
+ if state[2] not in types:
+ raise util.Abort(_('unknown subrepo type %s') % state[2])
+ subrev = ''
+ if state[2] == 'hg':
+ subrev = "0" * 40
+ return types[state[2]](pctx, path, (state[0], subrev))
+
def newcommitphase(ui, ctx):
commitphase = phases.newcommitphase(ui)
substate = getattr(ctx, "substate", None)
@@ -500,7 +519,11 @@
"""return file flags"""
return ''
- def printfiles(self, ui, m, fm, fmt):
+ def getfileset(self, expr):
+ """Resolve the fileset expression for this repo"""
+ return set()
+
+ def printfiles(self, ui, m, fm, fmt, subrepos):
"""handle the files command for this subrepo"""
return 1
@@ -592,21 +615,14 @@
def _storeclean(self, path):
clean = True
itercache = self._calcstorehash(path)
- try:
- for filehash in self._readstorehashcache(path):
- if filehash != itercache.next():
- clean = False
- break
- except StopIteration:
+ for filehash in self._readstorehashcache(path):
+ if filehash != next(itercache, None):
+ clean = False
+ break
+ if clean:
+ # if not empty:
# the cached and current pull states have a different size
- clean = False
- if clean:
- try:
- itercache.next()
- # the cached and current pull states have a different size
- clean = False
- except StopIteration:
- pass
+ clean = next(itercache, None) is None
return clean
def _calcstorehash(self, remotepath):
@@ -646,6 +662,15 @@
finally:
lock.release()
+ def _getctx(self):
+ '''fetch the context for this subrepo revision, possibly a workingctx
+ '''
+ if self._ctx.rev() is None:
+ return self._repo[None] # workingctx if parent is workingctx
+ else:
+ rev = self._state[1]
+ return self._repo[rev]
+
@annotatesubrepoerror
def _initrepo(self, parentrepo, source, create):
self._repo._subparent = parentrepo
@@ -907,7 +932,7 @@
return ctx.flags(name)
@annotatesubrepoerror
- def printfiles(self, ui, m, fm, fmt):
+ def printfiles(self, ui, m, fm, fmt, subrepos):
# If the parent context is a workingctx, use the workingctx here for
# consistency.
if self._ctx.rev() is None:
@@ -915,7 +940,27 @@
else:
rev = self._state[1]
ctx = self._repo[rev]
- return cmdutil.files(ui, ctx, m, fm, fmt, True)
+ return cmdutil.files(ui, ctx, m, fm, fmt, subrepos)
+
+ @annotatesubrepoerror
+ def getfileset(self, expr):
+ if self._ctx.rev() is None:
+ ctx = self._repo[None]
+ else:
+ rev = self._state[1]
+ ctx = self._repo[rev]
+
+ files = ctx.getfileset(expr)
+
+ for subpath in ctx.substate:
+ sub = ctx.sub(subpath)
+
+ try:
+ files.extend(subpath + '/' + f for f in sub.getfileset(expr))
+ except error.LookupError:
+ self.ui.status(_("skipping missing subrepository: %s\n")
+ % self.wvfs.reljoin(reporelpath(self), subpath))
+ return files
def walk(self, match):
ctx = self._repo[None]
@@ -1711,7 +1756,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/tags.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/tags.py Mon Jun 15 13:31:22 2015 -0500
@@ -442,11 +442,13 @@
self._raw.pop()
self._dirtyoffset = len(self._raw)
- def getfnode(self, node):
+ def getfnode(self, node, computemissing=True):
"""Obtain the filenode of the .hgtags file at a specified revision.
If the value is in the cache, the entry will be validated and returned.
- Otherwise, the filenode will be computed and returned.
+ Otherwise, the filenode will be computed and returned unless
+ "computemissing" is False, in which case None will be returned without
+ any potentially expensive computation being performed.
If an .hgtags does not exist at the specified revision, nullid is
returned.
@@ -470,21 +472,39 @@
# Fall through.
- # If we get here, the entry is either missing or invalid. Populate it.
+ # If we get here, the entry is either missing or invalid.
+
+ if not computemissing:
+ return None
+
+ # Populate missing entry.
try:
fnode = ctx.filenode('.hgtags')
except error.LookupError:
# No .hgtags file on this revision.
fnode = nullid
+ self._writeentry(offset, properprefix, fnode)
+ return fnode
+
+ def setfnode(self, node, fnode):
+ """Set the .hgtags filenode for a given changeset."""
+ assert len(fnode) == 20
+ ctx = self._repo[node]
+
+ # Do a lookup first to avoid writing if nothing has changed.
+ if self.getfnode(ctx.node(), computemissing=False) == fnode:
+ return
+
+ self._writeentry(ctx.rev() * _fnodesrecsize, node[0:4], fnode)
+
+ def _writeentry(self, offset, prefix, fnode):
# Slices on array instances only accept other array.
- entry = array('c', properprefix + fnode)
+ entry = array('c', prefix + fnode)
self._raw[offset:offset + _fnodesrecsize] = entry
# self._dirtyoffset could be None.
self._dirtyoffset = min(self._dirtyoffset, offset) or 0
- return fnode
-
def write(self):
"""Perform all necessary writes to cache file.
@@ -509,26 +529,25 @@
return
try:
+ f = repo.vfs.open(_fnodescachefile, 'ab')
try:
- f = repo.vfs.open(_fnodescachefile, 'ab')
- try:
- # if the file has been truncated
- actualoffset = f.tell()
- if actualoffset < self._dirtyoffset:
- self._dirtyoffset = actualoffset
- data = self._raw[self._dirtyoffset:]
- f.seek(self._dirtyoffset)
- f.truncate()
- repo.ui.log('tagscache',
- 'writing %d bytes to %s\n' % (
- len(data), _fnodescachefile))
- f.write(data)
- self._dirtyoffset = None
- finally:
- f.close()
- except (IOError, OSError), inst:
+ # if the file has been truncated
+ actualoffset = f.tell()
+ if actualoffset < self._dirtyoffset:
+ self._dirtyoffset = actualoffset
+ data = self._raw[self._dirtyoffset:]
+ f.seek(self._dirtyoffset)
+ f.truncate()
repo.ui.log('tagscache',
- "couldn't write %s: %s\n" % (
- _fnodescachefile, inst))
+ 'writing %d bytes to %s\n' % (
+ len(data), _fnodescachefile))
+ f.write(data)
+ self._dirtyoffset = None
+ finally:
+ f.close()
+ except (IOError, OSError), inst:
+ repo.ui.log('tagscache',
+ "couldn't write %s: %s\n" % (
+ _fnodescachefile, inst))
finally:
lock.release()
--- a/mercurial/templatefilters.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templatefilters.py Mon Jun 15 13:31:22 2015 -0500
@@ -326,6 +326,8 @@
"""
if util.safehasattr(thing, '__iter__') and not isinstance(thing, str):
return "".join([stringify(t) for t in thing if t is not None])
+ if thing is None:
+ return ""
return str(thing)
def strip(text):
--- a/mercurial/templatekw.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templatekw.py Mon Jun 15 13:31:22 2015 -0500
@@ -206,12 +206,12 @@
def showbookmarks(**args):
""":bookmarks: List of strings. Any bookmarks associated with the
- changeset.
+ changeset. Also sets 'active', the name of the active bookmark.
"""
repo = args['ctx']._repo
bookmarks = args['ctx'].bookmarks()
- current = repo._bookmarkcurrent
- makemap = lambda v: {'bookmark': v, 'current': current}
+ active = repo._activebookmark
+ makemap = lambda v: {'bookmark': v, 'active': active, 'current': active}
f = _showlist('bookmark', bookmarks, **args)
return _hybrid(f, bookmarks, makemap, lambda x: x['bookmark'])
@@ -221,15 +221,18 @@
childrevs = ['%d:%s' % (cctx, cctx) for cctx in ctx.children()]
return showlist('children', childrevs, element='child', **args)
+# Deprecated, but kept alive for help generation a purpose.
def showcurrentbookmark(**args):
""":currentbookmark: String. The active bookmark, if it is
+ associated with the changeset (DEPRECATED)"""
+ return showactivebookmark(**args)
+
+def showactivebookmark(**args):
+ """:activetbookmark: String. The active bookmark, if it is
associated with the changeset"""
- import bookmarks as bookmarks # to avoid circular import issues
- repo = args['repo']
- if bookmarks.iscurrent(repo):
- current = repo._bookmarkcurrent
- if current in args['ctx'].bookmarks():
- return current
+ active = args['repo']._activebookmark
+ if active and active in args['ctx'].bookmarks():
+ return active
return ''
def showdate(repo, ctx, templ, **args):
@@ -418,12 +421,14 @@
# cache - a cache dictionary for the whole templater run
# revcache - a cache dictionary for the current revision
keywords = {
+ 'activebookmark': showactivebookmark,
'author': showauthor,
'bisect': showbisect,
'branch': showbranch,
'branches': showbranches,
'bookmarks': showbookmarks,
'children': showchildren,
+ # currentbookmark is deprecated
'currentbookmark': showcurrentbookmark,
'date': showdate,
'desc': showdescription,
--- a/mercurial/templater.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templater.py Mon Jun 15 13:31:22 2015 -0500
@@ -20,6 +20,7 @@
"|": (5, None, ("|", 5)),
"%": (6, None, ("%", 6)),
")": (0, None, None),
+ "integer": (0, ("integer",), None),
"symbol": (0, ("symbol",), None),
"string": (0, ("string",), None),
"rawstring": (0, ("rawstring",), None),
@@ -59,6 +60,20 @@
pos += 1
else:
raise error.ParseError(_("unterminated string"), s)
+ elif c.isdigit() or c == '-':
+ s = pos
+ if c == '-': # simply take negate operator as part of integer
+ pos += 1
+ if pos >= end or not program[pos].isdigit():
+ raise error.ParseError(_("integer literal without digits"), s)
+ pos += 1
+ while pos < end:
+ d = program[pos]
+ if not d.isdigit():
+ break
+ pos += 1
+ yield ('integer', program[s:pos], s)
+ pos -= 1
elif c.isalnum() or c in '_':
s = pos
pos += 1
@@ -100,12 +115,12 @@
parseres, pos = p.parse(pd)
parsed.append(parseres)
- return [compileexp(e, context) for e in parsed]
+ return [compileexp(e, context, methods) for e in parsed]
-def compileexp(exp, context):
+def compileexp(exp, context, curmethods):
t = exp[0]
- if t in methods:
- return methods[t](exp, context)
+ if t in curmethods:
+ return curmethods[t](exp, context)
raise error.ParseError(_("unknown method '%s'") % t)
# template evaluation
@@ -135,6 +150,9 @@
return context._load(exp[1])
raise error.ParseError(_("expected template specifier"))
+def runinteger(context, mapping, data):
+ return int(data)
+
def runstring(context, mapping, data):
return data.decode("string-escape")
@@ -157,7 +175,7 @@
return v
def buildfilter(exp, context):
- func, data = compileexp(exp[1], context)
+ func, data = compileexp(exp[1], context, methods)
filt = getfilter(exp[2], context)
return (runfilter, (func, data, filt))
@@ -179,7 +197,7 @@
"keyword '%s'") % (filt.func_name, dt))
def buildmap(exp, context):
- func, data = compileexp(exp[1], context)
+ func, data = compileexp(exp[1], context, methods)
ctmpl = gettemplate(exp[2], context)
return (runmap, (func, data, ctmpl))
@@ -208,7 +226,7 @@
def buildfunc(exp, context):
n = getsymbol(exp[1])
- args = [compileexp(x, context) for x in getlist(exp[2])]
+ args = [compileexp(x, context, exprmethods) for x in getlist(exp[2])]
if n in funcs:
f = funcs[n]
return (f, args)
@@ -292,10 +310,7 @@
width = int(args[1][1])
- text = stringify(args[0][0](context, mapping, args[0][1]))
- if args[0][0] == runstring:
- text = stringify(runtemplate(context, mapping,
- compiletemplate(text, context)))
+ text = stringify(_evalifliteral(args[0], context, mapping))
right = False
fillchar = ' '
@@ -309,6 +324,26 @@
else:
return text.ljust(width, fillchar)
+def indent(context, mapping, args):
+ """:indent(text, indentchars[, firstline]): Indents all non-empty lines
+ with the characters given in the indentchars string. An optional
+ third parameter will override the indent for the first line only
+ if present."""
+ if not (2 <= len(args) <= 3):
+ # i18n: "indent" is a keyword
+ raise error.ParseError(_("indent() expects two or three arguments"))
+
+ text = stringify(args[0][0](context, mapping, args[0][1]))
+ indent = stringify(args[1][0](context, mapping, args[1][1]))
+
+ if len(args) == 3:
+ firstline = stringify(args[2][0](context, mapping, args[2][1]))
+ else:
+ firstline = indent
+
+ # the indent function doesn't indent the first line, so we do it here
+ return templatefilters.indent(firstline + text, indent)
+
def get(context, mapping, args):
""":get(dict, key): Get an attribute/key from an object. Some keywords
are complex types. This function allows you to obtain the value of an
@@ -552,8 +587,7 @@
num = int(stringify(args[0][0](context, mapping, args[0][1])))
except ValueError:
# i18n: "word" is a keyword
- raise error.ParseError(
- _("Use strings like '3' for numbers passed to word function"))
+ raise error.ParseError(_("word expects an integer index"))
text = stringify(args[1][0](context, mapping, args[1][1]))
if len(args) == 3:
splitter = stringify(args[2][0](context, mapping, args[2][1]))
@@ -566,17 +600,23 @@
else:
return tokens[num]
-methods = {
+# methods to interpret function arguments or inner expressions (e.g. {_(x)})
+exprmethods = {
+ "integer": lambda e, c: (runinteger, e[1]),
"string": lambda e, c: (runstring, e[1]),
"rawstring": lambda e, c: (runrawstring, e[1]),
"symbol": lambda e, c: (runsymbol, e[1]),
- "group": lambda e, c: compileexp(e[1], c),
+ "group": lambda e, c: compileexp(e[1], c, exprmethods),
# ".": buildmember,
"|": buildfilter,
"%": buildmap,
"func": buildfunc,
}
+# methods to interpret top-level template (e.g. {x}, {x|_}, {x % "y"})
+methods = exprmethods.copy()
+methods["integer"] = exprmethods["symbol"] # '{1}' as variable
+
funcs = {
"date": date,
"diff": diff,
@@ -585,6 +625,7 @@
"if": if_,
"ifcontains": ifcontains,
"ifeq": ifeq,
+ "indent": indent,
"join": join,
"label": label,
"pad": pad,
@@ -619,14 +660,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.
@@ -710,7 +762,7 @@
raise util.Abort(_("style '%s' not found") % mapfile,
hint=_("available styles: %s") % stylelist())
- conf = config.config()
+ conf = config.config(includepaths=templatepaths())
conf.read(mapfile)
for key, val in conf[''].items():
@@ -718,7 +770,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/gitweb/bookmarks.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/bookmarks.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -20,7 +20,7 @@
<a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a> |
bookmarks |
<a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a> |
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a> |
<a href="{url|urlescape}help{sessionvars%urlparameter}">help</a>
<br/>
</div>
--- a/mercurial/templates/gitweb/branches.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/branches.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -20,7 +20,7 @@
<a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a> |
<a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a> |
branches |
-<a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a> |
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a> |
<a href="{url|urlescape}help{sessionvars%urlparameter}">help</a>
<br/>
</div>
--- a/mercurial/templates/gitweb/error.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/error.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -19,7 +19,7 @@
<a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a> |
<a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a> |
<a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a> |
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a> |
<a href="{url|urlescape}help{sessionvars%urlparameter}">help</a>
<br/>
</div>
--- a/mercurial/templates/gitweb/fileannotate.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/fileannotate.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -39,19 +39,23 @@
<table cellspacing="0">
<tr>
<td>author</td>
- <td>{author|obfuscate}</td></tr>
+ <td>{author|obfuscate}</td>
+</tr>
<tr>
<td></td>
- <td class="date age">{date|rfc822date}</td></tr>
+ <td class="date age">{date|rfc822date}</td>
+</tr>
{branch%filerevbranch}
<tr>
<td>changeset {rev}</td>
- <td style="font-family:monospace"><a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
+ <td style="font-family:monospace"><a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
+</tr>
{parent%fileannotateparent}
{child%fileannotatechild}
<tr>
<td>permissions</td>
- <td style="font-family:monospace">{permissions|permissions}</td></tr>
+ <td style="font-family:monospace">{permissions|permissions}</td>
+</tr>
</table>
</div>
--- a/mercurial/templates/gitweb/filecomparison.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/filecomparison.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -39,7 +39,8 @@
{branch%filerevbranch}
<tr>
<td>changeset {rev}</td>
- <td style="font-family:monospace"><a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
+ <td style="font-family:monospace"><a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
+</tr>
{parent%filecompparent}
{child%filecompchild}
</table>
--- a/mercurial/templates/gitweb/filediff.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/filediff.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -39,7 +39,8 @@
{branch%filerevbranch}
<tr>
<td>changeset {rev}</td>
- <td style="font-family:monospace"><a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
+ <td style="font-family:monospace"><a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
+</tr>
{parent%filediffparent}
{child%filediffchild}
</table>
--- a/mercurial/templates/gitweb/filerevision.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/filerevision.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -39,19 +39,23 @@
<table cellspacing="0">
<tr>
<td>author</td>
- <td>{author|obfuscate}</td></tr>
+ <td>{author|obfuscate}</td>
+</tr>
<tr>
<td></td>
- <td class="date age">{date|rfc822date}</td></tr>
+ <td class="date age">{date|rfc822date}</td>
+</tr>
{branch%filerevbranch}
<tr>
<td>changeset {rev}</td>
- <td style="font-family:monospace"><a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
+ <td style="font-family:monospace"><a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
+</tr>
{parent%filerevparent}
{child%filerevchild}
<tr>
<td>permissions</td>
- <td style="font-family:monospace">{permissions|permissions}</td></tr>
+ <td style="font-family:monospace">{permissions|permissions}</td>
+</tr>
</table>
</div>
--- a/mercurial/templates/gitweb/help.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/help.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -20,7 +20,7 @@
<a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a> |
<a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a> |
<a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a> |
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a> |
help
<br/>
</div>
--- a/mercurial/templates/gitweb/helptopics.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/helptopics.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -20,7 +20,7 @@
<a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a> |
<a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a> |
<a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a> |
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a> |
help
<br/>
</div>
--- a/mercurial/templates/gitweb/map Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/map Mon Jun 15 13:31:22 2015 -0500
@@ -293,11 +293,16 @@
<td>
<a class="list" href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
<b>{desc|strip|firstline|escape|nonempty}</b>
+ <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}{bookmarks%bookmarktag}</span>
</a>
</td>
<td class="link">
- <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> | <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> | <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a> {rename%filelogrename}</td>
- </tr>'
+ <a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> |
+ <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> |
+ <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
+ {rename%filelogrename}
+ </td>
+ </tr>'
archiveentry = ' | <a href="{url|urlescape}archive/{node|short}{extension}{ifeq(path,'/','',path|urlescape)}">{type|escape}</a> '
indexentry = '
<tr class="parity{parity}">
--- a/mercurial/templates/gitweb/search.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/search.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -27,7 +27,7 @@
<a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a> |
<a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a> |
<a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry}
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a>{archives%archiveentry}
|
<a href="{url|urlescape}help{sessionvars%urlparameter}">help</a>
<br/>
--- a/mercurial/templates/gitweb/summary.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/summary.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -26,7 +26,7 @@
<a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a> |
<a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a> |
<a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>{archives%archiveentry} |
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a>{archives%archiveentry} |
<a href="{url|urlescape}help{sessionvars%urlparameter}">help</a>
<br/>
</div>
--- a/mercurial/templates/gitweb/tags.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/gitweb/tags.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -20,7 +20,7 @@
tags |
<a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a> |
<a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a> |
-<a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a> |
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a> |
<a href="{url|urlescape}help{sessionvars%urlparameter}">help</a>
<br/>
</div>
--- a/mercurial/templates/map-cmdline.bisect Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/map-cmdline.bisect Mon Jun 15 13:31:22 2015 -0500
@@ -1,25 +1,14 @@
-changeset = 'changeset: {rev}:{node|short}\nbisect: {bisect}\n{branches}{bookmarks}{tags}{parents}user: {author}\ndate: {date|date}\nsummary: {desc|firstline}\n\n'
-changeset_quiet = '{bisect|shortbisect} {rev}:{node|short}\n'
-changeset_verbose = 'changeset: {rev}:{node|short}\nbisect: {bisect}\n{branches}{bookmarks}{tags}{parents}user: {author}\ndate: {date|date}\n{files}{file_copies_switch}description:\n{desc|strip}\n\n\n'
-changeset_debug = 'changeset: {rev}:{node}\nbisect: {bisect}\n{branches}{bookmarks}{tags}{parents}{manifest}user: {author}\ndate: {date|date}\n{file_mods}{file_adds}{file_dels}{file_copies_switch}{extras}description:\n{desc|strip}\n\n\n'
-start_files = 'files: '
-file = ' {file}'
-end_files = '\n'
-start_file_mods = 'files: '
-file_mod = ' {file_mod}'
-end_file_mods = '\n'
-start_file_adds = 'files+: '
-file_add = ' {file_add}'
-end_file_adds = '\n'
-start_file_dels = 'files-: '
-file_del = ' {file_del}'
-end_file_dels = '\n'
-start_file_copies = 'copies: '
-file_copy = ' {name} ({source})'
-end_file_copies = '\n'
-parent = 'parent: {rev}:{node|formatnode}\n'
-manifest = 'manifest: {rev}:{node}\n'
-branch = 'branch: {branch}\n'
-tag = 'tag: {tag}\n'
-bookmark = 'bookmark: {bookmark}\n'
-extra = 'extra: {key}={value|stringescape}\n'
+%include map-cmdline.default
+
+changeset = '{cset}{lbisect}{branches}{bookmarks}{tags}{parents}{user}{ldate}{summary}\n'
+changeset_quiet = '{lshortbisect} {rev}:{node|short}\n'
+changeset_verbose = '{cset}{lbisect}{branches}{bookmarks}{tags}{parents}{user}{ldate}{lfiles}{lfile_copies_switch}{description}\n'
+changeset_debug = '{fullcset}{lbisect}{branches}{bookmarks}{tags}{lphase}{parents}{manifest}{user}{ldate}{lfile_mods}{lfile_adds}{lfile_dels}{lfile_copies_switch}{extras}{description}\n'
+
+# We take the zeroth word in order to omit "(implicit)" in the label
+bisectlabel = ' bisect.{word('0', bisect)}'
+
+lbisect ='{label("log.bisect{if(bisect, bisectlabel)}",
+ "bisect: {bisect}\n")}'
+lshortbisect ='{label("log.bisect{if(bisect, bisectlabel)}",
+ "{bisect|shortbisect}")}'
--- a/mercurial/templates/map-cmdline.default Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/map-cmdline.default Mon Jun 15 13:31:22 2015 -0500
@@ -71,3 +71,5 @@
'description:')}
{label('ui.note log.description',
'{desc|strip}')}\n\n")}'
+
+status = '{status} {path}\n{if(copy, " {copy}\n")}'
--- a/mercurial/templates/map-cmdline.phases Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/map-cmdline.phases Mon Jun 15 13:31:22 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")}'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/templates/map-cmdline.status Mon Jun 15 13:31:22 2015 -0500
@@ -0,0 +1,25 @@
+%include map-cmdline.default
+
+# Override base templates
+changeset = '{cset}{branches}{bookmarks}{tags}{parents}{user}{ldate}{summary}{lfiles}\n'
+changeset_verbose = '{cset}{branches}{bookmarks}{tags}{parents}{user}{ldate}{description}{lfiles}\n'
+changeset_debug = '{fullcset}{branches}{bookmarks}{tags}{lphase}{parents}{manifest}{user}{ldate}{extras}{description}{lfiles}\n'
+
+# Override the file templates
+lfiles = '{if(files,
+ label('ui.note log.files',
+ 'files:\n'))}{lfile_mods}{lfile_adds}{lfile_copies_switch}{lfile_dels}'
+
+# Exclude copied files, will display those in lfile_copies_switch
+lfile_adds = '{file_adds % "{ifcontains(file, file_copies_switch,
+ '',
+ '{lfile_add}')}"}'
+lfile_add = '{label("status.added", "A {file}\n")}'
+
+lfile_copies_switch = '{file_copies_switch % "{lfile_copy_orig}{lfile_copy_dest}"'
+lfile_copy_orig = '{label("status.added", "A {name}\n")}'
+lfile_copy_dest = '{label("status.copied", " {source}\n")}'
+
+lfile_mods = '{file_mods % "{label('status.modified', 'M {file}\n')}"}'
+
+lfile_dels = '{file_dels % "{label('status.removed', 'R {file}\n')}"}'
--- a/mercurial/templates/monoblue/bookmarks.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/monoblue/bookmarks.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -21,11 +21,11 @@
<li><a href="{url|urlescape}summary{sessionvars%urlparameter}">summary</a></li>
<li><a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a></li>
<li><a href="{url|urlescape}changelog{sessionvars%urlparameter}">changelog</a></li>
- <li><a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
+ <li><a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a></li>
<li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
<li class="current">bookmarks</li>
<li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
- <li><a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a></li>
+ <li><a href="{url|urlescape}file{sessionvars%urlparameter}">files</a></li>
<li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
</ul>
</div>
--- a/mercurial/templates/monoblue/branches.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/monoblue/branches.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -21,11 +21,11 @@
<li><a href="{url|urlescape}summary{sessionvars%urlparameter}">summary</a></li>
<li><a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a></li>
<li><a href="{url|urlescape}changelog{sessionvars%urlparameter}">changelog</a></li>
- <li><a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
+ <li><a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a></li>
<li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
<li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
<li class="current">branches</li>
- <li><a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a></li>
+ <li><a href="{url|urlescape}file{sessionvars%urlparameter}">files</a></li>
<li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
</ul>
</div>
--- a/mercurial/templates/monoblue/error.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/monoblue/error.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -21,11 +21,11 @@
<li class="current">summary</li>
<li><a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a></li>
<li><a href="{url|urlescape}log{sessionvars%urlparameter}">changelog</a></li>
- <li><a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
+ <li><a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a></li>
<li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
<li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
<li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
- <li><a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a></li>
+ <li><a href="{url|urlescape}file{sessionvars%urlparameter}">files</a></li>
<li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
</ul>
</div>
--- a/mercurial/templates/monoblue/help.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/monoblue/help.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -21,11 +21,11 @@
<li><a href="{url|urlescape}summary{sessionvars%urlparameter}">summary</a></li>
<li><a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a></li>
<li><a href="{url|urlescape}changelog{sessionvars%urlparameter}">changelog</a></li>
- <li><a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
+ <li><a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a></li>
<li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
<li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
<li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
- <li><a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a></li>
+ <li><a href="{url|urlescape}file{sessionvars%urlparameter}">files</a></li>
<li class="current">help</li>
</ul>
</div>
--- a/mercurial/templates/monoblue/helptopics.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/monoblue/helptopics.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -21,11 +21,11 @@
<li><a href="{url|urlescape}summary{sessionvars%urlparameter}">summary</a></li>
<li><a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a></li>
<li><a href="{url|urlescape}changelog{sessionvars%urlparameter}">changelog</a></li>
- <li><a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
+ <li><a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a></li>
<li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
<li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
<li><a href="{url|urlescape}help{sessionvars%urlparameter}">branches</a></li>
- <li><a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a></li>
+ <li><a href="{url|urlescape}file{sessionvars%urlparameter}">files</a></li>
<li class="current">help</li>
</ul>
</div>
--- a/mercurial/templates/monoblue/map Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/monoblue/map Mon Jun 15 13:31:22 2015 -0500
@@ -65,7 +65,10 @@
<td>drwxr-xr-x</td>
<td></td>
<td></td>
- <td><a href="{url|urlescape}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}</a></td>
+ <td>
+ <a href="{url|urlescape}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}</a>
+ <a href="{url|urlescape}file/{node|short}{path|urlescape}/{emptydirs|urlescape}{sessionvars%urlparameter}">{emptydirs|escape}</a>
+ </td>
<td><a href="{url|urlescape}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">files</a></td>
</tr>'
fileentry = '
@@ -244,7 +247,12 @@
filelogentry = '
<tr class="parity{parity}">
<td class="nowrap age">{date|rfc822date}</td>
- <td><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a></td>
+ <td>
+ <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">
+ {desc|strip|firstline|escape|nonempty}
+ <span class="logtags">{inbranch%inbranchtag}{branches%branchtag}{tags%tagtag}{bookmarks%bookmarktag}</span>
+ </a>
+ </td>
<td class="nowrap">
<a href="{url|urlescape}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a> | <a href="{url|urlescape}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a> | <a href="{url|urlescape}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a>
{rename%filelogrename}
--- a/mercurial/templates/monoblue/notfound.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/monoblue/notfound.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -21,11 +21,11 @@
<li class="current">summary</li>
<li><a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a></li>
<li><a href="{url|urlescape}log{sessionvars%urlparameter}">changelog</a></li>
- <li><a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
+ <li><a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a></li>
<li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
<li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
<li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
- <li><a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a></li>
+ <li><a href="{url|urlescape}file{sessionvars%urlparameter}">files</a></li>
{archives%archiveentry}
<li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
</ul>
--- a/mercurial/templates/monoblue/search.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/monoblue/search.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -21,11 +21,11 @@
<li><a href="{url|urlescape}summary{sessionvars%urlparameter}">summary</a></li>
<li><a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a></li>
<li><a href="{url|urlescape}log{sessionvars%urlparameter}">changelog</a></li>
- <li><a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
+ <li><a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a></li>
<li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
<li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
<li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
- <li><a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a></li>
+ <li><a href="{url|urlescape}file{sessionvars%urlparameter}">files</a></li>
{archives%archiveentry}
<li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
</ul>
--- a/mercurial/templates/monoblue/summary.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/monoblue/summary.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -21,11 +21,11 @@
<li class="current">summary</li>
<li><a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a></li>
<li><a href="{url|urlescape}log{sessionvars%urlparameter}">changelog</a></li>
- <li><a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
+ <li><a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a></li>
<li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
<li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
<li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
- <li><a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a></li>
+ <li><a href="{url|urlescape}file{sessionvars%urlparameter}">files</a></li>
<li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
</ul>
</div>
--- a/mercurial/templates/monoblue/tags.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/monoblue/tags.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -21,11 +21,11 @@
<li><a href="{url|urlescape}summary{sessionvars%urlparameter}">summary</a></li>
<li><a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a></li>
<li><a href="{url|urlescape}changelog{sessionvars%urlparameter}">changelog</a></li>
- <li><a href="{url|urlescape}graph/{node|short}{sessionvars%urlparameter}">graph</a></li>
+ <li><a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a></li>
<li class="current">tags</li>
<li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
<li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
- <li><a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a></li>
+ <li><a href="{url|urlescape}file{sessionvars%urlparameter}">files</a></li>
<li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
</ul>
</div>
--- a/mercurial/templates/paper/fileannotate.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/paper/fileannotate.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -37,7 +37,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> {pathdef%breadcrumb}</h2>
-<h3>annotate {file|escape} @ {rev}:{node|short}</h3>
+<h3>annotate {file|escape} @ {rev}:{node|short} {branch%changelogbranchname}{tags%changelogtag}{bookmarks%changelogtag}</h3>
<form class="search" action="{url|urlescape}log">
{sessionvars%hiddenformentry}
--- a/mercurial/templates/paper/filecomparison.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/paper/filecomparison.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -36,7 +36,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> {pathdef%breadcrumb}</h2>
-<h3>comparison {file|escape} @ {rev}:{node|short}</h3>
+<h3>comparison {file|escape} @ {rev}:{node|short} {branch%changelogbranchname}{tags%changelogtag}{bookmarks%changelogtag}</h3>
<form class="search" action="{url|urlescape}log">
<p>{sessionvars%hiddenformentry}</p>
--- a/mercurial/templates/paper/filediff.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/paper/filediff.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -36,7 +36,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> {pathdef%breadcrumb}</h2>
-<h3>diff {file|escape} @ {rev}:{node|short}</h3>
+<h3>diff {file|escape} @ {rev}:{node|short} {branch%changelogbranchname}{tags%changelogtag}{bookmarks%changelogtag}</h3>
<form class="search" action="{url|urlescape}log">
<p>{sessionvars%hiddenformentry}</p>
--- a/mercurial/templates/paper/filelogentry.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/paper/filelogentry.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -1,5 +1,8 @@
<tr>
<td class="age">{date|rfc822date}</td>
<td class="author">{author|person}</td>
- <td class="description"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags%changelogtag}{rename%filelogrename}</td>
+ <td class="description">
+ <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>
+ {inbranch%changelogbranchname}{branches%changelogbranchhead}{tags%changelogtag}{bookmarks%changelogtag}{rename%filelogrename}
+ </td>
</tr>
--- a/mercurial/templates/paper/filerevision.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/paper/filerevision.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -36,7 +36,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> {pathdef%breadcrumb}</h2>
-<h3>view {file|escape} @ {rev}:{node|short}</h3>
+<h3>view {file|escape} @ {rev}:{node|short} {branch%changelogbranchname}{tags%changelogtag}{bookmarks%changelogtag}</h3>
<form class="search" action="{url|urlescape}log">
{sessionvars%hiddenformentry}
--- a/mercurial/templates/paper/manifest.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/paper/manifest.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -30,7 +30,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> {pathdef%breadcrumb}</h2>
-<h3>directory {path|escape} @ {rev}:{node|short} {tags%changelogtag}</h3>
+<h3>directory {path|escape} @ {rev}:{node|short} {branch%changelogbranchname}{tags%changelogtag}{bookmarks%changelogtag}</h3>
<form class="search" action="{url|urlescape}log">
{sessionvars%hiddenformentry}
--- a/mercurial/templates/paper/search.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/paper/search.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -15,6 +15,8 @@
<li><a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a></li>
<li><a href="{url|urlescape}bookmarks{sessionvars%urlparameter}">bookmarks</a></li>
<li><a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a></li>
+</ul>
+<ul>
<li><a href="{url|urlescape}help{sessionvars%urlparameter}">help</a></li>
</ul>
</div>
--- a/mercurial/templates/paper/shortlogentry.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/paper/shortlogentry.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -1,5 +1,8 @@
<tr>
<td class="age">{date|rfc822date}</td>
<td class="author">{author|person}</td>
- <td class="description"><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>{inbranch%changelogbranchname}{branches%changelogbranchhead}{tags%changelogtag}{bookmarks%changelogtag}</td>
+ <td class="description">
+ <a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape|nonempty}</a>
+ {inbranch%changelogbranchname}{branches%changelogbranchhead}{tags%changelogtag}{bookmarks%changelogtag}
+ </td>
</tr>
--- a/mercurial/templates/spartan/branches.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/spartan/branches.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -12,7 +12,7 @@
<a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a>
<a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a>
<a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a>
-<a href="{url|urlescape}file/{node|short}/{sessionvars%urlparameter}">files</a>
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a>
<a href="{url|urlescape}help{sessionvars%urlparameter}">help</a>
<a type="application/rss+xml" href="{url|urlescape}rss-branches">rss</a>
<a type="application/atom+xml" href="{url|urlescape}atom-branches">atom</a>
--- a/mercurial/templates/spartan/fileannotate.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/spartan/fileannotate.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -22,12 +22,14 @@
<table>
<tr>
<td class="metatag">changeset {rev}:</td>
- <td><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
+ <td><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
+</tr>
{parent%fileannotateparent}
{child%fileannotatechild}
<tr>
<td class="metatag">author:</td>
- <td>{author|obfuscate}</td></tr>
+ <td>{author|obfuscate}</td>
+</tr>
<tr>
<td class="metatag">date:</td>
<td class="date age">{date|rfc822date}</td>
--- a/mercurial/templates/spartan/filerevision.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/spartan/filerevision.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -22,18 +22,22 @@
<table>
<tr>
<td class="metatag">changeset {rev}:</td>
- <td><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>
+ <td><a href="{url|urlescape}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td>
+</tr>
{parent%filerevparent}
{child%filerevchild}
<tr>
<td class="metatag">author:</td>
- <td>{author|obfuscate}</td></tr>
+ <td>{author|obfuscate}</td>
+</tr>
<tr>
<td class="metatag">date:</td>
- <td class="date age">{date|rfc822date}</td></tr>
+ <td class="date age">{date|rfc822date}</td>
+</tr>
<tr>
<td class="metatag">permissions:</td>
- <td>{permissions|permissions}</td></tr>
+ <td>{permissions|permissions}</td>
+</tr>
<tr>
<td class="metatag">description:</td>
<td>{desc|strip|escape|websub|addbreaks|nonempty}</td>
--- a/mercurial/templates/spartan/search.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/spartan/search.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -9,7 +9,7 @@
<a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a>
<a href="{url|urlescape}tags{sessionvars%urlparameter}">tags</a>
<a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url|urlescape}file/{node|short}{sessionvars%urlparameter}">files</a>
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a>
{archives%archiveentry}
<a href="{url|urlescape}help{sessionvars%urlparameter}">help</a>
</div>
--- a/mercurial/templates/spartan/tags.tmpl Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/spartan/tags.tmpl Mon Jun 15 13:31:22 2015 -0500
@@ -12,7 +12,7 @@
<a href="{url|urlescape}shortlog{sessionvars%urlparameter}">shortlog</a>
<a href="{url|urlescape}graph{sessionvars%urlparameter}">graph</a>
<a href="{url|urlescape}branches{sessionvars%urlparameter}">branches</a>
-<a href="{url|urlescape}file/{node|short}/{sessionvars%urlparameter}">files</a>
+<a href="{url|urlescape}file{sessionvars%urlparameter}">files</a>
<a href="{url|urlescape}help{sessionvars%urlparameter}">help</a>
<a type="application/rss+xml" href="{url|urlescape}rss-tags">rss</a>
<a type="application/atom+xml" href="{url|urlescape}atom-tags">atom</a>
--- a/mercurial/templates/static/style-monoblue.css Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/templates/static/style-monoblue.css Mon Jun 15 13:31:22 2015 -0500
@@ -53,10 +53,8 @@
}
div.page-header form {
- position: absolute;
- margin-bottom: 2px;
- bottom: 0;
- right: 20px;
+ float: right;
+ margin-top: -2px;
}
div.page-header form label {
color: #DDD;
@@ -83,7 +81,6 @@
margin: 10px 0 0 0;
list-style-type: none;
overflow: hidden;
- width: 900px;
}
ul.page-nav li {
margin: 0 2px 0 0;
--- a/mercurial/transaction.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/transaction.py Mon Jun 15 13:31:22 2015 -0500
@@ -496,7 +496,7 @@
_playback(self.journal, self.report, self.opener, self._vfsmap,
self.entries, self._backupentries, False)
self.report(_("rollback completed\n"))
- except Exception:
+ except BaseException:
self.report(_("rollback failed - please run hg recover\n"))
finally:
self.journal = None
--- a/mercurial/treediscovery.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/treediscovery.py Mon Jun 15 13:31:22 2015 -0500
@@ -5,6 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
+import collections
from node import nullid, short
from i18n import _
import util, error
@@ -56,7 +57,7 @@
# a 'branch' here is a linear segment of history, with four parts:
# head, root, first parent, second parent
# (a branch always has two parents (or none) by definition)
- unknown = util.deque(remote.branches(unknown))
+ unknown = collections.deque(remote.branches(unknown))
while unknown:
r = []
while unknown:
--- a/mercurial/ui.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/ui.py Mon Jun 15 13:31:22 2015 -0500
@@ -7,7 +7,7 @@
from i18n import _
import errno, getpass, os, socket, sys, tempfile, traceback
-import config, scmutil, util, error, formatter
+import config, scmutil, util, error, formatter, progress
from node import hex
samplehgrcs = {
@@ -584,6 +584,7 @@
"cmdname.type" is recommended. For example, status issues
a label of "status.modified" for modified files.
'''
+ self._progclear()
if self._buffers:
self._buffers[-1].extend([str(a) for a in args])
else:
@@ -591,6 +592,7 @@
self.fout.write(str(a))
def write_err(self, *args, **opts):
+ self._progclear()
try:
if self._bufferstates and self._bufferstates[-1][0]:
return self.write(*args, **opts)
@@ -842,7 +844,7 @@
output will be redirected if fout is not stdout.
'''
out = self.fout
- if util.any(s[1] for s in self._bufferstates):
+ if any(s[1] for s in self._bufferstates):
out = self
return util.system(cmd, environ=environ, cwd=cwd, onerr=onerr,
errprefix=errprefix, out=out)
@@ -867,8 +869,8 @@
''.join(causetb),
''.join(exconly))
else:
- traceback.print_exception(exc[0], exc[1], exc[2],
- file=self.ferr)
+ output = traceback.format_exception(exc[0], exc[1], exc[2])
+ self.write_err(''.join(output))
return self.tracebackflag or force
def geteditor(self):
@@ -885,6 +887,22 @@
os.environ.get("VISUAL") or
os.environ.get("EDITOR", editor))
+ @util.propertycache
+ def _progbar(self):
+ """setup the progbar singleton to the ui object"""
+ if (self.quiet or self.debugflag
+ or self.configbool('progress', 'disable', False)
+ or not progress.shouldprint(self)):
+ return None
+ return getprogbar(self)
+
+ def _progclear(self):
+ """clear progress bar output if any. use it before any output"""
+ if '_progbar' not in vars(self): # nothing loadef yet
+ return
+ if self._progbar is not None and self._progbar.printed:
+ self._progbar.clear()
+
def progress(self, topic, pos, item="", unit="", total=None):
'''show a progress message
@@ -901,8 +919,10 @@
All topics should be marked closed by setting pos to None at
termination.
'''
-
- if pos is None or not self.debugflag:
+ if self._progbar is not None:
+ self._progbar.progress(topic, pos, item=item, unit=unit,
+ total=total)
+ if pos is None or not self.configbool('progress', 'debug'):
return
if unit:
@@ -982,3 +1002,15 @@
self.name = name
# We'll do more intelligent things with rawloc in the future.
self.loc = rawloc
+
+# we instantiate one globally shared progress bar to avoid
+# competing progress bars when multiple UI objects get created
+_progresssingleton = None
+
+def getprogbar(ui):
+ global _progresssingleton
+ if _progresssingleton is None:
+ # passing 'ui' object to the singleton is fishy,
+ # this is how the extension used to work but feel free to rework it.
+ _progresssingleton = progress.progbar(ui)
+ return _progresssingleton
--- a/mercurial/url.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/url.py Mon Jun 15 13:31:22 2015 -0500
@@ -120,16 +120,6 @@
if e.startswith('.') and host.endswith(e[1:]):
return None
- # work around a bug in Python < 2.4.2
- # (it leaves a "\n" at the end of Proxy-authorization headers)
- baseclass = req.__class__
- class _request(baseclass):
- def add_header(self, key, val):
- if key.lower() == 'proxy-authorization':
- val = val.strip()
- return baseclass.add_header(self, key, val)
- req.__class__ = _request
-
return urllib2.ProxyHandler.proxy_open(self, req, proxy, type_)
def _gen_sendfile(orgsend):
@@ -185,8 +175,8 @@
self.sock.connect((self.host, self.port))
if _generic_proxytunnel(self):
# we do not support client X.509 certificates
- self.sock = sslutil.ssl_wrap_socket(self.sock, None, None,
- serverhostname=self.host)
+ self.sock = sslutil.wrapsocket(self.sock, None, None, None,
+ serverhostname=self.host)
else:
keepalive.HTTPConnection.connect(self)
@@ -328,11 +318,18 @@
return keepalive.HTTPHandler._start_transaction(self, h, req)
if has_https:
- class httpsconnection(httplib.HTTPSConnection):
+ class httpsconnection(httplib.HTTPConnection):
response_class = keepalive.HTTPResponse
+ default_port = httplib.HTTPS_PORT
# must be able to send big bundle as stream.
send = _gen_sendfile(keepalive.safesend)
- getresponse = keepalive.wrapgetresponse(httplib.HTTPSConnection)
+ getresponse = keepalive.wrapgetresponse(httplib.HTTPConnection)
+
+ def __init__(self, host, port=None, key_file=None, cert_file=None,
+ *args, **kwargs):
+ httplib.HTTPConnection.__init__(self, host, port, *args, **kwargs)
+ self.key_file = key_file
+ self.cert_file = cert_file
def connect(self):
self.sock = _create_connection((self.host, self.port))
@@ -341,7 +338,7 @@
if self.realhostport: # use CONNECT proxy
_generic_proxytunnel(self)
host = self.realhostport.rsplit(':', 1)[0]
- self.sock = sslutil.ssl_wrap_socket(
+ self.sock = sslutil.wrapsocket(
self.sock, self.key_file, self.cert_file, serverhostname=host,
**sslutil.sslkwargs(self.ui, host))
sslutil.validator(self.ui, host)(self.sock)
--- a/mercurial/util.h Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/util.h Mon Jun 15 13:31:22 2015 -0500
@@ -57,66 +57,6 @@
#endif /* PY_MAJOR_VERSION */
-/* Backports from 2.6 */
-#if PY_VERSION_HEX < 0x02060000
-
-#define Py_TYPE(ob) (ob)->ob_type
-#define Py_SIZE(ob) (ob)->ob_size
-#define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
-
-/* Shamelessly stolen from bytesobject.h */
-#define PyBytesObject PyStringObject
-#define PyBytes_Type PyString_Type
-
-#define PyBytes_Check PyString_Check
-#define PyBytes_CheckExact PyString_CheckExact
-#define PyBytes_CHECK_INTERNED PyString_CHECK_INTERNED
-#define PyBytes_AS_STRING PyString_AS_STRING
-#define PyBytes_GET_SIZE PyString_GET_SIZE
-#define Py_TPFLAGS_BYTES_SUBCLASS Py_TPFLAGS_STRING_SUBCLASS
-
-#define PyBytes_FromStringAndSize PyString_FromStringAndSize
-#define PyBytes_FromString PyString_FromString
-#define PyBytes_FromFormatV PyString_FromFormatV
-#define PyBytes_FromFormat PyString_FromFormat
-#define PyBytes_Size PyString_Size
-#define PyBytes_AsString PyString_AsString
-#define PyBytes_Repr PyString_Repr
-#define PyBytes_Concat PyString_Concat
-#define PyBytes_ConcatAndDel PyString_ConcatAndDel
-#define _PyBytes_Resize _PyString_Resize
-#define _PyBytes_Eq _PyString_Eq
-#define PyBytes_Format PyString_Format
-#define _PyBytes_FormatLong _PyString_FormatLong
-#define PyBytes_DecodeEscape PyString_DecodeEscape
-#define _PyBytes_Join _PyString_Join
-#define PyBytes_Decode PyString_Decode
-#define PyBytes_Encode PyString_Encode
-#define PyBytes_AsEncodedObject PyString_AsEncodedObject
-#define PyBytes_AsEncodedString PyString_AsEncodedString
-#define PyBytes_AsDecodedObject PyString_AsDecodedObject
-#define PyBytes_AsDecodedString PyString_AsDecodedString
-#define PyBytes_AsStringAndSize PyString_AsStringAndSize
-#define _PyBytes_InsertThousandsGrouping _PyString_InsertThousandsGrouping
-
-#endif /* PY_VERSION_HEX */
-
-#if (PY_VERSION_HEX < 0x02050000)
-/* Definitions to get compatibility with python 2.4 and earlier which
- does not have Py_ssize_t. See also PEP 353.
- Note: msvc (8 or earlier) does not have ssize_t, so we use Py_ssize_t.
-*/
-typedef int Py_ssize_t;
-typedef Py_ssize_t (*lenfunc)(PyObject *);
-typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
-#define PyInt_FromSsize_t PyInt_FromLong
-
-#if !defined(PY_SSIZE_T_MIN)
-#define PY_SSIZE_T_MAX INT_MAX
-#define PY_SSIZE_T_MIN INT_MIN
-#endif
-#endif
-
#ifdef _WIN32
#ifdef _MSC_VER
/* msvc 6.0 has problems */
--- a/mercurial/util.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/util.py Mon Jun 15 13:31:22 2015 -0500
@@ -19,7 +19,7 @@
import errno, shutil, sys, tempfile, traceback
import re as remod
import os, time, datetime, calendar, textwrap, signal, collections
-import imp, socket, urllib, struct
+import imp, socket, urllib
import gc
if os.name == 'nt':
@@ -54,6 +54,7 @@
oslink = platform.oslink
parsepatchoutput = platform.parsepatchoutput
pconvert = platform.pconvert
+poll = platform.poll
popen = platform.popen
posixfile = platform.posixfile
quotecommand = platform.quotecommand
@@ -232,14 +233,102 @@
import subprocess
closefds = os.name == 'posix'
-def unpacker(fmt):
- """create a struct unpacker for the specified format"""
- try:
- # 2.5+
- return struct.Struct(fmt).unpack
- except AttributeError:
- # 2.4
- return lambda buf: struct.unpack(fmt, buf)
+_chunksize = 4096
+
+class bufferedinputpipe(object):
+ """a manually buffered input pipe
+
+ Python will not let us use buffered IO and lazy reading with 'polling' at
+ the same time. We cannot probe the buffer state and select will not detect
+ that data are ready to read if they are already buffered.
+
+ This class let us work around that by implementing its own buffering
+ (allowing efficient readline) while offering a way to know if the buffer is
+ empty from the output (allowing collaboration of the buffer with polling).
+
+ This class lives in the 'util' module because it makes use of the 'os'
+ module from the python stdlib.
+ """
+
+ def __init__(self, input):
+ self._input = input
+ self._buffer = []
+ self._eof = False
+
+ @property
+ def hasbuffer(self):
+ """True is any data is currently buffered
+
+ This will be used externally a pre-step for polling IO. If there is
+ already data then no polling should be set in place."""
+ return bool(self._buffer)
+
+ @property
+ def closed(self):
+ return self._input.closed
+
+ def fileno(self):
+ return self._input.fileno()
+
+ def close(self):
+ return self._input.close()
+
+ def read(self, size):
+ while (not self._eof) and (self._lenbuf < size):
+ self._fillbuffer()
+ return self._frombuffer(size)
+
+ def readline(self, *args, **kwargs):
+ if 1 < len(self._buffer):
+ # this should not happen because both read and readline end with a
+ # _frombuffer call that collapse it.
+ self._buffer = [''.join(self._buffer)]
+ lfi = -1
+ if self._buffer:
+ lfi = self._buffer[-1].find('\n')
+ while (not self._eof) and lfi < 0:
+ self._fillbuffer()
+ if self._buffer:
+ lfi = self._buffer[-1].find('\n')
+ size = lfi + 1
+ if lfi < 0: # end of file
+ size = self._lenbuf
+ elif 1 < len(self._buffer):
+ # we need to take previous chunks into account
+ size += self._lenbuf - len(self._buffer[-1])
+ return self._frombuffer(size)
+
+ @property
+ def _lenbuf(self):
+ """return the current lengh of buffered data"""
+ return sum(len(d) for d in self._buffer)
+
+ def _frombuffer(self, size):
+ """return at most 'size' data from the buffer
+
+ The data are removed from the buffer."""
+ if size == 0 or not self._buffer:
+ return ''
+ buf = self._buffer[0]
+ if 1 < len(self._buffer):
+ buf = ''.join(self._buffer)
+
+ data = buf[:size]
+ buf = buf[len(data):]
+ if buf:
+ self._buffer = [buf]
+ else:
+ self._buffer = []
+ return data
+
+ def _fillbuffer(self):
+ """read data to the buffer"""
+ data = os.read(self._input.fileno(), _chunksize)
+ if not data:
+ self._eof = True
+ else:
+ # inefficient add
+ self._buffer.append(data)
def popen2(cmd, env=None, newlines=False):
# Setting bufsize to -1 lets the system decide the buffer size.
@@ -256,8 +345,8 @@
stdin, stdout, stderr, p = popen4(cmd, env, newlines)
return stdin, stdout, stderr
-def popen4(cmd, env=None, newlines=False):
- p = subprocess.Popen(cmd, shell=True, bufsize=-1,
+def popen4(cmd, env=None, newlines=False, bufsize=-1):
+ p = subprocess.Popen(cmd, shell=True, bufsize=bufsize,
close_fds=closefds,
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
@@ -334,18 +423,6 @@
return f
-try:
- collections.deque.remove
- deque = collections.deque
-except AttributeError:
- # python 2.4 lacks deque.remove
- class deque(collections.deque):
- def remove(self, val):
- for i, v in enumerate(self):
- if v == val:
- del self[i]
- break
-
class sortdict(dict):
'''a simple sorted dictionary'''
def __init__(self, data=None):
@@ -396,7 +473,7 @@
def __init__(self, maxsize):
self._cache = {}
self._maxsize = maxsize
- self._order = deque()
+ self._order = collections.deque()
def __getitem__(self, key):
value = self._cache[key]
@@ -418,12 +495,12 @@
def clear(self):
self._cache.clear()
- self._order = deque()
+ self._order = collections.deque()
def lrucachefunc(func):
'''cache most recent results of function calls'''
cache = {}
- order = deque()
+ order = collections.deque()
if func.func_code.co_argcount == 1:
def f(arg):
if arg not in cache:
@@ -1003,15 +1080,13 @@
f2 = testfile + ".hgtmp2"
fd = None
try:
- try:
- oslink(f1, f2)
- except OSError:
- return False
-
+ oslink(f1, f2)
# nlinks() may behave differently for files on Windows shares if
# the file is open.
fd = posixfile(f2)
return nlinks(f2) > 1
+ except OSError:
+ return False
finally:
if fd is not None:
fd.close()
@@ -1203,7 +1278,7 @@
else:
yield chunk
self.iter = splitbig(in_iter)
- self._queue = deque()
+ self._queue = collections.deque()
def read(self, l=None):
"""Read L bytes of data from the iterator of chunks of data.
@@ -1573,13 +1648,6 @@
This requires use decision to determine width of such characters.
"""
- def __init__(self, **kwargs):
- textwrap.TextWrapper.__init__(self, **kwargs)
-
- # for compatibility between 2.4 and 2.6
- if getattr(self, 'drop_whitespace', None) is None:
- self.drop_whitespace = kwargs.get('drop_whitespace', True)
-
def _cutdown(self, ucstr, space_left):
l = 0
colwidth = encoding.ucolwidth
@@ -1734,21 +1802,6 @@
if prevhandler is not None:
signal.signal(signal.SIGCHLD, prevhandler)
-try:
- any, all = any, all
-except NameError:
- def any(iterable):
- for i in iterable:
- if i:
- return True
- return False
-
- def all(iterable):
- for i in iterable:
- if not i:
- return False
- return True
-
def interpolate(prefix, mapping, s, fn=None, escape_prefix=False):
"""Return the result of interpolating items in the mapping into string s.
--- a/mercurial/windows.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/windows.py Mon Jun 15 13:31:22 2015 -0500
@@ -26,7 +26,6 @@
unlink = win32.unlink
umask = 0022
-_SEEK_END = 2 # os.SEEK_END was introduced in Python 2.5
def posixfile(name, mode='r', buffering=-1):
'''Open a file with even more POSIX-like semantics'''
@@ -36,7 +35,7 @@
# The position when opening in append mode is implementation defined, so
# make it consistent with other platforms, which position at EOF.
if 'a' in mode:
- fp.seek(0, _SEEK_END)
+ fp.seek(0, os.SEEK_END)
return fp
except WindowsError, err:
@@ -139,7 +138,7 @@
return pconvert(os.path.normpath(path))
def normcase(path):
- return encoding.upper(path)
+ return encoding.upper(path) # NTFS compares via upper()
# see posix.py for definitions
normcasespec = encoding.normcasespecs.upper
@@ -162,6 +161,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'(\\*)("|\\$)')
@@ -249,11 +260,9 @@
for n, k, s in osutil.listdir(dir, True)
if getkind(s.st_mode) in _wantedkinds])
except OSError, err:
- # handle directory not found in Python version prior to 2.5
- # Python <= 2.4 returns native Windows code 3 in errno
# Python >= 2.5 returns ENOENT and adds winerror field
# EINVAL is raised if dir is not a directory.
- if err.errno not in (3, errno.ENOENT, errno.EINVAL,
+ if err.errno not in (errno.ENOENT, errno.EINVAL,
errno.ENOTDIR):
raise
dmap = {}
@@ -361,6 +370,10 @@
'''check whether a stat result is an executable file'''
return False
+def poll(fds):
+ # see posix.py for description
+ raise NotImplementedError()
+
def readpipe(pipe):
"""Read all available data from a pipe."""
chunks = []
--- a/mercurial/wireproto.py Sat Jun 13 20:14:22 2015 +0900
+++ b/mercurial/wireproto.py Mon Jun 15 13:31:22 2015 -0500
@@ -9,7 +9,7 @@
from i18n import _
from node import bin, hex
import changegroup as changegroupmod, bundle2, pushkey as pushkeymod
-import peer, error, encoding, util, store, exchange
+import peer, error, encoding, util, exchange
class abstractserverproto(object):
@@ -203,11 +203,12 @@
#
# :nodes: list of binary nodes
# :csv: list of comma-separated values
+# :scsv: list of comma-separated values return as set
# :plain: string with no transformation needed.
gboptsmap = {'heads': 'nodes',
'common': 'nodes',
'obsmarkers': 'boolean',
- 'bundlecaps': 'csv',
+ 'bundlecaps': 'scsv',
'listkeys': 'csv',
'cg': 'boolean'}
@@ -324,6 +325,8 @@
self.ui.debug('preparing listkeys for "%s"\n' % namespace)
yield {'namespace': encoding.fromlocal(namespace)}, f
d = f.value
+ self.ui.debug('received listkey for "%s": %i bytes\n'
+ % (namespace, len(d)))
yield pushkeymod.decodekeys(d)
def stream_out(self):
@@ -345,6 +348,11 @@
def getbundle(self, source, **kwargs):
self.requirecap('getbundle', _('look up remote changes'))
opts = {}
+ bundlecaps = kwargs.get('bundlecaps')
+ if bundlecaps is not None:
+ kwargs['bundlecaps'] = sorted(bundlecaps)
+ else:
+ bundlecaps = () # kwargs could have it to None
for key, value in kwargs.iteritems():
if value is None:
continue
@@ -353,7 +361,7 @@
assert False, 'unexpected'
elif keytype == 'nodes':
value = encodelist(value)
- elif keytype == 'csv':
+ elif keytype in ('csv', 'scsv'):
value = ','.join(value)
elif keytype == 'boolean':
value = '%i' % bool(value)
@@ -362,10 +370,7 @@
% keytype)
opts[key] = value
f = self._callcompressable("getbundle", **opts)
- bundlecaps = kwargs.get('bundlecaps')
- if bundlecaps is None:
- bundlecaps = () # kwargs could have it to None
- if util.any((cap.startswith('HG2') for cap in bundlecaps)):
+ if any((cap.startswith('HG2') for cap in bundlecaps)):
return bundle2.getunbundler(self.ui, f)
else:
return changegroupmod.cg1unpacker(f, 'UN')
@@ -661,6 +666,8 @@
if keytype == 'nodes':
opts[k] = decodelist(v)
elif keytype == 'csv':
+ opts[k] = list(v.split(','))
+ elif keytype == 'scsv':
opts[k] = set(v.split(','))
elif keytype == 'boolean':
opts[k] = bool(v)
@@ -742,76 +749,27 @@
def _allowstream(ui):
return ui.configbool('server', 'uncompressed', True, untrusted=True)
-def _walkstreamfiles(repo):
- # this is it's own function so extensions can override it
- return repo.store.walk()
-
@wireprotocommand('stream_out')
def stream(repo, proto):
'''If the server supports streaming clone, it advertises the "stream"
capability with a value representing the version and flags of the repo
it is serving. Client checks to see if it understands the format.
-
- The format is simple: the server writes out a line with the amount
- of files, then the total amount of bytes to be transferred (separated
- by a space). Then, for each file, the server first writes the filename
- and file size (separated by the null character), then the file contents.
'''
-
if not _allowstream(repo.ui):
return '1\n'
- entries = []
- total_bytes = 0
- try:
- # get consistent snapshot of repo, lock during scan
- lock = repo.lock()
- try:
- repo.ui.debug('scanning\n')
- for name, ename, size in _walkstreamfiles(repo):
- if size:
- entries.append((name, size))
- total_bytes += size
- finally:
- lock.release()
- except error.LockError:
- return '2\n' # error: 2
-
- def streamer(repo, entries, total):
- '''stream out all metadata files in repository.'''
- yield '0\n' # success
- repo.ui.debug('%d files, %d bytes to transfer\n' %
- (len(entries), total_bytes))
- yield '%d %d\n' % (len(entries), total_bytes)
+ def getstream(it):
+ yield '0\n'
+ for chunk in it:
+ yield chunk
- sopener = repo.svfs
- oldaudit = sopener.mustaudit
- debugflag = repo.ui.debugflag
- sopener.mustaudit = False
-
- try:
- for name, size in entries:
- if debugflag:
- repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
- # partially encode name over the wire for backwards compat
- yield '%s\0%d\n' % (store.encodedir(name), size)
- if size <= 65536:
- fp = sopener(name)
- try:
- data = fp.read(size)
- finally:
- fp.close()
- yield data
- else:
- for chunk in util.filechunkiter(sopener(name), limit=size):
- yield chunk
- # replace with "finally:" when support for python 2.4 has been dropped
- except Exception:
- sopener.mustaudit = oldaudit
- raise
- sopener.mustaudit = oldaudit
-
- return streamres(streamer(repo, entries, total_bytes))
+ try:
+ # LockError may be raised before the first result is yielded. Don't
+ # emit output until we're sure we got the lock successfully.
+ it = exchange.generatestreamclone(repo)
+ return streamres(getstream(it))
+ except error.LockError:
+ return '2\n'
@wireprotocommand('unbundle', 'heads')
def unbundle(repo, proto, heads):
@@ -861,7 +819,27 @@
for out in getattr(exc, '_bundle2salvagedoutput', ()):
bundler.addpart(out)
try:
- raise
+ try:
+ raise
+ except error.PushkeyFailed, exc:
+ # check client caps
+ remotecaps = getattr(exc, '_replycaps', None)
+ if (remotecaps is not None
+ and 'pushkey' not in remotecaps.get('error', ())):
+ # no support remote side, fallback to Abort handler.
+ raise
+ part = bundler.newpart('error:pushkey')
+ part.addparam('in-reply-to', exc.partid)
+ if exc.namespace is not None:
+ part.addparam('namespace', exc.namespace, mandatory=False)
+ if exc.key is not None:
+ part.addparam('key', exc.key, mandatory=False)
+ if exc.new is not None:
+ part.addparam('new', exc.new, mandatory=False)
+ if exc.old is not None:
+ part.addparam('old', exc.old, mandatory=False)
+ if exc.ret is not None:
+ part.addparam('ret', exc.ret, mandatory=False)
except error.BundleValueError, exc:
errpart = bundler.newpart('error:unsupportedcontent')
if exc.parttype is not None:
--- a/setup.py Sat Jun 13 20:14:22 2015 +0900
+++ b/setup.py Mon Jun 15 13:31:22 2015 -0500
@@ -5,8 +5,8 @@
# 'python setup.py --help' for more options
import sys, platform
-if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
- raise SystemExit("Mercurial requires Python 2.4 or later.")
+if getattr(sys, 'version_info', (0, 0, 0)) < (2, 6, 0, 'final'):
+ raise SystemExit("Mercurial requires Python 2.6 or later.")
if sys.version_info[0] >= 3:
def b(s):
@@ -106,25 +106,24 @@
tmpdir = tempfile.mkdtemp(prefix='hg-install-')
devnull = oldstderr = None
try:
- try:
- fname = os.path.join(tmpdir, 'funcname.c')
- f = open(fname, 'w')
- f.write('int main(void) {\n')
- f.write(' %s();\n' % funcname)
- f.write('}\n')
- f.close()
- # Redirect stderr to /dev/null to hide any error messages
- # from the compiler.
- # This will have to be changed if we ever have to check
- # for a function on Windows.
- devnull = open('/dev/null', 'w')
- oldstderr = os.dup(sys.stderr.fileno())
- os.dup2(devnull.fileno(), sys.stderr.fileno())
- objects = cc.compile([fname], output_dir=tmpdir)
- cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
- except Exception:
- return False
+ fname = os.path.join(tmpdir, 'funcname.c')
+ f = open(fname, 'w')
+ f.write('int main(void) {\n')
+ f.write(' %s();\n' % funcname)
+ f.write('}\n')
+ f.close()
+ # Redirect stderr to /dev/null to hide any error messages
+ # from the compiler.
+ # This will have to be changed if we ever have to check
+ # for a function on Windows.
+ devnull = open('/dev/null', 'w')
+ oldstderr = os.dup(sys.stderr.fileno())
+ os.dup2(devnull.fileno(), sys.stderr.fileno())
+ objects = cc.compile([fname], output_dir=tmpdir)
+ cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
return True
+ except Exception:
+ return False
finally:
if oldstderr is not None:
os.dup2(oldstderr, sys.stderr.fileno())
@@ -408,11 +407,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)
@@ -483,6 +483,11 @@
common_depends = ['mercurial/util.h']
+osutil_ldflags = []
+
+if sys.platform == 'darwin':
+ osutil_ldflags += ['-framework', 'ApplicationServices']
+
extmodules = [
Extension('mercurial.base85', ['mercurial/base85.c'],
depends=common_depends),
@@ -497,21 +502,11 @@
'mercurial/parsers.c',
'mercurial/pathencode.c'],
depends=common_depends),
+ Extension('mercurial.osutil', ['mercurial/osutil.c'],
+ extra_link_args=osutil_ldflags,
+ depends=common_depends),
]
-osutil_ldflags = []
-
-if sys.platform == 'darwin':
- osutil_ldflags += ['-framework', 'ApplicationServices']
-
-# disable osutil.c under windows + python 2.4 (issue1364)
-if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
- pymodules.append('mercurial.pure.osutil')
-else:
- extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
- extra_link_args=osutil_ldflags,
- depends=common_depends))
-
try:
from distutils import cygwinccompiler
@@ -562,6 +557,8 @@
'product_version':version}]
# sub command of 'build' because 'py2exe' does not handle sub_commands
build.sub_commands.insert(0, ('build_hgextindex', None))
+ # put dlls in sub directory so that they won't pollute PATH
+ extra['zipfile'] = 'lib/library.zip'
if os.name == 'nt':
# Windows binary file versions for exe/dll files must have the
@@ -572,6 +569,8 @@
version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
if version:
version = version[0]
+ if sys.version_info[0] == 3:
+ version = version.decode('utf-8')
xcode4 = (version.startswith('Xcode') and
StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
xcode51 = re.match(r'^Xcode\s+5\.1', version) is not None
--- a/tests/get-with-headers.py Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/get-with-headers.py Mon Jun 15 13:31:22 2015 -0500
@@ -33,8 +33,6 @@
sys.argv.remove('--json')
formatjson = True
-reasons = {'Not modified': 'Not Modified'} # python 2.4
-
tag = None
def request(host, path, show):
assert not path.startswith('/'), path
@@ -46,7 +44,7 @@
conn = httplib.HTTPConnection(host)
conn.request("GET", '/' + path, None, headers)
response = conn.getresponse()
- print response.status, reasons.get(response.reason, response.reason)
+ print response.status, response.reason
if show[:1] == ['-']:
show = sorted(h for h, v in response.getheaders()
if h.lower() not in show)
--- a/tests/heredoctest.py Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/heredoctest.py Mon Jun 15 13:31:22 2015 -0500
@@ -5,7 +5,7 @@
while lines:
l = lines.pop(0)
if l.startswith('SALT'):
- print l[:-1]
+ print(l[:-1])
elif l.startswith('>>> '):
snippet = l[4:]
while lines and lines[0].startswith('... '):
@@ -13,6 +13,6 @@
snippet += l[4:]
c = compile(snippet, '<heredoc>', 'single')
try:
- exec c in globalvars
- except Exception, inst:
- print repr(inst)
+ exec(c, globalvars)
+ except Exception as inst:
+ print(repr(inst))
--- a/tests/hghave.py Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/hghave.py Mon Jun 15 13:31:22 2015 -0500
@@ -225,12 +225,11 @@
os.close(fh)
name = tempfile.mktemp(dir='.', prefix=tempprefix)
try:
- try:
- util.oslink(fn, name)
- os.unlink(name)
- return True
- except OSError:
- return False
+ util.oslink(fn, name)
+ os.unlink(name)
+ return True
+ except OSError:
+ return False
finally:
os.unlink(fn)
@@ -282,10 +281,6 @@
except ImportError:
return False
-@check("python243", "python >= 2.4.3")
-def has_python243():
- return sys.version_info >= (2, 4, 3)
-
@check("json", "some json module available")
def has_json():
try:
@@ -320,6 +315,15 @@
except ImportError:
return False
+@check("sslcontext", "python >= 2.7.9 ssl")
+def has_sslcontext():
+ try:
+ import ssl
+ ssl.SSLContext
+ return True
+ except (ImportError, AttributeError):
+ return False
+
@check("defaultcacerts", "can verify SSL certs by system's CA certs store")
def has_defaultcacerts():
from mercurial import sslutil
--- a/tests/killdaemons.py Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/killdaemons.py Mon Jun 15 13:31:22 2015 -0500
@@ -64,7 +64,7 @@
os.kill(pid, 0)
logfn('# Daemon process %d is stuck - really killing it' % pid)
os.kill(pid, signal.SIGKILL)
- except OSError, err:
+ except OSError as err:
if err.errno != errno.ESRCH:
raise
@@ -87,5 +87,9 @@
pass
if __name__ == '__main__':
- path, = sys.argv[1:]
+ if len(sys.argv) > 1:
+ path, = sys.argv[1:]
+ else:
+ path = os.environ["DAEMON_PIDS"]
+
killdaemons(path)
--- a/tests/printenv.py Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/printenv.py Mon Jun 15 13:31:22 2015 -0500
@@ -1,3 +1,5 @@
+#!/usr/bin/env python
+#
# simple script to be used in hooks
#
# put something like this in the repo .hg/hgrc:
--- a/tests/run-tests.py Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/run-tests.py Mon Jun 15 13:31:22 2015 -0500
@@ -41,6 +41,8 @@
# completes fairly quickly, includes both shell and Python scripts, and
# includes some scripts that run daemon processes.)
+from __future__ import print_function
+
from distutils import version
import difflib
import errno
@@ -49,6 +51,7 @@
import shutil
import subprocess
import signal
+import socket
import sys
import tempfile
import time
@@ -56,10 +59,15 @@
import re
import threading
import killdaemons as killmod
-import Queue as queue
+try:
+ import Queue as queue
+except ImportError:
+ import queue
from xml.dom import minidom
import unittest
+osenvironb = getattr(os, 'environb', os.environ)
+
try:
import json
except ImportError:
@@ -70,14 +78,46 @@
processlock = threading.Lock()
-# subprocess._cleanup can race with any Popen.wait or Popen.poll on py24
-# http://bugs.python.org/issue1731717 for details. We shouldn't be producing
-# zombies but it's pretty harmless even if we do.
-if sys.version_info < (2, 5):
- subprocess._cleanup = lambda: None
+if sys.version_info > (3, 5, 0):
+ PYTHON3 = True
+ xrange = range # we use xrange in one place, and we'd rather not use range
+ def _bytespath(p):
+ return p.encode('utf-8')
+
+ def _strpath(p):
+ return p.decode('utf-8')
+
+elif sys.version_info >= (3, 0, 0):
+ print('%s is only supported on Python 3.5+ and 2.6-2.7, not %s' %
+ (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3])))
+ sys.exit(70) # EX_SOFTWARE from `man 3 sysexit`
+else:
+ PYTHON3 = False
+ # In python 2.x, path operations are generally done using
+ # bytestrings by default, so we don't have to do any extra
+ # fiddling there. We define the wrapper functions anyway just to
+ # help keep code consistent between platforms.
+ def _bytespath(p):
+ return p
+
+ _strpath = _bytespath
+
+# For Windows support
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 as exc:
+ if not exc.errno == errno.EADDRINUSE:
+ raise
+ return False
+
closefds = os.name == 'posix'
def Popen4(cmd, wd, timeout, env=None):
processlock.acquire()
@@ -104,10 +144,10 @@
return p
-PYTHON = sys.executable.replace('\\', '/')
-IMPL_PATH = 'PYTHONPATH'
+PYTHON = _bytespath(sys.executable.replace('\\', '/'))
+IMPL_PATH = b'PYTHONPATH'
if 'java' in sys.platform:
- IMPL_PATH = 'JYTHONPATH'
+ IMPL_PATH = b'JYTHONPATH'
defaults = {
'jobs': ('HGTEST_JOBS', 1),
@@ -122,15 +162,15 @@
try:
path = os.path.expanduser(os.path.expandvars(filename))
f = open(path, "rb")
- except IOError, err:
+ except IOError as err:
if err.errno != errno.ENOENT:
raise
if warn:
- print "warning: no such %s file: %s" % (listtype, filename)
+ print("warning: no such %s file: %s" % (listtype, filename))
continue
for line in f.readlines():
- line = line.split('#', 1)[0].strip()
+ line = line.split(b'#', 1)[0].strip()
if line:
entries[line] = filename
@@ -217,6 +257,8 @@
help='set the given config opt in the test hgrc')
parser.add_option('--random', action="store_true",
help='run tests in random order')
+ parser.add_option('--profile-runner', action='store_true',
+ help='run statprof on run-tests')
for option, (envvar, default) in defaults.items():
defaults[option] = type(default)(os.environ.get(envvar, default))
@@ -240,8 +282,8 @@
if not os.path.basename(options.with_hg) == 'hg':
sys.stderr.write('warning: --with-hg should specify an hg script\n')
if options.local:
- testdir = os.path.dirname(os.path.realpath(sys.argv[0]))
- hgbin = os.path.join(os.path.dirname(testdir), 'hg')
+ testdir = os.path.dirname(_bytespath(os.path.realpath(sys.argv[0])))
+ hgbin = os.path.join(os.path.dirname(testdir), b'hg')
if os.name != 'nt' and not os.access(hgbin, os.X_OK):
parser.error('--local specified, but %r not found or not executable'
% hgbin)
@@ -283,8 +325,9 @@
'warning: --timeout option ignored with --debug\n')
options.timeout = 0
if options.py3k_warnings:
- if sys.version_info[:2] < (2, 6) or sys.version_info[:2] >= (3, 0):
- parser.error('--py3k-warnings can only be used on Python 2.6+')
+ if PYTHON3:
+ parser.error(
+ '--py3k-warnings can only be used on Python 2.6 and 2.7')
if options.blacklist:
options.blacklist = parselistfiles(options.blacklist, 'blacklist')
if options.whitelist:
@@ -301,17 +344,22 @@
shutil.copy(src, dst)
os.remove(src)
+_unified_diff = difflib.unified_diff
+if PYTHON3:
+ import functools
+ _unified_diff = functools.partial(difflib.diff_bytes, difflib.unified_diff)
+
def getdiff(expected, output, ref, err):
servefail = False
lines = []
- for line in difflib.unified_diff(expected, output, ref, err):
- if line.startswith('+++') or line.startswith('---'):
- line = line.replace('\\', '/')
- if line.endswith(' \n'):
- line = line[:-2] + '\n'
+ for line in _unified_diff(expected, output, ref, err):
+ if line.startswith(b'+++') or line.startswith(b'---'):
+ line = line.replace(b'\\', b'/')
+ if line.endswith(b' \n'):
+ line = line[:-2] + b'\n'
lines.append(line)
if not servefail and line.startswith(
- '+ abort: child process failed to start'):
+ b'+ abort: child process failed to start'):
servefail = True
return servefail, lines
@@ -326,7 +374,7 @@
# Bytes that break XML even in a CDATA block: control characters 0-31
# sans \t, \n and \r
-CDATA_EVIL = re.compile(r"[\000-\010\013\014\016-\037]")
+CDATA_EVIL = re.compile(br"[\000-\010\013\014\016-\037]")
def cdatasafe(data):
"""Make a string safe to include in a CDATA block.
@@ -336,21 +384,20 @@
replaces illegal bytes with ? and adds a space between the ]] so
that it won't break the CDATA block.
"""
- return CDATA_EVIL.sub('?', data).replace(']]>', '] ]>')
+ return CDATA_EVIL.sub(b'?', data).replace(b']]>', b'] ]>')
def log(*msg):
"""Log something to stdout.
Arguments are strings to print.
"""
- iolock.acquire()
- if verbose:
- print verbose,
- for m in msg:
- print m,
- print
- sys.stdout.flush()
- iolock.release()
+ with iolock:
+ if verbose:
+ print(verbose, end=' ')
+ for m in msg:
+ print(m, end=' ')
+ print()
+ sys.stdout.flush()
def terminate(proc):
"""Terminate subprocess (with fallback for Python versions < 2.6)"""
@@ -408,11 +455,11 @@
shell is the shell to execute tests in.
"""
-
self.path = path
- self.name = os.path.basename(path)
+ self.bname = os.path.basename(path)
+ self.name = _strpath(self.bname)
self._testdir = os.path.dirname(path)
- self.errpath = os.path.join(self._testdir, '%s.err' % self.name)
+ self.errpath = os.path.join(self._testdir, b'%s.err' % self.bname)
self._threadtmp = tmpdir
self._keeptmpdir = keeptmpdir
@@ -421,7 +468,7 @@
self._startport = startport
self._extraconfigopts = extraconfigopts or []
self._py3kwarnings = py3kwarnings
- self._shell = shell
+ self._shell = _bytespath(shell)
self._aborted = False
self._daemonpids = []
@@ -442,6 +489,11 @@
else:
self._refout = []
+ # needed to get base class __repr__ running
+ @property
+ def _testMethodName(self):
+ return self.name
+
def __str__(self):
return self.name
@@ -457,7 +509,7 @@
try:
os.mkdir(self._threadtmp)
- except OSError, e:
+ except OSError as e:
if e.errno != errno.EEXIST:
raise
@@ -469,7 +521,7 @@
if os.path.exists(self.errpath):
try:
os.remove(self.errpath)
- except OSError, e:
+ except OSError as e:
# We might have raced another test to clean up a .err
# file, so ignore ENOENT when removing a previous .err
# file.
@@ -499,20 +551,20 @@
except KeyboardInterrupt:
self._aborted = True
raise
- except SkipTest, e:
+ except SkipTest as e:
result.addSkip(self, str(e))
# The base class will have already counted this as a
# test we "ran", but we want to exclude skipped tests
# from those we count towards those run.
result.testsRun -= 1
- except IgnoreTest, e:
+ except IgnoreTest as e:
result.addIgnore(self, str(e))
# As with skips, ignores also should be excluded from
# the number of tests executed.
result.testsRun -= 1
- except WarnTest, e:
+ except WarnTest as e:
result.addWarn(self, str(e))
- except self.failureException, e:
+ except self.failureException as e:
# This differs from unittest in that we don't capture
# the stack trace. This is for historical reasons and
# this decision could be revisited in the future,
@@ -620,7 +672,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.
@@ -638,20 +690,20 @@
occur.
"""
r = [
- (r':%s\b' % self._startport, ':$HGPORT'),
- (r':%s\b' % (self._startport + 1), ':$HGPORT1'),
- (r':%s\b' % (self._startport + 2), ':$HGPORT2'),
- (r'(?m)^(saved backup bundle to .*\.hg)( \(glob\))?$',
- r'\1 (glob)'),
+ (br':%d\b' % self._startport, b':$HGPORT'),
+ (br':%d\b' % (self._startport + 1), b':$HGPORT1'),
+ (br':%d\b' % (self._startport + 2), b':$HGPORT2'),
+ (br'(?m)^(saved backup bundle to .*\.hg)( \(glob\))?$',
+ br'\1 (glob)'),
]
if os.name == 'nt':
r.append(
- (''.join(c.isalpha() and '[%s%s]' % (c.lower(), c.upper()) or
- c in '/\\' and r'[/\\]' or c.isdigit() and c or '\\' + c
- for c in self._testtmp), '$TESTTMP'))
+ (b''.join(c.isalpha() and b'[%s%s]' % (c.lower(), c.upper()) or
+ c in b'/\\' and br'[/\\]' or c.isdigit() and c or b'\\' + c
+ for c in self._testtmp), b'$TESTTMP'))
else:
- r.append((re.escape(self._testtmp), '$TESTTMP'))
+ r.append((re.escape(self._testtmp), b'$TESTTMP'))
return r
@@ -663,8 +715,8 @@
env["HGPORT"] = str(self._startport)
env["HGPORT1"] = str(self._startport + 1)
env["HGPORT2"] = str(self._startport + 2)
- env["HGRCPATH"] = os.path.join(self._threadtmp, '.hgrc')
- env["DAEMON_PIDS"] = os.path.join(self._threadtmp, 'daemon.pids')
+ env["HGRCPATH"] = os.path.join(self._threadtmp, b'.hgrc')
+ env["DAEMON_PIDS"] = os.path.join(self._threadtmp, b'daemon.pids')
env["HGEDITOR"] = ('"' + sys.executable + '"'
+ ' -c "import sys; sys.exit(0)"')
env["HGMERGE"] = "internal:merge"
@@ -695,27 +747,27 @@
def _createhgrc(self, path):
"""Create an hgrc file for this test."""
hgrc = open(path, 'wb')
- hgrc.write('[ui]\n')
- hgrc.write('slash = True\n')
- hgrc.write('interactive = False\n')
- hgrc.write('mergemarkers = detailed\n')
- hgrc.write('promptecho = True\n')
- hgrc.write('[defaults]\n')
- hgrc.write('backout = -d "0 0"\n')
- hgrc.write('commit = -d "0 0"\n')
- hgrc.write('shelve = --date "0 0"\n')
- hgrc.write('tag = -d "0 0"\n')
- hgrc.write('[devel]\n')
- hgrc.write('all = true\n')
- hgrc.write('[largefiles]\n')
- hgrc.write('usercache = %s\n' %
- (os.path.join(self._testtmp, '.cache/largefiles')))
+ hgrc.write(b'[ui]\n')
+ hgrc.write(b'slash = True\n')
+ hgrc.write(b'interactive = False\n')
+ hgrc.write(b'mergemarkers = detailed\n')
+ hgrc.write(b'promptecho = True\n')
+ hgrc.write(b'[defaults]\n')
+ hgrc.write(b'backout = -d "0 0"\n')
+ hgrc.write(b'commit = -d "0 0"\n')
+ hgrc.write(b'shelve = --date "0 0"\n')
+ hgrc.write(b'tag = -d "0 0"\n')
+ hgrc.write(b'[devel]\n')
+ hgrc.write(b'all-warnings = true\n')
+ hgrc.write(b'[largefiles]\n')
+ hgrc.write(b'usercache = %s\n' %
+ (os.path.join(self._testtmp, b'.cache/largefiles')))
for opt in self._extraconfigopts:
section, key = opt.split('.', 1)
assert '=' in key, ('extra config opt %s must '
'have an = for assignment' % opt)
- hgrc.write('[%s]\n%s\n' % (section, key))
+ hgrc.write(b'[%s]\n%s\n' % (section, key))
hgrc.close()
def fail(self, msg):
@@ -777,11 +829,11 @@
@property
def refpath(self):
- return os.path.join(self._testdir, '%s.out' % self.name)
+ return os.path.join(self._testdir, b'%s.out' % self.bname)
def _run(self, env):
- py3kswitch = self._py3kwarnings and ' -3' or ''
- cmd = '%s%s "%s"' % (PYTHON, py3kswitch, self.path)
+ py3kswitch = self._py3kwarnings and b' -3' or b''
+ cmd = b'%s%s "%s"' % (PYTHON, py3kswitch, self.path)
vlog("# Running", cmd)
normalizenewlines = os.name == 'nt'
result = self._runcommand(cmd, env,
@@ -795,25 +847,29 @@
# Windows, but check-code.py wants a glob on these lines unconditionally. Don't
# warn if that is the case for anything matching these lines.
checkcodeglobpats = [
- re.compile(r'^pushing to \$TESTTMP/.*[^)]$'),
- re.compile(r'^moving \S+/.*[^)]$'),
- re.compile(r'^pulling from \$TESTTMP/.*[^)]$')
+ re.compile(br'^pushing to \$TESTTMP/.*[^)]$'),
+ re.compile(br'^moving \S+/.*[^)]$'),
+ re.compile(br'^pulling from \$TESTTMP/.*[^)]$')
]
+bchr = chr
+if PYTHON3:
+ bchr = lambda x: bytes([x])
+
class TTest(Test):
"""A "t test" is a test backed by a .t file."""
SKIPPED_PREFIX = 'skipped: '
FAILED_PREFIX = 'hghave check failed: '
- NEEDESCAPE = re.compile(r'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
+ NEEDESCAPE = re.compile(br'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
- ESCAPESUB = re.compile(r'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
- ESCAPEMAP = dict((chr(i), r'\x%02x' % i) for i in range(256))
- ESCAPEMAP.update({'\\': '\\\\', '\r': r'\r'})
+ ESCAPESUB = re.compile(br'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
+ ESCAPEMAP = dict((bchr(i), br'\x%02x' % i) for i in range(256))
+ ESCAPEMAP.update({b'\\': b'\\\\', b'\r': br'\r'})
@property
def refpath(self):
- return os.path.join(self._testdir, self.name)
+ return os.path.join(self._testdir, self.bname)
def _run(self, env):
f = open(self.path, 'rb')
@@ -823,13 +879,13 @@
salt, script, after, expected = self._parsetest(lines)
# Write out the generated script.
- fname = '%s.sh' % self._testtmp
+ fname = b'%s.sh' % self._testtmp
f = open(fname, 'wb')
for l in script:
f.write(l)
f.close()
- cmd = '%s "%s"' % (self._shell, fname)
+ cmd = b'%s "%s"' % (self._shell, fname)
vlog("# Running", cmd)
exitcode, output = self._runcommand(cmd, env)
@@ -846,16 +902,16 @@
def _hghave(self, reqs):
# TODO do something smarter when all other uses of hghave are gone.
- tdir = self._testdir.replace('\\', '/')
- proc = Popen4('%s -c "%s/hghave %s"' %
- (self._shell, tdir, ' '.join(reqs)),
+ tdir = self._testdir.replace(b'\\', b'/')
+ proc = Popen4(b'%s -c "%s/hghave %s"' %
+ (self._shell, tdir, b' '.join(reqs)),
self._testtmp, 0, self._getenv())
stdout, stderr = proc.communicate()
ret = proc.wait()
if wifexited(ret):
ret = os.WEXITSTATUS(ret)
if ret == 2:
- print stdout
+ print(stdout)
sys.exit(1)
return ret == 0
@@ -864,12 +920,12 @@
# We generate a shell script which outputs unique markers to line
# up script results with our source. These markers include input
# line number and the last return code.
- salt = "SALT" + str(time.time())
+ salt = b"SALT%d" % time.time()
def addsalt(line, inpython):
if inpython:
- script.append('%s %d 0\n' % (salt, line))
+ script.append(b'%s %d 0\n' % (salt, line))
else:
- script.append('echo %s %s $?\n' % (salt, line))
+ script.append(b'echo %s %d $?\n' % (salt, line))
script = []
@@ -892,42 +948,42 @@
inpython = False
if self._debug:
- script.append('set -x\n')
+ script.append(b'set -x\n')
if os.getenv('MSYSTEM'):
- script.append('alias pwd="pwd -W"\n')
+ script.append(b'alias pwd="pwd -W"\n')
for n, l in enumerate(lines):
- if not l.endswith('\n'):
- l += '\n'
- if l.startswith('#require'):
+ if not l.endswith(b'\n'):
+ l += b'\n'
+ if l.startswith(b'#require'):
lsplit = l.split()
- if len(lsplit) < 2 or lsplit[0] != '#require':
+ if len(lsplit) < 2 or lsplit[0] != b'#require':
after.setdefault(pos, []).append(' !!! invalid #require\n')
if not self._hghave(lsplit[1:]):
- script = ["exit 80\n"]
+ script = [b"exit 80\n"]
break
after.setdefault(pos, []).append(l)
- elif l.startswith('#if'):
+ elif l.startswith(b'#if'):
lsplit = l.split()
- if len(lsplit) < 2 or lsplit[0] != '#if':
+ if len(lsplit) < 2 or lsplit[0] != b'#if':
after.setdefault(pos, []).append(' !!! invalid #if\n')
if skipping is not None:
after.setdefault(pos, []).append(' !!! nested #if\n')
skipping = not self._hghave(lsplit[1:])
after.setdefault(pos, []).append(l)
- elif l.startswith('#else'):
+ elif l.startswith(b'#else'):
if skipping is None:
after.setdefault(pos, []).append(' !!! missing #if\n')
skipping = not skipping
after.setdefault(pos, []).append(l)
- elif l.startswith('#endif'):
+ elif l.startswith(b'#endif'):
if skipping is None:
after.setdefault(pos, []).append(' !!! missing #if\n')
skipping = None
after.setdefault(pos, []).append(l)
elif skipping:
after.setdefault(pos, []).append(l)
- elif l.startswith(' >>> '): # python inlines
+ elif l.startswith(b' >>> '): # python inlines
after.setdefault(pos, []).append(l)
prepos = pos
pos = n
@@ -935,39 +991,39 @@
# We've just entered a Python block. Add the header.
inpython = True
addsalt(prepos, False) # Make sure we report the exit code.
- script.append('%s -m heredoctest <<EOF\n' % PYTHON)
+ script.append(b'%s -m heredoctest <<EOF\n' % PYTHON)
addsalt(n, True)
script.append(l[2:])
- elif l.startswith(' ... '): # python inlines
+ elif l.startswith(b' ... '): # python inlines
after.setdefault(prepos, []).append(l)
script.append(l[2:])
- elif l.startswith(' $ '): # commands
+ elif l.startswith(b' $ '): # commands
if inpython:
- script.append('EOF\n')
+ script.append(b'EOF\n')
inpython = False
after.setdefault(pos, []).append(l)
prepos = pos
pos = n
addsalt(n, False)
cmd = l[4:].split()
- if len(cmd) == 2 and cmd[0] == 'cd':
- l = ' $ cd %s || exit 1\n' % cmd[1]
+ if len(cmd) == 2 and cmd[0] == b'cd':
+ l = b' $ cd %s || exit 1\n' % cmd[1]
script.append(l[4:])
- elif l.startswith(' > '): # continuations
+ elif l.startswith(b' > '): # continuations
after.setdefault(prepos, []).append(l)
script.append(l[4:])
- elif l.startswith(' '): # results
+ elif l.startswith(b' '): # results
# Queue up a list of expected results.
expected.setdefault(pos, []).append(l[2:])
else:
if inpython:
- script.append('EOF\n')
+ script.append(b'EOF\n')
inpython = False
# Non-command/result. Queue up for merged output.
after.setdefault(pos, []).append(l)
if inpython:
- script.append('EOF\n')
+ script.append(b'EOF\n')
if skipping is not None:
after.setdefault(pos, []).append(' !!! missing #endif\n')
addsalt(n + 1, False)
@@ -987,9 +1043,9 @@
if salt in l:
lout, lcmd = l.split(salt, 1)
- if lout:
- if not lout.endswith('\n'):
- lout += ' (no-eol)\n'
+ while lout:
+ if not lout.endswith(b'\n'):
+ lout += b' (no-eol)\n'
# Find the expected output at the current position.
el = None
@@ -1004,26 +1060,38 @@
elif r == '-glob':
lout = ''.join(el.rsplit(' (glob)', 1))
r = '' # Warn only this line.
+ elif r == "retry":
+ postout.append(b' ' + el)
+ continue
else:
log('\ninfo, unknown linematch result: %r\n' % r)
r = False
if r:
- postout.append(' ' + el)
+ postout.append(b' ' + el)
else:
if self.NEEDESCAPE(lout):
- lout = TTest._stringescape('%s (esc)\n' %
- lout.rstrip('\n'))
- postout.append(' ' + lout) # Let diff deal with it.
+ lout = TTest._stringescape(b'%s (esc)\n' %
+ lout.rstrip(b'\n'))
+ postout.append(b' ' + lout) # Let diff deal with it.
if r != '': # If line failed.
warnonly = 3 # for sure not
elif warnonly == 1: # Is "not yet" and line is warn only.
warnonly = 2 # Yes do warn.
+ break
+
+ # clean up any optional leftovers
+ while expected.get(pos, None):
+ el = expected[pos].pop(0)
+ if not el.endswith(" (?)\n"):
+ expected[pos].insert(0, el)
+ break
+ postout.append(b' ' + el)
if lcmd:
# Add on last return code.
ret = int(lcmd.split()[1])
if ret != 0:
- postout.append(' [%s]\n' % ret)
+ postout.append(b' [%d]\n' % ret)
if pos in after:
# Merge in non-active test bits.
postout += after.pop(pos)
@@ -1042,8 +1110,8 @@
try:
# use \Z to ensure that the regex matches to the end of the string
if os.name == 'nt':
- return re.match(el + r'\r?\n\Z', l)
- return re.match(el + r'\n\Z', l)
+ return re.match(el + br'\r?\n\Z', l)
+ return re.match(el + br'\n\Z', l)
except re.error:
# el is an invalid regex
return False
@@ -1052,51 +1120,59 @@
def globmatch(el, l):
# The only supported special characters are * and ? plus / which also
# matches \ on windows. Escaping of these characters is supported.
- if el + '\n' == l:
+ if el + b'\n' == l:
if os.altsep:
# matching on "/" is not needed for this line
for pat in checkcodeglobpats:
if pat.match(el):
return True
- return '-glob'
+ return b'-glob'
return True
i, n = 0, len(el)
- res = ''
+ res = b''
while i < n:
- c = el[i]
+ c = el[i:i + 1]
i += 1
- if c == '\\' and i < n and el[i] in '*?\\/':
+ if c == b'\\' and i < n and el[i:i + 1] in b'*?\\/':
res += el[i - 1:i + 1]
i += 1
- elif c == '*':
- res += '.*'
- elif c == '?':
- res += '.'
- elif c == '/' and os.altsep:
- res += '[/\\\\]'
+ elif c == b'*':
+ res += b'.*'
+ elif c == b'?':
+ res += b'.'
+ elif c == b'/' and os.altsep:
+ res += b'[/\\\\]'
else:
res += re.escape(c)
return TTest.rematch(res, l)
@staticmethod
def linematch(el, l):
+ retry = False
if el == l: # perfect match (fast)
return True
if el:
- if el.endswith(" (esc)\n"):
- el = el[:-7].decode('string-escape') + '\n'
- if el == l or os.name == 'nt' and el[:-1] + '\r\n' == l:
+ if el.endswith(" (?)\n"):
+ retry = "retry"
+ el = el[:-5] + "\n"
+ if el.endswith(b" (esc)\n"):
+ if PYTHON3:
+ el = el[:-7].decode('unicode_escape') + '\n'
+ el = el.encode('utf-8')
+ else:
+ el = el[:-7].decode('string-escape') + '\n'
+ if el == l or os.name == 'nt' and el[:-1] + b'\r\n' == l:
return True
- if el.endswith(" (re)\n"):
- return TTest.rematch(el[:-6], l)
- if el.endswith(" (glob)\n"):
+ if el.endswith(b" (re)\n"):
+ return TTest.rematch(el[:-6], l) or retry
+ if el.endswith(b" (glob)\n"):
# ignore '(glob)' added to l by 'replacements'
- if l.endswith(" (glob)\n"):
- l = l[:-8] + "\n"
+ if l.endswith(b" (glob)\n"):
+ l = l[:-8] + b"\n"
return TTest.globmatch(el[:-8], l)
- if os.altsep and l.replace('\\', '/') == el:
- return '+glob'
- return False
+ if os.altsep and l.replace(b'\\', b'/') == el:
+ return b'+glob'
+ return retry
@staticmethod
def parsehghaveoutput(lines):
@@ -1160,6 +1236,7 @@
self.warned = []
self.times = []
+ self._firststarttime = None
# Data stored for the benefit of generating xunit reports.
self.successes = []
self.faildata = {}
@@ -1170,18 +1247,16 @@
if self._options.first:
self.stop()
else:
- iolock.acquire()
- if not self._options.nodiff:
- self.stream.write('\nERROR: %s output changed\n' % test)
+ with iolock:
+ if not self._options.nodiff:
+ self.stream.write('\nERROR: %s output changed\n' % test)
- self.stream.write('!')
- self.stream.flush()
- iolock.release()
+ self.stream.write('!')
+ self.stream.flush()
def addSuccess(self, test):
- iolock.acquire()
- super(TestResult, self).addSuccess(test)
- iolock.release()
+ with iolock:
+ super(TestResult, self).addSuccess(test)
self.successes.append(test)
def addError(self, test, err):
@@ -1192,26 +1267,24 @@
# Polyfill.
def addSkip(self, test, reason):
self.skipped.append((test, reason))
- iolock.acquire()
- if self.showAll:
- self.stream.writeln('skipped %s' % reason)
- else:
- self.stream.write('s')
- self.stream.flush()
- iolock.release()
+ with iolock:
+ if self.showAll:
+ self.stream.writeln('skipped %s' % reason)
+ else:
+ self.stream.write('s')
+ self.stream.flush()
def addIgnore(self, test, reason):
self.ignored.append((test, reason))
- iolock.acquire()
- if self.showAll:
- self.stream.writeln('ignored %s' % reason)
- else:
- if reason != 'not retesting' and reason != "doesn't match keyword":
- self.stream.write('i')
+ with iolock:
+ if self.showAll:
+ self.stream.writeln('ignored %s' % reason)
else:
- self.testsRun += 1
- self.stream.flush()
- iolock.release()
+ if reason not in ('not retesting', "doesn't match keyword"):
+ self.stream.write('i')
+ else:
+ self.testsRun += 1
+ self.stream.flush()
def addWarn(self, test, reason):
self.warned.append((test, reason))
@@ -1219,13 +1292,12 @@
if self._options.first:
self.stop()
- iolock.acquire()
- if self.showAll:
- self.stream.writeln('warned %s' % reason)
- else:
- self.stream.write('~')
- self.stream.flush()
- iolock.release()
+ with iolock:
+ if self.showAll:
+ self.stream.writeln('warned %s' % reason)
+ else:
+ self.stream.write('~')
+ self.stream.flush()
def addOutputMismatch(self, test, ret, got, expected):
"""Record a mismatch in test output for a particular test."""
@@ -1239,38 +1311,45 @@
failed = False
lines = []
- iolock.acquire()
- if self._options.nodiff:
- pass
- elif self._options.view:
- os.system("%s %s %s" %
- (self._options.view, test.refpath, test.errpath))
- else:
- servefail, lines = getdiff(expected, got,
- test.refpath, test.errpath)
- if servefail:
- self.addFailure(
- test,
- 'server failed to start (HGPORT=%s)' % test._startport)
+ with iolock:
+ if self._options.nodiff:
+ pass
+ elif self._options.view:
+ v = self._options.view
+ if PYTHON3:
+ v = _bytespath(v)
+ os.system(b"%s %s %s" %
+ (v, test.refpath, test.errpath))
else:
- self.stream.write('\n')
- for line in lines:
- self.stream.write(line)
- self.stream.flush()
+ servefail, lines = getdiff(expected, got,
+ test.refpath, test.errpath)
+ if servefail:
+ self.addFailure(
+ test,
+ 'server failed to start (HGPORT=%s)' % test._startport)
+ else:
+ self.stream.write('\n')
+ for line in lines:
+ if PYTHON3:
+ self.stream.flush()
+ self.stream.buffer.write(line)
+ self.stream.buffer.flush()
+ else:
+ self.stream.write(line)
+ self.stream.flush()
- # handle interactive prompt without releasing iolock
- if self._options.interactive:
- self.stream.write('Accept this change? [n] ')
- answer = sys.stdin.readline().strip()
- if answer.lower() in ('y', 'yes'):
- if test.name.endswith('.t'):
- rename(test.errpath, test.path)
- else:
- rename(test.errpath, '%s.out' % test.path)
- accepted = True
- if not accepted and not failed:
- self.faildata[test.name] = ''.join(lines)
- iolock.release()
+ # handle interactive prompt without releasing iolock
+ if self._options.interactive:
+ self.stream.write('Accept this change? [n] ')
+ answer = sys.stdin.readline().strip()
+ if answer.lower() in ('y', 'yes'):
+ if test.name.endswith('.t'):
+ rename(test.errpath, test.path)
+ else:
+ rename(test.errpath, '%s.out' % test.path)
+ accepted = True
+ if not accepted and not failed:
+ self.faildata[test.name] = b''.join(lines)
return accepted
@@ -1282,6 +1361,8 @@
# This module has one limitation. It can only work for Linux user
# and not for Windows.
test.started = os.times()
+ if self._firststarttime is None: # thread racy but irrelevant
+ self._firststarttime = test.started[4]
def stopTest(self, test, interrupted=False):
super(TestResult, self).stopTest(test)
@@ -1290,14 +1371,19 @@
starttime = test.started
endtime = test.stopped
- self.times.append((test.name, endtime[2] - starttime[2],
- endtime[3] - starttime[3], endtime[4] - starttime[4]))
+ origin = self._firststarttime
+ 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
+ starttime[4] - origin, # start date in run context
+ endtime[4] - origin, # end date in run context
+ ))
if interrupted:
- iolock.acquire()
- self.stream.writeln('INTERRUPTED: %s (after %d seconds)' % (
- test.name, self.times[-1][3]))
- iolock.release()
+ with iolock:
+ self.stream.writeln('INTERRUPTED: %s (after %d seconds)' % (
+ test.name, self.times[-1][3]))
class TestSuite(unittest.TestSuite):
"""Custom unittest TestSuite that knows how to execute Mercurial tests."""
@@ -1352,14 +1438,14 @@
def get():
num_tests[0] += 1
if getattr(test, 'should_reload', False):
- return self._loadtest(test.name, num_tests[0])
+ return self._loadtest(test.bname, num_tests[0])
return test
if not os.path.exists(test.path):
result.addSkip(test, "Doesn't exist")
continue
if not (self._whitelist and test.name in self._whitelist):
- if self._blacklist and test.name in self._blacklist:
+ if self._blacklist and test.bname in self._blacklist:
result.addSkip(test, 'blacklisted')
continue
@@ -1369,7 +1455,7 @@
if self._keywords:
f = open(test.path, 'rb')
- t = f.read().lower() + test.name.lower()
+ t = f.read().lower() + test.bname.lower()
f.close()
ignored = False
for k in self._keywords.lower().split():
@@ -1460,101 +1546,92 @@
skipped = len(result.skipped)
ignored = len(result.ignored)
- iolock.acquire()
- self.stream.writeln('')
-
- if not self._runner.options.noskips:
- for test, msg in result.skipped:
- self.stream.writeln('Skipped %s: %s' % (test.name, msg))
- for test, msg in result.warned:
- self.stream.writeln('Warned %s: %s' % (test.name, msg))
- for test, msg in result.failures:
- self.stream.writeln('Failed %s: %s' % (test.name, msg))
- for test, msg in result.errors:
- self.stream.writeln('Errored %s: %s' % (test.name, msg))
+ with iolock:
+ self.stream.writeln('')
- 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)
- doc = minidom.Document()
- s = doc.createElement('testsuite')
- s.setAttribute('name', 'run-tests')
- s.setAttribute('tests', str(result.testsRun))
- s.setAttribute('errors', "0") # TODO
- s.setAttribute('failures', str(failed))
- s.setAttribute('skipped', str(skipped + ignored))
- doc.appendChild(s)
- for tc in result.successes:
- t = doc.createElement('testcase')
- t.setAttribute('name', tc.name)
- t.setAttribute('time', '%.3f' % timesd[tc.name])
- s.appendChild(t)
- for tc, err in sorted(result.faildata.iteritems()):
- t = doc.createElement('testcase')
- t.setAttribute('name', tc)
- t.setAttribute('time', '%.3f' % timesd[tc])
- # createCDATASection expects a unicode or it will convert
- # using default conversion rules, which will fail if
- # string isn't ASCII.
- err = cdatasafe(err).decode('utf-8', 'replace')
- cd = doc.createCDATASection(err)
- t.appendChild(cd)
- s.appendChild(t)
- xuf.write(doc.toprettyxml(indent=' ', encoding='utf-8'))
- finally:
- xuf.close()
+ if not self._runner.options.noskips:
+ for test, msg in result.skipped:
+ self.stream.writeln('Skipped %s: %s' % (test.name, msg))
+ for test, msg in result.warned:
+ self.stream.writeln('Warned %s: %s' % (test.name, msg))
+ for test, msg in result.failures:
+ self.stream.writeln('Failed %s: %s' % (test.name, msg))
+ for test, msg in result.errors:
+ self.stream.writeln('Errored %s: %s' % (test.name, msg))
- if self._runner.options.json:
- if json is None:
- raise ImportError("json module not installed")
- jsonpath = os.path.join(self._runner._testdir, 'report.json')
- fp = open(jsonpath, 'w')
- try:
- timesd = {}
- for test, cuser, csys, real in result.times:
- timesd[test] = (real, cuser, csys)
-
- 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
+ if self._runner.options.xunit:
+ xuf = open(self._runner.options.xunit, 'wb')
+ try:
+ timesd = dict((t[0], t[3]) for t in result.times)
+ doc = minidom.Document()
+ s = doc.createElement('testsuite')
+ s.setAttribute('name', 'run-tests')
+ s.setAttribute('tests', str(result.testsRun))
+ s.setAttribute('errors', "0") # TODO
+ s.setAttribute('failures', str(failed))
+ s.setAttribute('skipped', str(skipped + ignored))
+ doc.appendChild(s)
+ for tc in result.successes:
+ t = doc.createElement('testcase')
+ t.setAttribute('name', tc.name)
+ t.setAttribute('time', '%.3f' % timesd[tc.name])
+ s.appendChild(t)
+ for tc, err in sorted(result.faildata.items()):
+ t = doc.createElement('testcase')
+ t.setAttribute('name', tc)
+ t.setAttribute('time', '%.3f' % timesd[tc])
+ # createCDATASection expects a unicode or it will
+ # convert using default conversion rules, which will
+ # fail if string isn't ASCII.
+ err = cdatasafe(err).decode('utf-8', 'replace')
+ cd = doc.createCDATASection(err)
+ t.appendChild(cd)
+ s.appendChild(t)
+ xuf.write(doc.toprettyxml(indent=' ', encoding='utf-8'))
+ finally:
+ xuf.close()
- 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
-
- jsonout = json.dumps(outcome, sort_keys=True, indent=4)
- fp.writelines(("testreport =", jsonout))
- finally:
- fp.close()
+ if self._runner.options.json:
+ if json is None:
+ raise ImportError("json module not installed")
+ jsonpath = os.path.join(self._runner._testdir, 'report.json')
+ fp = open(jsonpath, 'w')
+ try:
+ timesd = {}
+ for tdata in result.times:
+ test = tdata[0]
+ timesd[test] = tdata[1:]
- self._runner._checkhglib('Tested')
+ outcome = {}
+ groups = [('success', ((tc, None)
+ for tc in result.successes)),
+ ('failure', result.failures),
+ ('skip', result.skipped)]
+ for res, testcases in groups:
+ for tc, __ in testcases:
+ tres = {'result': res,
+ 'time': ('%0.3f' % timesd[tc.name][2]),
+ 'cuser': ('%0.3f' % timesd[tc.name][0]),
+ 'csys': ('%0.3f' % timesd[tc.name][1]),
+ 'start': ('%0.3f' % timesd[tc.name][3]),
+ 'end': ('%0.3f' % timesd[tc.name][4])}
+ outcome[tc.name] = tres
+ jsonout = json.dumps(outcome, sort_keys=True, indent=4)
+ fp.writelines(("testreport =", jsonout))
+ finally:
+ fp.close()
- self.stream.writeln('# Ran %d tests, %d skipped, %d warned, %d failed.'
- % (result.testsRun,
- skipped + ignored, warned, failed))
- if failed:
- self.stream.writeln('python hash seed: %s' %
- os.environ['PYTHONHASHSEED'])
- if self._runner.options.time:
- self.printtimes(result.times)
+ self._runner._checkhglib('Tested')
- iolock.release()
+ self.stream.writeln(
+ '# Ran %d tests, %d skipped, %d warned, %d failed.'
+ % (result.testsRun,
+ skipped + ignored, warned, failed))
+ if failed:
+ self.stream.writeln('python hash seed: %s' %
+ os.environ['PYTHONHASHSEED'])
+ if self._runner.options.time:
+ self.printtimes(result.times)
return result
@@ -1562,11 +1639,13 @@
# iolock held by run
self.stream.writeln('# Producing time report')
times.sort(key=lambda t: (t[3]))
- 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:
- self.stream.writeln(cols % (cuser, csys, real, test))
+ cols = '%7.3f %7.3f %7.3f %7.3f %7.3f %s'
+ self.stream.writeln('%-7s %-7s %-7s %-7s %-7s %s' %
+ ('start', 'end', 'cuser', 'csys', 'real', 'Test'))
+ for tdata in times:
+ test = tdata[0]
+ cuser, csys, real, start, end = tdata[1:6]
+ self.stream.writeln(cols % (start, end, cuser, csys, real, test))
class TestRunner(object):
"""Holds context for executing tests.
@@ -1576,19 +1655,19 @@
# Programs required to run tests.
REQUIREDTOOLS = [
- os.path.basename(sys.executable),
- 'diff',
- 'grep',
- 'unzip',
- 'gunzip',
- 'bunzip2',
- 'sed',
+ os.path.basename(_bytespath(sys.executable)),
+ b'diff',
+ b'grep',
+ b'unzip',
+ b'gunzip',
+ b'bunzip2',
+ b'sed',
]
# Maps file extensions to test class.
TESTTYPES = [
- ('.py', PythonTest),
- ('.t', TTest),
+ (b'.py', PythonTest),
+ (b'.t', TTest),
]
def __init__(self):
@@ -1603,18 +1682,31 @@
self._coveragefile = None
self._createdfiles = []
self._hgpath = None
+ self._portoffset = 0
+ self._ports = {}
def run(self, args, parser=None):
"""Run the test suite."""
- oldmask = os.umask(022)
+ oldmask = os.umask(0o22)
try:
parser = parser or getparser()
options, args = parseargs(args, parser)
+ # positional arguments are paths to test files to run, so
+ # we make sure they're all bytestrings
+ args = [_bytespath(a) for a in args]
self.options = options
self._checktools()
tests = self.findtests(args)
- return self._run(tests)
+ if options.profile_runner:
+ import statprof
+ statprof.start()
+ result = self._run(tests)
+ if options.profile_runner:
+ statprof.stop()
+ statprof.display()
+ return result
+
finally:
os.umask(oldmask)
@@ -1623,22 +1715,26 @@
random.shuffle(tests)
else:
# keywords for slow tests
- slow = 'svn gendoc check-code-hg'.split()
+ slow = {b'svn': 10,
+ b'gendoc': 10,
+ b'check-code-hg': 100,
+ }
def sortkey(f):
# run largest tests first, as they tend to take the longest
try:
val = -os.stat(f).st_size
- except OSError, e:
+ except OSError as e:
if e.errno != errno.ENOENT:
raise
return -1e9 # file does not exist, tell early
- for kw in slow:
+ for kw, mul in slow.items():
if kw in f:
- val *= 10
+ val *= mul
return val
tests.sort(key=sortkey)
- self._testdir = os.environ['TESTDIR'] = os.getcwd()
+ self._testdir = osenvironb[b'TESTDIR'] = getattr(
+ os, 'getcwdb', os.getcwd)()
if 'PYTHONHASHSEED' not in os.environ:
# use a random python hash seed all the time
@@ -1647,12 +1743,12 @@
if self.options.tmpdir:
self.options.keep_tmpdir = True
- tmpdir = self.options.tmpdir
+ tmpdir = _bytespath(self.options.tmpdir)
if os.path.exists(tmpdir):
# Meaning of tmpdir has changed since 1.3: we used to create
# HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
# tmpdir already exists.
- print "error: temp dir %r already exists" % tmpdir
+ print("error: temp dir %r already exists" % tmpdir)
return 1
# Automatically removing tmpdir sounds convenient, but could
@@ -1666,15 +1762,24 @@
if os.name == 'nt':
# without this, we get the default temp dir location, but
# in all lowercase, which causes troubles with paths (issue3490)
- d = os.getenv('TMP')
- tmpdir = tempfile.mkdtemp('', 'hgtests.', d)
- self._hgtmp = os.environ['HGTMP'] = os.path.realpath(tmpdir)
+ d = osenvironb.get(b'TMP', None)
+ tmpdir = tempfile.mkdtemp(b'', b'hgtests.', d)
+
+ self._hgtmp = osenvironb[b'HGTMP'] = (
+ os.path.realpath(tmpdir))
if self.options.with_hg:
self._installdir = None
- self._bindir = os.path.dirname(os.path.realpath(
- self.options.with_hg))
- self._tmpbindir = os.path.join(self._hgtmp, 'install', 'bin')
+ whg = self.options.with_hg
+ # If --with-hg is not specified, we have bytes already,
+ # but if it was specified in python3 we get a str, so we
+ # have to encode it back into a bytes.
+ if PYTHON3:
+ if not isinstance(whg, bytes):
+ whg = _bytespath(whg)
+ self._bindir = os.path.dirname(os.path.realpath(whg))
+ assert isinstance(self._bindir, bytes)
+ self._tmpbindir = os.path.join(self._hgtmp, b'install', b'bin')
os.makedirs(self._tmpbindir)
# This looks redundant with how Python initializes sys.path from
@@ -1684,25 +1789,30 @@
# ... which means it's not really redundant at all.
self._pythondir = self._bindir
else:
- self._installdir = os.path.join(self._hgtmp, "install")
- self._bindir = os.environ["BINDIR"] = \
- os.path.join(self._installdir, "bin")
+ self._installdir = os.path.join(self._hgtmp, b"install")
+ self._bindir = osenvironb[b"BINDIR"] = \
+ os.path.join(self._installdir, b"bin")
self._tmpbindir = self._bindir
- self._pythondir = os.path.join(self._installdir, "lib", "python")
+ self._pythondir = os.path.join(self._installdir, b"lib", b"python")
- os.environ["BINDIR"] = self._bindir
- os.environ["PYTHON"] = PYTHON
+ osenvironb[b"BINDIR"] = self._bindir
+ osenvironb[b"PYTHON"] = PYTHON
- runtestdir = os.path.abspath(os.path.dirname(__file__))
- path = [self._bindir, runtestdir] + os.environ["PATH"].split(os.pathsep)
+ fileb = _bytespath(__file__)
+ runtestdir = os.path.abspath(os.path.dirname(fileb))
+ if PYTHON3:
+ sepb = _bytespath(os.pathsep)
+ else:
+ sepb = os.pathsep
+ path = [self._bindir, runtestdir] + osenvironb[b"PATH"].split(sepb)
if os.path.islink(__file__):
# test helper will likely be at the end of the symlink
- realfile = os.path.realpath(__file__)
+ realfile = os.path.realpath(fileb)
realdir = os.path.abspath(os.path.dirname(realfile))
path.insert(2, realdir)
if self._tmpbindir != self._bindir:
path = [self._tmpbindir] + path
- os.environ["PATH"] = os.pathsep.join(path)
+ osenvironb[b"PATH"] = sepb.join(path)
# Include TESTDIR in PYTHONPATH so that out-of-tree extensions
# can run .../tests/run-tests.py test-foo where test-foo
@@ -1713,20 +1823,20 @@
# it, in case external libraries are only available via current
# PYTHONPATH. (In particular, the Subversion bindings on OS X
# are in /opt/subversion.)
- oldpypath = os.environ.get(IMPL_PATH)
+ oldpypath = osenvironb.get(IMPL_PATH)
if oldpypath:
pypath.append(oldpypath)
- os.environ[IMPL_PATH] = os.pathsep.join(pypath)
+ osenvironb[IMPL_PATH] = sepb.join(pypath)
if self.options.pure:
os.environ["HGTEST_RUN_TESTS_PURE"] = "--pure"
- self._coveragefile = os.path.join(self._testdir, '.coverage')
+ self._coveragefile = os.path.join(self._testdir, b'.coverage')
vlog("# Using TESTDIR", self._testdir)
vlog("# Using HGTMP", self._hgtmp)
vlog("# Using PATH", os.environ["PATH"])
- vlog("# Using", IMPL_PATH, os.environ[IMPL_PATH])
+ vlog("# Using", IMPL_PATH, osenvironb[IMPL_PATH])
try:
return self._runtests(tests) or 0
@@ -1745,13 +1855,13 @@
proc = Popen4('hg st --rev "%s" -man0 .' %
self.options.changed, None, 0)
stdout, stderr = proc.communicate()
- args = stdout.strip('\0').split('\0')
+ args = stdout.strip(b'\0').split(b'\0')
else:
- args = os.listdir('.')
+ args = os.listdir(b'.')
return [t for t in args
- if os.path.basename(t).startswith('test-')
- and (t.endswith('.py') or t.endswith('.t'))]
+ if os.path.basename(t).startswith(b'test-')
+ and (t.endswith(b'.py') or t.endswith(b'.t'))]
def _runtests(self, tests):
try:
@@ -1768,20 +1878,23 @@
break
tests.pop(0)
if not tests:
- print "running all tests"
+ print("running all tests")
tests = orig
tests = [self._gettest(t, i) for i, t in enumerate(tests)]
failed = False
warned = False
+ kws = self.options.keywords
+ if kws is not None and PYTHON3:
+ kws = kws.encode('utf-8')
suite = TestSuite(self._testdir,
jobs=self.options.jobs,
whitelist=self.options.whitelisted,
blacklist=self.options.blacklist,
retest=self.options.retest,
- keywords=self.options.keywords,
+ keywords=kws,
loop=self.options.loop,
runs_per_test=self.options.runs_per_test,
tests=tests, loadtest=self._gettest)
@@ -1800,13 +1913,31 @@
self._outputcoverage()
except KeyboardInterrupt:
failed = True
- print "\ninterrupted!"
+ print("\ninterrupted!")
if failed:
return 1
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.
@@ -1822,13 +1953,13 @@
break
refpath = os.path.join(self._testdir, test)
- tmpdir = os.path.join(self._hgtmp, 'child%d' % count)
+ tmpdir = os.path.join(self._hgtmp, b'child%d' % count)
t = testcls(refpath, tmpdir,
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)
@@ -1852,7 +1983,7 @@
def _usecorrectpython(self):
"""Configure the environment to use the appropriate Python in tests."""
# Tests must use the same interpreter as us or bad things will happen.
- pyexename = sys.platform == 'win32' and 'python.exe' or 'python'
+ pyexename = sys.platform == 'win32' and b'python.exe' or b'python'
if getattr(os, 'symlink', None):
vlog("# Making python executable in test path a symlink to '%s'" %
sys.executable)
@@ -1861,14 +1992,14 @@
if os.readlink(mypython) == sys.executable:
return
os.unlink(mypython)
- except OSError, err:
+ except OSError as err:
if err.errno != errno.ENOENT:
raise
if self._findprogram(pyexename) != sys.executable:
try:
os.symlink(sys.executable, mypython)
self._createdfiles.append(mypython)
- except OSError, err:
+ except OSError as err:
# child processes may race, which is harmless
if err.errno != errno.EEXIST:
raise
@@ -1881,7 +2012,7 @@
path.remove(exedir)
os.environ['PATH'] = os.pathsep.join([exedir] + path)
if not self._findprogram(pyexename):
- print "WARNING: Cannot find %s in search path" % pyexename
+ print("WARNING: Cannot find %s in search path" % pyexename)
def _installhg(self):
"""Install hg into the test environment.
@@ -1889,47 +2020,51 @@
This will also configure hg with the appropriate testing settings.
"""
vlog("# Performing temporary installation of HG")
- installerrs = os.path.join("tests", "install.err")
+ installerrs = os.path.join(b"tests", b"install.err")
compiler = ''
if self.options.compiler:
compiler = '--compiler ' + self.options.compiler
if self.options.pure:
- pure = "--pure"
+ pure = b"--pure"
else:
- pure = ""
+ pure = b""
py3 = ''
- if sys.version_info[0] == 3:
- py3 = '--c2to3'
# Run installer in hg root
script = os.path.realpath(sys.argv[0])
+ exe = sys.executable
+ if PYTHON3:
+ py3 = b'--c2to3'
+ compiler = _bytespath(compiler)
+ script = _bytespath(script)
+ exe = _bytespath(exe)
hgroot = os.path.dirname(os.path.dirname(script))
self._hgroot = hgroot
os.chdir(hgroot)
- nohome = '--home=""'
+ nohome = b'--home=""'
if os.name == 'nt':
# The --home="" trick works only on OS where os.sep == '/'
# because of a distutils convert_path() fast-path. Avoid it at
# least on Windows for now, deal with .pydistutils.cfg bugs
# when they happen.
- nohome = ''
- cmd = ('%(exe)s setup.py %(py3)s %(pure)s clean --all'
- ' build %(compiler)s --build-base="%(base)s"'
- ' install --force --prefix="%(prefix)s"'
- ' --install-lib="%(libdir)s"'
- ' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
- % {'exe': sys.executable, 'py3': py3, 'pure': pure,
- 'compiler': compiler,
- 'base': os.path.join(self._hgtmp, "build"),
- 'prefix': self._installdir, 'libdir': self._pythondir,
- 'bindir': self._bindir,
- 'nohome': nohome, 'logfile': installerrs})
+ nohome = b''
+ cmd = (b'%(exe)s setup.py %(py3)s %(pure)s clean --all'
+ b' build %(compiler)s --build-base="%(base)s"'
+ b' install --force --prefix="%(prefix)s"'
+ b' --install-lib="%(libdir)s"'
+ b' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
+ % {b'exe': exe, b'py3': py3, b'pure': pure,
+ b'compiler': compiler,
+ b'base': os.path.join(self._hgtmp, b"build"),
+ b'prefix': self._installdir, b'libdir': self._pythondir,
+ b'bindir': self._bindir,
+ b'nohome': nohome, b'logfile': installerrs})
# setuptools requires install directories to exist.
def makedirs(p):
try:
os.makedirs(p)
- except OSError, e:
+ except OSError as e:
if e.errno != errno.EEXIST:
raise
makedirs(self._pythondir)
@@ -1942,7 +2077,10 @@
else:
f = open(installerrs, 'rb')
for line in f:
- sys.stdout.write(line)
+ if PYTHON3:
+ sys.stdout.buffer.write(line)
+ else:
+ sys.stdout.write(line)
f.close()
sys.exit(1)
os.chdir(self._testdir)
@@ -1960,21 +2098,21 @@
f.write(line + '\n')
f.close()
- hgbat = os.path.join(self._bindir, 'hg.bat')
+ hgbat = os.path.join(self._bindir, b'hg.bat')
if os.path.isfile(hgbat):
# hg.bat expects to be put in bin/scripts while run-tests.py
# installation layout put it in bin/ directly. Fix it
f = open(hgbat, 'rb')
data = f.read()
f.close()
- if '"%~dp0..\python" "%~dp0hg" %*' in data:
- data = data.replace('"%~dp0..\python" "%~dp0hg" %*',
- '"%~dp0python" "%~dp0hg" %*')
+ if b'"%~dp0..\python" "%~dp0hg" %*' in data:
+ data = data.replace(b'"%~dp0..\python" "%~dp0hg" %*',
+ b'"%~dp0python" "%~dp0hg" %*')
f = open(hgbat, 'wb')
f.write(data)
f.close()
else:
- print 'WARNING: cannot fix hg.bat reference to python.exe'
+ print('WARNING: cannot fix hg.bat reference to python.exe')
if self.options.anycoverage:
custom = os.path.join(self._testdir, 'sitecustomize.py')
@@ -1987,7 +2125,7 @@
covdir = os.path.join(self._installdir, '..', 'coverage')
try:
os.mkdir(covdir)
- except OSError, e:
+ except OSError as e:
if e.errno != errno.EEXIST:
raise
@@ -2001,7 +2139,7 @@
# The pythondir has been inferred from --with-hg flag.
# We cannot expect anything sensible here.
return
- expecthg = os.path.join(self._pythondir, 'mercurial')
+ expecthg = os.path.join(self._pythondir, b'mercurial')
actualhg = self._gethgpath()
if os.path.abspath(actualhg) != os.path.abspath(expecthg):
sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
@@ -2013,10 +2151,13 @@
if self._hgpath is not None:
return self._hgpath
- cmd = '%s -c "import mercurial; print (mercurial.__path__[0])"'
- pipe = os.popen(cmd % PYTHON)
+ cmd = b'%s -c "import mercurial; print (mercurial.__path__[0])"'
+ cmd = cmd % PYTHON
+ if PYTHON3:
+ cmd = _strpath(cmd)
+ pipe = os.popen(cmd)
try:
- self._hgpath = pipe.read().strip()
+ self._hgpath = _bytespath(pipe.read().strip())
finally:
pipe.close()
@@ -2052,7 +2193,9 @@
def _findprogram(self, program):
"""Search PATH for a executable program"""
- for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
+ dpb = _bytespath(os.defpath)
+ sepb = _bytespath(os.pathsep)
+ for p in osenvironb.get(b'PATH', dpb).split(sepb):
name = os.path.join(p, program)
if os.name == 'nt' or os.access(name, os.X_OK):
return name
@@ -2067,7 +2210,7 @@
if found:
vlog("# Found prerequisite", p, "at", found)
else:
- print "WARNING: Did not find prerequisite tool: %s " % p
+ print("WARNING: Did not find prerequisite tool: %s " % p)
if __name__ == '__main__':
runner = TestRunner()
--- a/tests/test-acl.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-acl.t Mon Jun 15 13:31:22 2015 -0500
@@ -44,6 +44,13 @@
> EOF
> }
+ $ cat << EOF >> $HGRCPATH
+ > [experimental]
+ > # drop me once bundle2 is the default,
+ > # added to get test change early.
+ > bundle2-exp = True
+ > EOF
+
$ hg init a
$ cd a
$ mkdir foo foo/Bar quux
@@ -91,37 +98,40 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
+ bundle2-input-part: total payload size 1606
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-bundle: 3 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 2 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 1 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 0 (undo push)
0:6675d58eff77
@@ -151,39 +161,42 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: changes have source "push" - skipping
+ bundle2-input-part: total payload size 1606
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-bundle: 3 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 2 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 1 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 0 (undo push)
0:6675d58eff77
@@ -214,33 +227,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "fred"
@@ -254,9 +260,19 @@
acl: path access granted: "f9cafe1212c8"
acl: branch access granted: "911600dab2ae" on branch "default"
acl: path access granted: "911600dab2ae"
+ bundle2-input-part: total payload size 1606
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-bundle: 3 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 2 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 1 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 0 (undo push)
0:6675d58eff77
@@ -287,33 +303,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "fred"
@@ -323,6 +332,8 @@
acl: acl.deny not enabled
acl: branch access granted: "ef1ea85a6374" on branch "default"
error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
@@ -357,33 +368,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "fred"
@@ -397,6 +401,8 @@
acl: path access granted: "f9cafe1212c8"
acl: branch access granted: "911600dab2ae" on branch "default"
error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
@@ -432,33 +438,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "barney"
@@ -468,6 +467,8 @@
acl: acl.deny enabled, 0 entries for user barney
acl: branch access granted: "ef1ea85a6374" on branch "default"
error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
@@ -504,33 +505,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "fred"
@@ -544,6 +538,8 @@
acl: path access granted: "f9cafe1212c8"
acl: branch access granted: "911600dab2ae" on branch "default"
error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
@@ -581,33 +577,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "fred"
@@ -619,6 +608,8 @@
acl: path access granted: "ef1ea85a6374"
acl: branch access granted: "f9cafe1212c8" on branch "default"
error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
@@ -655,33 +646,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "barney"
@@ -691,6 +675,8 @@
acl: acl.deny enabled, 0 entries for user barney
acl: branch access granted: "ef1ea85a6374" on branch "default"
error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
@@ -731,33 +717,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "barney"
@@ -771,9 +750,19 @@
acl: path access granted: "f9cafe1212c8"
acl: branch access granted: "911600dab2ae" on branch "default"
acl: path access granted: "911600dab2ae"
+ bundle2-input-part: total payload size 1606
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-bundle: 3 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 2 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 1 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 0 (undo push)
0:6675d58eff77
@@ -811,33 +800,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "wilma"
@@ -851,6 +833,8 @@
acl: path access granted: "f9cafe1212c8"
acl: branch access granted: "911600dab2ae" on branch "default"
error: pretxnchangegroup.acl hook failed: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
@@ -894,37 +878,32 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "barney"
error: pretxnchangegroup.acl hook raised an exception: [Errno 2] No such file or directory: '../acl.config'
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: No such file or directory: ../acl.config
@@ -972,33 +951,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "betty"
@@ -1012,6 +984,8 @@
acl: path access granted: "f9cafe1212c8"
acl: branch access granted: "911600dab2ae" on branch "default"
error: pretxnchangegroup.acl hook failed: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
@@ -1061,33 +1035,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "barney"
@@ -1101,9 +1068,19 @@
acl: path access granted: "f9cafe1212c8"
acl: branch access granted: "911600dab2ae" on branch "default"
acl: path access granted: "911600dab2ae"
+ bundle2-input-part: total payload size 1606
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-bundle: 3 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 2 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 1 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 0 (undo push)
0:6675d58eff77
@@ -1144,33 +1121,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "fred"
@@ -1184,9 +1154,19 @@
acl: path access granted: "f9cafe1212c8"
acl: branch access granted: "911600dab2ae" on branch "default"
acl: path access granted: "911600dab2ae"
+ bundle2-input-part: total payload size 1606
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-bundle: 3 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 2 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 1 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 0 (undo push)
0:6675d58eff77
@@ -1223,33 +1203,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "fred"
@@ -1261,6 +1234,8 @@
acl: path access granted: "ef1ea85a6374"
acl: branch access granted: "f9cafe1212c8" on branch "default"
error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
@@ -1304,33 +1279,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "fred"
@@ -1345,9 +1313,19 @@
acl: path access granted: "f9cafe1212c8"
acl: branch access granted: "911600dab2ae" on branch "default"
acl: path access granted: "911600dab2ae"
+ bundle2-input-part: total payload size 1606
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-bundle: 3 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 2 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 1 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 0 (undo push)
0:6675d58eff77
@@ -1384,33 +1362,26 @@
ef1ea85a6374b77d6da9dcda9541f498f2d17df7
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: foo/Bar/file.txt 1/3 files (33.33%)
- bundling: foo/file.txt 2/3 files (66.67%)
- bundling: quux/file.py 3/3 files (100.00%)
+ bundle2-output-bundle: "HG20", 4 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
adding manifests
- manifests: 1/3 chunks (33.33%)
- manifests: 2/3 chunks (66.67%)
- manifests: 3/3 chunks (100.00%)
adding file changes
adding foo/Bar/file.txt revisions
- files: 1/3 chunks (33.33%)
adding foo/file.txt revisions
- files: 2/3 chunks (66.67%)
adding quux/file.py revisions
- files: 3/3 chunks (100.00%)
added 3 changesets with 3 changes to 3 files
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "fred"
@@ -1424,6 +1395,8 @@
acl: path access granted: "ef1ea85a6374"
acl: branch access granted: "f9cafe1212c8" on branch "default"
error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
+ bundle2-input-part: total payload size 1606
+ bundle2-input-bundle: 3 parts total
transaction abort!
rollback completed
abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
@@ -1504,41 +1477,29 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
- bundling: 1/4 changesets (25.00%)
- bundling: 2/4 changesets (50.00%)
- bundling: 3/4 changesets (75.00%)
- bundling: 4/4 changesets (100.00%)
- bundling: 1/4 manifests (25.00%)
- bundling: 2/4 manifests (50.00%)
- bundling: 3/4 manifests (75.00%)
- bundling: 4/4 manifests (100.00%)
- bundling: abc.txt 1/4 files (25.00%)
- bundling: foo/Bar/file.txt 2/4 files (50.00%)
- bundling: foo/file.txt 3/4 files (75.00%)
- bundling: quux/file.py 4/4 files (100.00%)
+ bundle2-output-bundle: "HG20", 5 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
- changesets: 4 chunks
add changeset e8fc755d4d82
adding manifests
- manifests: 1/4 chunks (25.00%)
- manifests: 2/4 chunks (50.00%)
- manifests: 3/4 chunks (75.00%)
- manifests: 4/4 chunks (100.00%)
adding file changes
adding abc.txt revisions
- files: 1/4 chunks (25.00%)
adding foo/Bar/file.txt revisions
- files: 2/4 chunks (50.00%)
adding foo/file.txt revisions
- files: 3/4 chunks (75.00%)
adding quux/file.py revisions
- files: 4/4 chunks (100.00%)
added 4 changesets with 4 changes to 4 files (+1 heads)
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "astro"
@@ -1554,9 +1515,23 @@
acl: path access granted: "911600dab2ae"
acl: branch access granted: "e8fc755d4d82" on branch "foobar"
acl: path access granted: "e8fc755d4d82"
+ bundle2-input-part: total payload size 2101
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
+ bundle2-input-bundle: 4 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 3 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 2 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 2 (undo push)
2:fb35475503ef
@@ -1590,41 +1565,29 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
- bundling: 1/4 changesets (25.00%)
- bundling: 2/4 changesets (50.00%)
- bundling: 3/4 changesets (75.00%)
- bundling: 4/4 changesets (100.00%)
- bundling: 1/4 manifests (25.00%)
- bundling: 2/4 manifests (50.00%)
- bundling: 3/4 manifests (75.00%)
- bundling: 4/4 manifests (100.00%)
- bundling: abc.txt 1/4 files (25.00%)
- bundling: foo/Bar/file.txt 2/4 files (50.00%)
- bundling: foo/file.txt 3/4 files (75.00%)
- bundling: quux/file.py 4/4 files (100.00%)
+ bundle2-output-bundle: "HG20", 5 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
- changesets: 4 chunks
add changeset e8fc755d4d82
adding manifests
- manifests: 1/4 chunks (25.00%)
- manifests: 2/4 chunks (50.00%)
- manifests: 3/4 chunks (75.00%)
- manifests: 4/4 chunks (100.00%)
adding file changes
adding abc.txt revisions
- files: 1/4 chunks (25.00%)
adding foo/Bar/file.txt revisions
- files: 2/4 chunks (50.00%)
adding foo/file.txt revisions
- files: 3/4 chunks (75.00%)
adding quux/file.py revisions
- files: 4/4 chunks (100.00%)
added 4 changesets with 4 changes to 4 files (+1 heads)
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "astro"
@@ -1639,6 +1602,8 @@
acl: branch access granted: "911600dab2ae" on branch "default"
acl: path access granted: "911600dab2ae"
error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
+ bundle2-input-part: total payload size 2101
+ bundle2-input-bundle: 4 parts total
transaction abort!
rollback completed
abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
@@ -1674,41 +1639,29 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
- bundling: 1/4 changesets (25.00%)
- bundling: 2/4 changesets (50.00%)
- bundling: 3/4 changesets (75.00%)
- bundling: 4/4 changesets (100.00%)
- bundling: 1/4 manifests (25.00%)
- bundling: 2/4 manifests (50.00%)
- bundling: 3/4 manifests (75.00%)
- bundling: 4/4 manifests (100.00%)
- bundling: abc.txt 1/4 files (25.00%)
- bundling: foo/Bar/file.txt 2/4 files (50.00%)
- bundling: foo/file.txt 3/4 files (75.00%)
- bundling: quux/file.py 4/4 files (100.00%)
+ bundle2-output-bundle: "HG20", 5 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
- changesets: 4 chunks
add changeset e8fc755d4d82
adding manifests
- manifests: 1/4 chunks (25.00%)
- manifests: 2/4 chunks (50.00%)
- manifests: 3/4 chunks (75.00%)
- manifests: 4/4 chunks (100.00%)
adding file changes
adding abc.txt revisions
- files: 1/4 chunks (25.00%)
adding foo/Bar/file.txt revisions
- files: 2/4 chunks (50.00%)
adding foo/file.txt revisions
- files: 3/4 chunks (75.00%)
adding quux/file.py revisions
- files: 4/4 chunks (100.00%)
added 4 changesets with 4 changes to 4 files (+1 heads)
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "astro"
@@ -1717,6 +1670,8 @@
acl: acl.allow not enabled
acl: acl.deny not enabled
error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
+ bundle2-input-part: total payload size 2101
+ bundle2-input-bundle: 4 parts total
transaction abort!
rollback completed
abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
@@ -1754,41 +1709,29 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
- bundling: 1/4 changesets (25.00%)
- bundling: 2/4 changesets (50.00%)
- bundling: 3/4 changesets (75.00%)
- bundling: 4/4 changesets (100.00%)
- bundling: 1/4 manifests (25.00%)
- bundling: 2/4 manifests (50.00%)
- bundling: 3/4 manifests (75.00%)
- bundling: 4/4 manifests (100.00%)
- bundling: abc.txt 1/4 files (25.00%)
- bundling: foo/Bar/file.txt 2/4 files (50.00%)
- bundling: foo/file.txt 3/4 files (75.00%)
- bundling: quux/file.py 4/4 files (100.00%)
+ bundle2-output-bundle: "HG20", 5 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
- changesets: 4 chunks
add changeset e8fc755d4d82
adding manifests
- manifests: 1/4 chunks (25.00%)
- manifests: 2/4 chunks (50.00%)
- manifests: 3/4 chunks (75.00%)
- manifests: 4/4 chunks (100.00%)
adding file changes
adding abc.txt revisions
- files: 1/4 chunks (25.00%)
adding foo/Bar/file.txt revisions
- files: 2/4 chunks (50.00%)
adding foo/file.txt revisions
- files: 3/4 chunks (75.00%)
adding quux/file.py revisions
- files: 4/4 chunks (100.00%)
added 4 changesets with 4 changes to 4 files (+1 heads)
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "astro"
@@ -1797,6 +1740,8 @@
acl: acl.allow not enabled
acl: acl.deny not enabled
error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
+ bundle2-input-part: total payload size 2101
+ bundle2-input-bundle: 4 parts total
transaction abort!
rollback completed
abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
@@ -1828,41 +1773,29 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
- bundling: 1/4 changesets (25.00%)
- bundling: 2/4 changesets (50.00%)
- bundling: 3/4 changesets (75.00%)
- bundling: 4/4 changesets (100.00%)
- bundling: 1/4 manifests (25.00%)
- bundling: 2/4 manifests (50.00%)
- bundling: 3/4 manifests (75.00%)
- bundling: 4/4 manifests (100.00%)
- bundling: abc.txt 1/4 files (25.00%)
- bundling: foo/Bar/file.txt 2/4 files (50.00%)
- bundling: foo/file.txt 3/4 files (75.00%)
- bundling: quux/file.py 4/4 files (100.00%)
+ bundle2-output-bundle: "HG20", 5 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
- changesets: 4 chunks
add changeset e8fc755d4d82
adding manifests
- manifests: 1/4 chunks (25.00%)
- manifests: 2/4 chunks (50.00%)
- manifests: 3/4 chunks (75.00%)
- manifests: 4/4 chunks (100.00%)
adding file changes
adding abc.txt revisions
- files: 1/4 chunks (25.00%)
adding foo/Bar/file.txt revisions
- files: 2/4 chunks (50.00%)
adding foo/file.txt revisions
- files: 3/4 chunks (75.00%)
adding quux/file.py revisions
- files: 4/4 chunks (100.00%)
added 4 changesets with 4 changes to 4 files (+1 heads)
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "george"
@@ -1878,9 +1811,23 @@
acl: path access granted: "911600dab2ae"
acl: branch access granted: "e8fc755d4d82" on branch "foobar"
acl: path access granted: "e8fc755d4d82"
+ bundle2-input-part: total payload size 2101
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
+ bundle2-input-bundle: 4 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 3 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 2 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 2 (undo push)
2:fb35475503ef
@@ -1919,41 +1866,29 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
- bundling: 1/4 changesets (25.00%)
- bundling: 2/4 changesets (50.00%)
- bundling: 3/4 changesets (75.00%)
- bundling: 4/4 changesets (100.00%)
- bundling: 1/4 manifests (25.00%)
- bundling: 2/4 manifests (50.00%)
- bundling: 3/4 manifests (75.00%)
- bundling: 4/4 manifests (100.00%)
- bundling: abc.txt 1/4 files (25.00%)
- bundling: foo/Bar/file.txt 2/4 files (50.00%)
- bundling: foo/file.txt 3/4 files (75.00%)
- bundling: quux/file.py 4/4 files (100.00%)
+ bundle2-output-bundle: "HG20", 5 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
- changesets: 4 chunks
add changeset e8fc755d4d82
adding manifests
- manifests: 1/4 chunks (25.00%)
- manifests: 2/4 chunks (50.00%)
- manifests: 3/4 chunks (75.00%)
- manifests: 4/4 chunks (100.00%)
adding file changes
adding abc.txt revisions
- files: 1/4 chunks (25.00%)
adding foo/Bar/file.txt revisions
- files: 2/4 chunks (50.00%)
adding foo/file.txt revisions
- files: 3/4 chunks (75.00%)
adding quux/file.py revisions
- files: 4/4 chunks (100.00%)
added 4 changesets with 4 changes to 4 files (+1 heads)
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "george"
@@ -1969,9 +1904,23 @@
acl: path access granted: "911600dab2ae"
acl: branch access granted: "e8fc755d4d82" on branch "foobar"
acl: path access granted: "e8fc755d4d82"
+ bundle2-input-part: total payload size 2101
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
+ bundle2-input-bundle: 4 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 3 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 2 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 2 (undo push)
2:fb35475503ef
@@ -2009,41 +1958,29 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
- bundling: 1/4 changesets (25.00%)
- bundling: 2/4 changesets (50.00%)
- bundling: 3/4 changesets (75.00%)
- bundling: 4/4 changesets (100.00%)
- bundling: 1/4 manifests (25.00%)
- bundling: 2/4 manifests (50.00%)
- bundling: 3/4 manifests (75.00%)
- bundling: 4/4 manifests (100.00%)
- bundling: abc.txt 1/4 files (25.00%)
- bundling: foo/Bar/file.txt 2/4 files (50.00%)
- bundling: foo/file.txt 3/4 files (75.00%)
- bundling: quux/file.py 4/4 files (100.00%)
+ bundle2-output-bundle: "HG20", 5 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
- changesets: 4 chunks
add changeset e8fc755d4d82
adding manifests
- manifests: 1/4 chunks (25.00%)
- manifests: 2/4 chunks (50.00%)
- manifests: 3/4 chunks (75.00%)
- manifests: 4/4 chunks (100.00%)
adding file changes
adding abc.txt revisions
- files: 1/4 chunks (25.00%)
adding foo/Bar/file.txt revisions
- files: 2/4 chunks (50.00%)
adding foo/file.txt revisions
- files: 3/4 chunks (75.00%)
adding quux/file.py revisions
- files: 4/4 chunks (100.00%)
added 4 changesets with 4 changes to 4 files (+1 heads)
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "george"
@@ -2052,6 +1989,8 @@
acl: acl.allow not enabled
acl: acl.deny not enabled
error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
+ bundle2-input-part: total payload size 2101
+ bundle2-input-bundle: 4 parts total
transaction abort!
rollback completed
abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
@@ -2088,41 +2027,29 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
- bundling: 1/4 changesets (25.00%)
- bundling: 2/4 changesets (50.00%)
- bundling: 3/4 changesets (75.00%)
- bundling: 4/4 changesets (100.00%)
- bundling: 1/4 manifests (25.00%)
- bundling: 2/4 manifests (50.00%)
- bundling: 3/4 manifests (75.00%)
- bundling: 4/4 manifests (100.00%)
- bundling: abc.txt 1/4 files (25.00%)
- bundling: foo/Bar/file.txt 2/4 files (50.00%)
- bundling: foo/file.txt 3/4 files (75.00%)
- bundling: quux/file.py 4/4 files (100.00%)
+ bundle2-output-bundle: "HG20", 5 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
- changesets: 4 chunks
add changeset e8fc755d4d82
adding manifests
- manifests: 1/4 chunks (25.00%)
- manifests: 2/4 chunks (50.00%)
- manifests: 3/4 chunks (75.00%)
- manifests: 4/4 chunks (100.00%)
adding file changes
adding abc.txt revisions
- files: 1/4 chunks (25.00%)
adding foo/Bar/file.txt revisions
- files: 2/4 chunks (50.00%)
adding foo/file.txt revisions
- files: 3/4 chunks (75.00%)
adding quux/file.py revisions
- files: 4/4 chunks (100.00%)
added 4 changesets with 4 changes to 4 files (+1 heads)
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "astro"
@@ -2138,9 +2065,23 @@
acl: path access granted: "911600dab2ae"
acl: branch access granted: "e8fc755d4d82" on branch "foobar"
acl: path access granted: "e8fc755d4d82"
+ bundle2-input-part: total payload size 2101
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
+ bundle2-input-part: "pushkey" (params: 4 mandatory) supported
+ pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
+ bundle2-input-bundle: 4 parts total
updating the branch cache
+ bundle2-output-bundle: "HG20", 3 parts total
+ bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
+ bundle2-input-bundle: 2 parts total
listing keys for "phases"
- try to push obsolete markers to remote
repository tip rolled back to revision 2 (undo push)
2:fb35475503ef
@@ -2172,41 +2113,29 @@
f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
911600dab2ae7a9baff75958b84fe606851ce955
e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
- bundling: 1/4 changesets (25.00%)
- bundling: 2/4 changesets (50.00%)
- bundling: 3/4 changesets (75.00%)
- bundling: 4/4 changesets (100.00%)
- bundling: 1/4 manifests (25.00%)
- bundling: 2/4 manifests (50.00%)
- bundling: 3/4 manifests (75.00%)
- bundling: 4/4 manifests (100.00%)
- bundling: abc.txt 1/4 files (25.00%)
- bundling: foo/Bar/file.txt 2/4 files (50.00%)
- bundling: foo/file.txt 3/4 files (75.00%)
- bundling: quux/file.py 4/4 files (100.00%)
+ bundle2-output-bundle: "HG20", 5 parts total
+ bundle2-output-part: "replycaps" 155 bytes payload
+ bundle2-output-part: "check:heads" streamed payload
+ bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "replycaps" supported
+ bundle2-input-part: total payload size 155
+ bundle2-input-part: "check:heads" supported
+ bundle2-input-part: total payload size 20
+ bundle2-input-part: "changegroup" (params: 1 mandatory) supported
adding changesets
- changesets: 1 chunks
add changeset ef1ea85a6374
- changesets: 2 chunks
add changeset f9cafe1212c8
- changesets: 3 chunks
add changeset 911600dab2ae
- changesets: 4 chunks
add changeset e8fc755d4d82
adding manifests
- manifests: 1/4 chunks (25.00%)
- manifests: 2/4 chunks (50.00%)
- manifests: 3/4 chunks (75.00%)
- manifests: 4/4 chunks (100.00%)
adding file changes
adding abc.txt revisions
- files: 1/4 chunks (25.00%)
adding foo/Bar/file.txt revisions
- files: 2/4 chunks (50.00%)
adding foo/file.txt revisions
- files: 3/4 chunks (75.00%)
adding quux/file.py revisions
- files: 4/4 chunks (100.00%)
added 4 changesets with 4 changes to 4 files (+1 heads)
calling hook pretxnchangegroup.acl: hgext.acl.hook
acl: checking access for user "george"
@@ -2215,6 +2144,8 @@
acl: acl.allow not enabled
acl: acl.deny not enabled
error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
+ bundle2-input-part: total payload size 2101
+ bundle2-input-bundle: 4 parts total
transaction abort!
rollback completed
abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
--- a/tests/test-archive-symlinks.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-archive-symlinks.t Mon Jun 15 13:31:22 2015 -0500
@@ -18,7 +18,7 @@
$ cd "$origdir"
$ cd archive
- $ "$TESTDIR/readlink.py" dangling
+ $ readlink.py dangling
dangling -> nothing
tar
@@ -26,7 +26,7 @@
$ cd "$origdir"
$ tar xf archive.tar
$ cd tar
- $ "$TESTDIR/readlink.py" dangling
+ $ readlink.py dangling
dangling -> nothing
zip
@@ -34,7 +34,7 @@
$ cd "$origdir"
$ unzip archive.zip > /dev/null 2>&1
$ cd zip
- $ "$TESTDIR/readlink.py" dangling
+ $ readlink.py dangling
dangling -> nothing
$ cd ..
--- a/tests/test-archive.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-archive.t Mon Jun 15 13:31:22 2015 -0500
@@ -27,11 +27,11 @@
> hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
> cat hg.pid >> $DAEMON_PIDS
> echo % $1 allowed should give 200
- > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.$2" | head -n 1
+ > get-with-headers.py localhost:$HGPORT "archive/tip.$2" | head -n 1
> echo % $3 and $4 disallowed should both give 403
- > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.$3" | head -n 1
- > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.$4" | head -n 1
- > "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ > get-with-headers.py localhost:$HGPORT "archive/tip.$3" | head -n 1
+ > get-with-headers.py localhost:$HGPORT "archive/tip.$4" | head -n 1
+ > killdaemons.py
> cat errors.log
> cp .hg/hgrc-base .hg/hgrc
> }
@@ -63,7 +63,7 @@
invalid arch type should give 404
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT "archive/tip.invalid" | head -n 1
+ $ get-with-headers.py localhost:$HGPORT "archive/tip.invalid" | head -n 1
404 Unsupported archive type: None
$ TIP=`hg id -v | cut -f1 -d' '`
@@ -134,7 +134,7 @@
$ python getarchive.py "$TIP" gz relre:baz
HTTP Error 404: file(s) not found: relre:baz
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ hg archive -t tar test.tar
$ tar tf test.tar
@@ -145,7 +145,7 @@
test/baz/bletch
test/foo
- $ hg archive --debug -t tbz2 -X baz test.tar.bz2
+ $ hg archive --debug -t tbz2 -X baz test.tar.bz2 --config progress.debug=true
archiving: 0/4 files (0.00%)
archiving: .hgsub 1/4 files (25.00%)
archiving: .hgsubstate 2/4 files (50.00%)
@@ -282,18 +282,11 @@
$ hg archive ../with-progress
\r (no-eol) (esc)
archiving [ ] 0/6\r (no-eol) (esc)
- archiving [ ] 0/6\r (no-eol) (esc)
archiving [======> ] 1/6\r (no-eol) (esc)
- archiving [======> ] 1/6\r (no-eol) (esc)
- archiving [=============> ] 2/6\r (no-eol) (esc)
archiving [=============> ] 2/6\r (no-eol) (esc)
archiving [====================> ] 3/6\r (no-eol) (esc)
- archiving [====================> ] 3/6\r (no-eol) (esc)
- archiving [===========================> ] 4/6\r (no-eol) (esc)
archiving [===========================> ] 4/6\r (no-eol) (esc)
archiving [==================================> ] 5/6\r (no-eol) (esc)
- archiving [==================================> ] 5/6\r (no-eol) (esc)
- archiving [==========================================>] 6/6\r (no-eol) (esc)
archiving [==========================================>] 6/6\r (no-eol) (esc)
\r (no-eol) (esc)
--- a/tests/test-backout.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-backout.t Mon Jun 15 13:31:22 2015 -0500
@@ -42,6 +42,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 3 draft
commit option
@@ -69,6 +70,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 4 draft
$ echo ypples > a
$ hg commit -d '5 0' -m ypples
@@ -83,6 +85,7 @@
branch: default
commit: 1 unresolved (clean)
update: (current)
+ phases: 5 draft
file that was removed is recreated
(this also tests that editor is not invoked if the commit message is
@@ -110,6 +113,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 3 draft
backout of backout is as if nothing happened
@@ -124,6 +128,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 4 draft
across branch
@@ -144,6 +149,7 @@
branch: default
commit: (clean)
update: 1 new changesets (update)
+ phases: 2 draft
should fail
@@ -160,6 +166,7 @@
branch: default
commit: (clean)
update: 1 new changesets, 2 branch heads (merge)
+ phases: 3 draft
should fail
@@ -172,6 +179,7 @@
branch: default
commit: (clean)
update: 1 new changesets, 2 branch heads (merge)
+ phases: 3 draft
backout with merge
@@ -189,6 +197,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 1 draft
remove line 1
@@ -213,6 +222,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 5 draft
check line 1 is back
@@ -241,6 +251,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 3 draft
without --merge
$ hg backout -d '3 0' 1 --tool=true
@@ -258,6 +269,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 3 draft
with --merge
$ hg backout --merge -d '3 0' 1 --tool=true
@@ -302,6 +314,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 5 draft
backout of merge should fail
@@ -332,6 +345,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 6 draft
$ hg rollback
repository tip rolled back to revision 4 (undo commit)
@@ -344,6 +358,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 5 draft
$ hg backout -d '6 0' --parent 3 4 --tool=true
removing c
@@ -354,6 +369,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 6 draft
$ cd ..
@@ -373,7 +389,6 @@
adding file1
$ hg branch branch2
marked working directory as branch branch2
- (branches are permanent and global, did you want a bookmark?)
$ echo branch2 > file2
$ hg ci -d '2 0' -Am file2
adding file2
@@ -394,6 +409,7 @@
branch: branch2
commit: 1 removed
update: (current)
+ phases: 3 draft
with --merge
(this also tests that editor is invoked if '--edit' is specified
@@ -424,6 +440,7 @@
branch: branch2
commit: 1 removed (merge)
update: (current)
+ phases: 4 draft
$ hg update -q -C 2
on branch2 with branch1 not merged, so file1 should still exist:
@@ -440,6 +457,7 @@
branch: branch2
commit: (clean)
update: 1 new changesets, 2 branch heads (merge)
+ phases: 4 draft
on branch2 with branch1 merged, so file1 should be gone:
@@ -458,6 +476,7 @@
branch: branch2
commit: (clean)
update: (current)
+ phases: 5 draft
on branch1, so no file1 and file2:
@@ -474,6 +493,7 @@
branch: branch1
commit: (clean)
update: (current)
+ phases: 5 draft
$ cd ..
@@ -553,6 +573,7 @@
branch: default
commit: 1 unresolved (clean)
update: (current)
+ phases: 3 draft
$ hg resolve --all --debug
picked tool 'internal:merge' for foo (binary False symlink False)
merging foo
@@ -570,6 +591,7 @@
branch: default
commit: 1 modified, 1 unknown
update: (current)
+ phases: 3 draft
$ cat foo
one
two
--- a/tests/test-bad-extension.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bad-extension.t Mon Jun 15 13:31:22 2015 -0500
@@ -15,3 +15,32 @@
hg help [-ec] [TOPIC]
show help for a given topic or a help overview
+
+show traceback
+
+ $ hg -q help help --traceback 2>&1 | grep -v '^ '
+ *** failed to import extension badext from $TESTTMP/badext.py: bit bucket overflow
+ Traceback (most recent call last):
+ Exception: bit bucket overflow
+ *** failed to import extension badext2: No module named badext2
+ Traceback (most recent call last):
+ ImportError: No module named badext2
+ hg help [-ec] [TOPIC]
+
+ show help for a given topic or a help overview
+
+show traceback for ImportError of hgext.name if debug is set
+(note that --debug option isn't applied yet when loading extensions)
+
+ $ hg help help --traceback --config ui.debug=True 2>&1 \
+ > | grep -v '^ ' | head -n10
+ *** failed to import extension badext from $TESTTMP/badext.py: bit bucket overflow
+ Traceback (most recent call last):
+ Exception: bit bucket overflow
+ could not import hgext.badext2 (No module named badext2): trying badext2
+ Traceback (most recent call last):
+ ImportError: No module named badext2
+ *** failed to import extension badext2: No module named badext2
+ Traceback (most recent call last):
+ ImportError: No module named badext2
+ hg help [-ec] [TOPIC]
--- a/tests/test-bad-pull.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bad-pull.t Mon Jun 15 13:31:22 2015 -0500
@@ -18,4 +18,4 @@
$ hg clone http://localhost:$HGPORT/foo copy2
abort: HTTP Error 404: * (glob)
[255]
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
--- a/tests/test-basic.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-basic.t Mon Jun 15 13:31:22 2015 -0500
@@ -5,7 +5,7 @@
defaults.commit=-d "0 0"
defaults.shelve=--date "0 0"
defaults.tag=-d "0 0"
- devel.all=true
+ devel.all-warnings=true
largefiles.usercache=$TESTTMP/.cache/largefiles (glob)
ui.slash=True
ui.interactive=False
--- a/tests/test-bheads.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bheads.t Mon Jun 15 13:31:22 2015 -0500
@@ -37,7 +37,6 @@
$ hg add b
$ hg branch b
marked working directory as branch b
- (branches are permanent and global, did you want a bookmark?)
$ hg commit -m "Adding b branch"
$ heads
2: Adding b branch (b)
@@ -119,7 +118,6 @@
$ hg add c
$ hg branch c
marked working directory as branch c
- (branches are permanent and global, did you want a bookmark?)
$ hg commit -m "Adding c branch"
$ heads
7: Adding c branch (c)
@@ -302,7 +300,6 @@
$ hg up -q null
$ hg branch -f b
marked working directory as branch b
- (branches are permanent and global, did you want a bookmark?)
$ echo 1 > bb
$ hg ci -Am "b4 (NN): new topo root for branch b"
adding bb
@@ -317,7 +314,6 @@
$ hg branch -f default
marked working directory as branch default
- (branches are permanent and global, did you want a bookmark?)
$ echo 1 > aa
$ hg ci -Am "a6 (BN): new branch root"
adding aa
@@ -337,7 +333,6 @@
$ hg merge -q 3
$ hg branch -f default
marked working directory as branch default
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -m "a8 (BB): weird new branch root"
created new head
--- a/tests/test-bisect.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bisect.t Mon Jun 15 13:31:22 2015 -0500
@@ -190,6 +190,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 32 draft
$ hg bisect -g 1
Testing changeset 16:a2e6ea4973e9 (30 changesets remaining, ~4 tests)
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-bisect3.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bisect3.t Mon Jun 15 13:31:22 2015 -0500
@@ -230,3 +230,20 @@
I 2:e1355ee1f23e
G 1:ce7c85e06a9f
G 0:b4e73ffab476
+
+ $ hg --config extensions.color= --color=debug log --quiet --style bisect
+ [log.bisect| ] 14:cbf2f3105bbf
+ [log.bisect| ] 13:e07efca37c43
+ [log.bisect bisect.bad|B] 12:98c6b56349c0
+ [log.bisect bisect.bad|B] 11:03f491376e63
+ [log.bisect bisect.bad|B] 10:c012b15e2409
+ [log.bisect bisect.untested|U] 9:2197c557e14c
+ [log.bisect bisect.untested|U] 8:e74a86251f58
+ [log.bisect bisect.skipped|S] 7:a5f87041c899
+ [log.bisect bisect.good|G] 6:7d997bedcd8d
+ [log.bisect bisect.good|G] 5:2dd1875f1028
+ [log.bisect bisect.good|G] 4:2a1daef14cd4
+ [log.bisect bisect.ignored|I] 3:8417d459b90c
+ [log.bisect bisect.ignored|I] 2:e1355ee1f23e
+ [log.bisect bisect.good|G] 1:ce7c85e06a9f
+ [log.bisect bisect.good|G] 0:b4e73ffab476
--- a/tests/test-bookmarks-current.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bookmarks-current.t Mon Jun 15 13:31:22 2015 -0500
@@ -69,7 +69,7 @@
* Y 0:719295282060
Z -1:000000000000
-Verify that switching to Z updates the current bookmark:
+Verify that switching to Z updates the active bookmark:
$ hg update Z
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
(activating bookmark Z)
@@ -118,7 +118,7 @@
* Y 0:719295282060
Z 0:719295282060
-deactivate current bookmark using -i
+deactivate active bookmark using -i
$ hg bookmark -i Y
$ hg bookmarks
@@ -137,7 +137,7 @@
* Y 0:719295282060
Z 0:719295282060
-deactivate current bookmark while renaming
+deactivate active bookmark while renaming
$ hg bookmark -i -m Y X
$ hg bookmarks
@@ -193,3 +193,12 @@
$ hg up -q .
$ test -f .hg/bookmarks.current
[1]
+
+issue 4552 -- simulate a pull moving the active bookmark
+
+ $ hg up -q X
+ $ printf "Z" > .hg/bookmarks.current
+ $ hg log -T '{activebookmark}\n' -r Z
+ Z
+ $ hg log -T '{bookmarks % "{active}\n"}' -r Z
+ Z
--- a/tests/test-bookmarks-pushpull.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bookmarks-pushpull.t Mon Jun 15 13:31:22 2015 -0500
@@ -7,6 +7,9 @@
> publish=False
> [experimental]
> evolution=createmarkers,exchange
+ > # drop me once bundle2 is the default,
+ > # added to get test change early.
+ > bundle2-exp = True
> EOF
initialize
@@ -260,7 +263,14 @@
$ cd ..
$ hg clone -q a pull-race
- $ hg clone -q pull-race pull-race2
+
+We want to use http because it is stateless and therefore more susceptible to
+race conditions
+
+ $ hg -R pull-race serve -p $HGPORT -d --pid-file=pull-race.pid -E main-error.log
+ $ cat pull-race.pid >> $DAEMON_PIDS
+
+ $ hg clone -q http://localhost:$HGPORT/ pull-race2
$ cd pull-race
$ hg up -q Y
$ echo c4 > f2
@@ -270,13 +280,23 @@
> [hooks]
> outgoing.makecommit = hg ci -Am5; echo committed in pull-race
> EOF
- $ cd ../pull-race2
+
+(new config needs a server restart)
+
+ $ cd ..
+ $ killdaemons.py
+ $ hg -R pull-race serve -p $HGPORT -d --pid-file=pull-race.pid -E main-error.log
+ $ cat pull-race.pid >> $DAEMON_PIDS
+ $ cd pull-race2
+ $ hg -R $TESTTMP/pull-race book
+ @ 1:0d2164f0ce0d
+ X 1:0d2164f0ce0d
+ * Y 4:b0a5eff05604
+ Z 1:0d2164f0ce0d
$ hg pull
- pulling from $TESTTMP/pull-race (glob)
+ pulling from http://localhost:$HGPORT/
searching for changes
adding changesets
- adding f3
- committed in pull-race
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
@@ -287,6 +307,47 @@
X 1:0d2164f0ce0d
Y 4:b0a5eff05604
Z 1:0d2164f0ce0d
+
+Update a bookmark right after the initial lookup -B (issue4689)
+
+ $ echo c6 > ../pull-race/f3 # to be committed during the race
+ $ cat <<EOF > ../pull-race/.hg/hgrc
+ > [hooks]
+ > # If anything to commit, commit it right after the first key listing used
+ > # during lookup. This makes the commit appear before the actual getbundle
+ > # call.
+ > listkeys.makecommit= ((hg st | grep -q M) && (hg commit -m race; echo commited in pull-race)) || exit 0
+ > EOF
+
+(new config need server restart)
+
+ $ killdaemons.py
+ $ hg -R ../pull-race serve -p $HGPORT -d --pid-file=../pull-race.pid -E main-error.log
+ $ cat ../pull-race.pid >> $DAEMON_PIDS
+
+ $ hg -R $TESTTMP/pull-race book
+ @ 1:0d2164f0ce0d
+ X 1:0d2164f0ce0d
+ * Y 5:35d1ef0a8d1b
+ Z 1:0d2164f0ce0d
+ $ hg pull -B Y
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ updating bookmark Y
+ (run 'hg update' to get a working copy)
+ $ hg book
+ * @ 1:0d2164f0ce0d
+ X 1:0d2164f0ce0d
+ Y 5:35d1ef0a8d1b
+ Z 1:0d2164f0ce0d
+
+(done with this section of the test)
+
+ $ killdaemons.py
$ cd ../b
diverging a remote bookmark fails
@@ -368,6 +429,7 @@
remote: adding manifests
remote: adding file changes
remote: added 2 changesets with 2 changes to 1 files (+1 heads)
+ remote: 2 new obsolescence markers
updating bookmark Y
$ hg -R ../a book
@ 1:0d2164f0ce0d
@@ -436,6 +498,7 @@
adding manifests
adding file changes
added 5 changesets with 5 changes to 3 files (+2 heads)
+ 2 new obsolescence markers
updating to bookmark @
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg -R cloned-bookmarks bookmarks
@@ -571,6 +634,7 @@
adding manifests
adding file changes
added 5 changesets with 5 changes to 3 files (+2 heads)
+ 2 new obsolescence markers
updating to bookmark @
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd addmarks
@@ -679,7 +743,7 @@
> push_ssl = false
> allow_push = *
> EOF
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ hg -R ../issue4455-dest serve -p $HGPORT -d --pid-file=../issue4455.pid -E ../issue4455-error.log
$ cat ../issue4455.pid >> $DAEMON_PIDS
@@ -691,15 +755,25 @@
searching for changes
no changes found
pushkey-abort: prepushkey hook exited with status 1
- exporting bookmark @ failed!
- [1]
+ abort: exporting bookmark @ failed!
+ [255]
$ hg -R ../issue4455-dest/ bookmarks
no bookmarks set
Using ssh
---------
- $ hg push -B @ ssh
+ $ hg push -B @ ssh --config experimental.bundle2-exp=True
+ pushing to ssh://user@dummy/issue4455-dest
+ searching for changes
+ no changes found
+ remote: pushkey-abort: prepushkey hook exited with status 1
+ abort: exporting bookmark @ failed!
+ [255]
+ $ hg -R ../issue4455-dest/ bookmarks
+ no bookmarks set
+
+ $ hg push -B @ ssh --config experimental.bundle2-exp=False
pushing to ssh://user@dummy/issue4455-dest
searching for changes
no changes found
@@ -712,7 +786,17 @@
Using http
----------
- $ hg push -B @ http
+ $ hg push -B @ http --config experimental.bundle2-exp=True
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ remote: pushkey-abort: prepushkey hook exited with status 1
+ abort: exporting bookmark @ failed!
+ [255]
+ $ hg -R ../issue4455-dest/ bookmarks
+ no bookmarks set
+
+ $ hg push -B @ http --config experimental.bundle2-exp=False
pushing to http://localhost:$HGPORT/
searching for changes
no changes found
--- a/tests/test-bookmarks.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bookmarks.t Mon Jun 15 13:31:22 2015 -0500
@@ -393,6 +393,7 @@
bookmarks: *Z Y x y
commit: (clean)
update: 1 new changesets, 2 branch heads (merge)
+ phases: 3 draft
test id
@@ -529,7 +530,7 @@
added 2 changesets with 2 changes to 2 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
-update to current bookmark if it's not the parent
+update to active bookmark if it's not the parent
$ hg summary
parent: 2:db815d6d32e6
@@ -538,6 +539,7 @@
bookmarks: *Z Y x y
commit: 1 added, 1 unknown (new branch head)
update: 2 new changesets (update)
+ phases: 5 draft
$ hg update
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
updating bookmark Z
--- a/tests/test-branch-option.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-branch-option.t Mon Jun 15 13:31:22 2015 -0500
@@ -14,7 +14,6 @@
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg branch c
marked working directory as branch c
- (branches are permanent and global, did you want a bookmark?)
$ echo c > foo
$ hg ci -d '0 0' -mc
$ hg tag -l z
@@ -31,21 +30,18 @@
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg branch b
marked working directory as branch b
- (branches are permanent and global, did you want a bookmark?)
$ echo b > foo
$ hg ci -d '0 0' -mb
$ hg up 0
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg --encoding utf-8 branch æ
marked working directory as branch \xc3\xa6 (esc)
- (branches are permanent and global, did you want a bookmark?)
$ echo ae1 > foo
$ hg ci -d '0 0' -mae1
$ hg up 0
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg --encoding utf-8 branch -f æ
marked working directory as branch \xc3\xa6 (esc)
- (branches are permanent and global, did you want a bookmark?)
$ echo ae2 > foo
$ hg ci -d '0 0' -mae2
created new head
@@ -53,7 +49,6 @@
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg branch -f b
marked working directory as branch b
- (branches are permanent and global, did you want a bookmark?)
$ echo b2 > foo
$ hg ci -d '0 0' -mb2
created new head
--- a/tests/test-branches.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-branches.t Mon Jun 15 13:31:22 2015 -0500
@@ -13,7 +13,6 @@
$ hg branch q
marked working directory as branch q
- (branches are permanent and global, did you want a bookmark?)
$ echo 'aa' >a
$ hg branch -C
reset working directory to branch a
@@ -25,7 +24,6 @@
$ hg add b
$ hg branch b
marked working directory as branch b
- (branches are permanent and global, did you want a bookmark?)
$ hg commit -d '2 0' -m "Adding b branch"
$ echo 'bh1' >bh1
@@ -42,7 +40,6 @@
$ hg add c
$ hg branch c
marked working directory as branch c
- (branches are permanent and global, did you want a bookmark?)
$ hg commit -d '5 0' -m "Adding c branch"
reserved names
@@ -101,7 +98,6 @@
$ hg add d
$ hg branch 'a branch name much longer than the default justification used by branches'
marked working directory as branch a branch name much longer than the default justification used by branches
- (branches are permanent and global, did you want a bookmark?)
$ hg commit -d '6 0' -m "Adding d branch"
$ hg branches
@@ -601,7 +597,6 @@
cache is updated when committing
$ hg branch i-will-regret-this
marked working directory as branch i-will-regret-this
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -m regrets
$ f --size .hg/cache/rbc-*
.hg/cache/rbc-names-v1: size=106
--- a/tests/test-bundle.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bundle.t Mon Jun 15 13:31:22 2015 -0500
@@ -211,7 +211,7 @@
Pull ../full.hg into empty (with hook)
$ echo "[hooks]" >> .hg/hgrc
- $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
+ $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
doesn't work (yet ?)
@@ -629,7 +629,7 @@
== bundling
- $ hg bundle bundle.hg part --debug
+ $ hg bundle bundle.hg part --debug --config progress.debug=true
query 1; heads
searching for changes
all remote heads known locally
--- a/tests/test-bundle2-exchange.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bundle2-exchange.t Mon Jun 15 13:31:22 2015 -0500
@@ -28,7 +28,7 @@
> [hooks]
> pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
> txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
- > txnclose.env = sh -c "HG_LOCAL= python \"$TESTDIR/printenv.py\" txnclose"
+ > txnclose.env = sh -c "HG_LOCAL= printenv.py txnclose"
> pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
> EOF
@@ -466,7 +466,7 @@
> failpush=$TESTTMP/failpush.py
> EOF
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
$ cat other.pid >> $DAEMON_PIDS
@@ -562,7 +562,7 @@
> txnabort.failpush = sh -c "echo 'Cleaning up the mess...'"
> EOF
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
$ cat other.pid >> $DAEMON_PIDS
@@ -625,7 +625,7 @@
$ cat << EOF >> $HGRCPATH
> pretxnchangegroup = sh -c "echo 'Fail early!'; false"
> EOF
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
+ $ killdaemons.py # reload http config
$ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
$ cat other.pid >> $DAEMON_PIDS
@@ -717,3 +717,153 @@
remote: rollback completed
abort: pretxnchangegroup hook exited with status 1
[255]
+
+Check abort from mandatory pushkey
+
+ $ cat > mandatorypart.py << EOF
+ > from mercurial import exchange
+ > from mercurial import pushkey
+ > from mercurial import node
+ > from mercurial import error
+ > @exchange.b2partsgenerator('failingpuskey')
+ > def addfailingpushey(pushop, bundler):
+ > enc = pushkey.encode
+ > part = bundler.newpart('pushkey')
+ > part.addparam('namespace', enc('phases'))
+ > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
+ > part.addparam('old', enc(str(0))) # successful update
+ > part.addparam('new', enc(str(0)))
+ > def fail(pushop, exc):
+ > raise error.Abort('Correct phase push failed (because hooks)')
+ > pushop.pkfailcb[part.id] = fail
+ > EOF
+ $ cat >> $HGRCPATH << EOF
+ > [hooks]
+ > pretxnchangegroup=
+ > pretxnclose.failpush=
+ > prepushkey.failpush = sh -c "echo 'do not push the key !'; false"
+ > [extensions]
+ > mandatorypart=$TESTTMP/mandatorypart.py
+ > EOF
+ $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
+ $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
+ $ cat other.pid >> $DAEMON_PIDS
+
+(Failure from a hook)
+
+ $ hg -R main push other -r e7ec4e813ba6
+ pushing to other
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ do not push the key !
+ pushkey-abort: prepushkey.failpush hook exited with status 1
+ transaction abort!
+ Cleaning up the mess...
+ rollback completed
+ abort: Correct phase push failed (because hooks)
+ [255]
+ $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
+ pushing to ssh://user@dummy/other
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: do not push the key !
+ remote: pushkey-abort: prepushkey.failpush hook exited with status 1
+ remote: transaction abort!
+ remote: Cleaning up the mess...
+ remote: rollback completed
+ abort: Correct phase push failed (because hooks)
+ [255]
+ $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
+ pushing to http://localhost:$HGPORT2/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: do not push the key !
+ remote: pushkey-abort: prepushkey.failpush hook exited with status 1
+ remote: transaction abort!
+ remote: Cleaning up the mess...
+ remote: rollback completed
+ abort: Correct phase push failed (because hooks)
+ [255]
+
+(Failure from a the pushkey)
+
+ $ cat > mandatorypart.py << EOF
+ > from mercurial import exchange
+ > from mercurial import pushkey
+ > from mercurial import node
+ > from mercurial import error
+ > @exchange.b2partsgenerator('failingpuskey')
+ > def addfailingpushey(pushop, bundler):
+ > enc = pushkey.encode
+ > part = bundler.newpart('pushkey')
+ > part.addparam('namespace', enc('phases'))
+ > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
+ > part.addparam('old', enc(str(4))) # will fail
+ > part.addparam('new', enc(str(3)))
+ > def fail(pushop, exc):
+ > raise error.Abort('Clown phase push failed')
+ > pushop.pkfailcb[part.id] = fail
+ > EOF
+ $ cat >> $HGRCPATH << EOF
+ > [hooks]
+ > prepushkey.failpush =
+ > EOF
+ $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
+ $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
+ $ cat other.pid >> $DAEMON_PIDS
+
+ $ hg -R main push other -r e7ec4e813ba6
+ pushing to other
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ transaction abort!
+ Cleaning up the mess...
+ rollback completed
+ pushkey: lock state after "phases"
+ lock: free
+ wlock: free
+ abort: Clown phase push failed
+ [255]
+ $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
+ pushing to ssh://user@dummy/other
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: transaction abort!
+ remote: Cleaning up the mess...
+ remote: rollback completed
+ remote: pushkey: lock state after "phases"
+ remote: lock: free
+ remote: wlock: free
+ abort: Clown phase push failed
+ [255]
+ $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
+ pushing to http://localhost:$HGPORT2/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: transaction abort!
+ remote: Cleaning up the mess...
+ remote: rollback completed
+ remote: pushkey: lock state after "phases"
+ remote: lock: free
+ remote: wlock: free
+ abort: Clown phase push failed
+ [255]
+
--- a/tests/test-bundle2-format.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bundle2-format.t Mon Jun 15 13:31:22 2015 -0500
@@ -336,11 +336,12 @@
bundling debug
- $ hg bundle2 --debug --param 'e|! 7/=babar%#==tutu' --param simple ../out.hg2
- start emission of HG20 stream
- bundle parameter: e%7C%21%207/=babar%25%23%3D%3Dtutu simple
- start of parts
- end of bundle
+ $ hg bundle2 --debug --param 'e|! 7/=babar%#==tutu' --param simple ../out.hg2 --config progress.debug=true --config devel.bundle2.debug=true
+ bundle2-output-bundle: "HG20", (2 params) 0 parts total
+ bundle2-output: start emission of HG20 stream
+ bundle2-output: bundle parameter: e%7C%21%207/=babar%25%23%3D%3Dtutu simple
+ bundle2-output: start of parts
+ bundle2-output: end of bundle
file content is ok
@@ -349,18 +350,18 @@
unbundling debug
- $ hg statbundle2 --debug < ../out.hg2
- start processing of HG20 stream
- reading bundle2 stream parameters
- ignoring unknown parameter 'e|! 7/'
- ignoring unknown parameter 'simple'
+ $ hg statbundle2 --debug --config progress.debug=true --config devel.bundle2.debug=true < ../out.hg2
+ bundle2-input: start processing of HG20 stream
+ bundle2-input: reading bundle2 stream parameters
+ bundle2-input: ignoring unknown parameter 'e|! 7/'
+ bundle2-input: ignoring unknown parameter 'simple'
options count: 2
- e|! 7/
babar%#==tutu
- simple
- start extraction of bundle2 parts
- part header size: 0
- end of bundle2 stream
+ bundle2-input: start extraction of bundle2 parts
+ bundle2-input: part header size: 0
+ bundle2-input: end of bundle2 stream
parts count: 0
@@ -383,18 +384,49 @@
Test part
=================
- $ hg bundle2 --parts ../parts.hg2 --debug
- start emission of HG20 stream
- bundle parameter:
- start of parts
- bundle part: "test:empty"
- bundle part: "test:empty"
- bundle part: "test:song"
- bundle part: "test:debugreply"
- bundle part: "test:math"
- bundle part: "test:song"
- bundle part: "test:ping"
- end of bundle
+ $ hg bundle2 --parts ../parts.hg2 --debug --config progress.debug=true --config devel.bundle2.debug=true
+ bundle2-output-bundle: "HG20", 7 parts total
+ bundle2-output: start emission of HG20 stream
+ bundle2-output: bundle parameter:
+ bundle2-output: start of parts
+ bundle2-output: bundle part: "test:empty"
+ bundle2-output-part: "test:empty" (advisory) empty payload
+ bundle2-output: part 0: "test:empty"
+ bundle2-output: header chunk size: 17
+ bundle2-output: closing payload chunk
+ bundle2-output: bundle part: "test:empty"
+ bundle2-output-part: "test:empty" (advisory) empty payload
+ bundle2-output: part 1: "test:empty"
+ bundle2-output: header chunk size: 17
+ bundle2-output: closing payload chunk
+ bundle2-output: bundle part: "test:song"
+ bundle2-output-part: "test:song" (advisory) 178 bytes payload
+ bundle2-output: part 2: "test:song"
+ bundle2-output: header chunk size: 16
+ bundle2-output: payload chunk size: 178
+ bundle2-output: closing payload chunk
+ bundle2-output: bundle part: "test:debugreply"
+ bundle2-output-part: "test:debugreply" (advisory) empty payload
+ bundle2-output: part 3: "test:debugreply"
+ bundle2-output: header chunk size: 22
+ bundle2-output: closing payload chunk
+ bundle2-output: bundle part: "test:math"
+ bundle2-output-part: "test:math" (advisory) (params: 2 mandatory 2 advisory) 2 bytes payload
+ bundle2-output: part 4: "test:math"
+ bundle2-output: header chunk size: 43
+ bundle2-output: payload chunk size: 2
+ bundle2-output: closing payload chunk
+ bundle2-output: bundle part: "test:song"
+ bundle2-output-part: "test:song" (advisory) (params: 1 mandatory) empty payload
+ bundle2-output: part 5: "test:song"
+ bundle2-output: header chunk size: 29
+ bundle2-output: closing payload chunk
+ bundle2-output: bundle part: "test:ping"
+ bundle2-output-part: "test:ping" (advisory) empty payload
+ bundle2-output: part 6: "test:ping"
+ bundle2-output: header chunk size: 16
+ bundle2-output: closing payload chunk
+ bundle2-output: end of bundle
$ cat ../parts.hg2
HG20\x00\x00\x00\x00\x00\x00\x00\x11 (esc)
@@ -436,78 +468,80 @@
payload: 0 bytes
parts count: 7
- $ hg statbundle2 --debug < ../parts.hg2
- start processing of HG20 stream
- reading bundle2 stream parameters
+ $ hg statbundle2 --debug --config progress.debug=true --config devel.bundle2.debug=true < ../parts.hg2
+ bundle2-input: start processing of HG20 stream
+ bundle2-input: reading bundle2 stream parameters
options count: 0
- start extraction of bundle2 parts
- part header size: 17
- part type: "test:empty"
- part id: "0"
- part parameters: 0
+ bundle2-input: start extraction of bundle2 parts
+ bundle2-input: part header size: 17
+ bundle2-input: part type: "test:empty"
+ bundle2-input: part id: "0"
+ bundle2-input: part parameters: 0
:test:empty:
mandatory: 0
advisory: 0
- payload chunk size: 0
+ bundle2-input: payload chunk size: 0
payload: 0 bytes
- part header size: 17
- part type: "test:empty"
- part id: "1"
- part parameters: 0
+ bundle2-input: part header size: 17
+ bundle2-input: part type: "test:empty"
+ bundle2-input: part id: "1"
+ bundle2-input: part parameters: 0
:test:empty:
mandatory: 0
advisory: 0
- payload chunk size: 0
+ bundle2-input: payload chunk size: 0
payload: 0 bytes
- part header size: 16
- part type: "test:song"
- part id: "2"
- part parameters: 0
+ bundle2-input: part header size: 16
+ bundle2-input: part type: "test:song"
+ bundle2-input: part id: "2"
+ bundle2-input: part parameters: 0
:test:song:
mandatory: 0
advisory: 0
- payload chunk size: 178
- payload chunk size: 0
+ bundle2-input: payload chunk size: 178
+ bundle2-input: payload chunk size: 0
+ bundle2-input-part: total payload size 178
payload: 178 bytes
- part header size: 22
- part type: "test:debugreply"
- part id: "3"
- part parameters: 0
+ bundle2-input: part header size: 22
+ bundle2-input: part type: "test:debugreply"
+ bundle2-input: part id: "3"
+ bundle2-input: part parameters: 0
:test:debugreply:
mandatory: 0
advisory: 0
- payload chunk size: 0
+ bundle2-input: payload chunk size: 0
payload: 0 bytes
- part header size: 43
- part type: "test:math"
- part id: "4"
- part parameters: 3
+ bundle2-input: part header size: 43
+ bundle2-input: part type: "test:math"
+ bundle2-input: part id: "4"
+ bundle2-input: part parameters: 3
:test:math:
mandatory: 2
advisory: 1
- payload chunk size: 2
- payload chunk size: 0
+ bundle2-input: payload chunk size: 2
+ bundle2-input: payload chunk size: 0
+ bundle2-input-part: total payload size 2
payload: 2 bytes
- part header size: 29
- part type: "test:song"
- part id: "5"
- part parameters: 1
+ bundle2-input: part header size: 29
+ bundle2-input: part type: "test:song"
+ bundle2-input: part id: "5"
+ bundle2-input: part parameters: 1
:test:song:
mandatory: 1
advisory: 0
- payload chunk size: 0
+ bundle2-input: payload chunk size: 0
payload: 0 bytes
- part header size: 16
- part type: "test:ping"
- part id: "6"
- part parameters: 0
+ bundle2-input: part header size: 16
+ bundle2-input: part type: "test:ping"
+ bundle2-input: part id: "6"
+ bundle2-input: part parameters: 0
:test:ping:
mandatory: 0
advisory: 0
- payload chunk size: 0
+ bundle2-input: payload chunk size: 0
payload: 0 bytes
- part header size: 0
- end of bundle2 stream
+ bundle2-input: part header size: 0
+ bundle2-input: end of bundle2 stream
parts count: 7
Test actual unbundling of test part
@@ -515,63 +549,74 @@
Process the bundle
- $ hg unbundle2 --debug < ../parts.hg2
- start processing of HG20 stream
- reading bundle2 stream parameters
- start extraction of bundle2 parts
- part header size: 17
- part type: "test:empty"
- part id: "0"
- part parameters: 0
- ignoring unsupported advisory part test:empty
- payload chunk size: 0
- part header size: 17
- part type: "test:empty"
- part id: "1"
- part parameters: 0
- ignoring unsupported advisory part test:empty
- payload chunk size: 0
- part header size: 16
- part type: "test:song"
- part id: "2"
- part parameters: 0
- found a handler for part 'test:song'
+ $ hg unbundle2 --debug --config progress.debug=true --config devel.bundle2.debug=true < ../parts.hg2
+ bundle2-input: start processing of HG20 stream
+ bundle2-input: reading bundle2 stream parameters
+ bundle2-input-bundle: with-transaction
+ bundle2-input: start extraction of bundle2 parts
+ bundle2-input: part header size: 17
+ bundle2-input: part type: "test:empty"
+ bundle2-input: part id: "0"
+ bundle2-input: part parameters: 0
+ bundle2-input: ignoring unsupported advisory part test:empty
+ bundle2-input-part: "test:empty" (advisory) unsupported-type
+ bundle2-input: payload chunk size: 0
+ bundle2-input: part header size: 17
+ bundle2-input: part type: "test:empty"
+ bundle2-input: part id: "1"
+ bundle2-input: part parameters: 0
+ bundle2-input: ignoring unsupported advisory part test:empty
+ bundle2-input-part: "test:empty" (advisory) unsupported-type
+ bundle2-input: payload chunk size: 0
+ bundle2-input: part header size: 16
+ bundle2-input: part type: "test:song"
+ bundle2-input: part id: "2"
+ bundle2-input: part parameters: 0
+ bundle2-input: found a handler for part 'test:song'
+ bundle2-input-part: "test:song" (advisory) supported
The choir starts singing:
- payload chunk size: 178
- payload chunk size: 0
+ bundle2-input: payload chunk size: 178
+ bundle2-input: payload chunk size: 0
+ bundle2-input-part: total payload size 178
Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
- part header size: 22
- part type: "test:debugreply"
- part id: "3"
- part parameters: 0
- found a handler for part 'test:debugreply'
+ bundle2-input: part header size: 22
+ bundle2-input: part type: "test:debugreply"
+ bundle2-input: part id: "3"
+ bundle2-input: part parameters: 0
+ bundle2-input: found a handler for part 'test:debugreply'
+ bundle2-input-part: "test:debugreply" (advisory) supported
debugreply: no reply
- payload chunk size: 0
- part header size: 43
- part type: "test:math"
- part id: "4"
- part parameters: 3
- ignoring unsupported advisory part test:math
- payload chunk size: 2
- payload chunk size: 0
- part header size: 29
- part type: "test:song"
- part id: "5"
- part parameters: 1
- found a handler for part 'test:song'
- ignoring unsupported advisory part test:song - randomparam
- payload chunk size: 0
- part header size: 16
- part type: "test:ping"
- part id: "6"
- part parameters: 0
- found a handler for part 'test:ping'
+ bundle2-input: payload chunk size: 0
+ bundle2-input: part header size: 43
+ bundle2-input: part type: "test:math"
+ bundle2-input: part id: "4"
+ bundle2-input: part parameters: 3
+ bundle2-input: ignoring unsupported advisory part test:math
+ bundle2-input-part: "test:math" (advisory) (params: 2 mandatory 2 advisory) unsupported-type
+ bundle2-input: payload chunk size: 2
+ bundle2-input: payload chunk size: 0
+ bundle2-input-part: total payload size 2
+ bundle2-input: part header size: 29
+ bundle2-input: part type: "test:song"
+ bundle2-input: part id: "5"
+ bundle2-input: part parameters: 1
+ bundle2-input: found a handler for part 'test:song'
+ bundle2-input: ignoring unsupported advisory part test:song - randomparam
+ bundle2-input-part: "test:song" (advisory) (params: 1 mandatory) unsupported-params (['randomparam'])
+ bundle2-input: payload chunk size: 0
+ bundle2-input: part header size: 16
+ bundle2-input: part type: "test:ping"
+ bundle2-input: part id: "6"
+ bundle2-input: part parameters: 0
+ bundle2-input: found a handler for part 'test:ping'
+ bundle2-input-part: "test:ping" (advisory) supported
received ping request (id 6)
- payload chunk size: 0
- part header size: 0
- end of bundle2 stream
+ bundle2-input: payload chunk size: 0
+ bundle2-input: part header size: 0
+ bundle2-input: end of bundle2 stream
+ bundle2-input-bundle: 6 parts total
0 unread bytes
3 total verses sung
@@ -704,17 +749,21 @@
@ 0:3903775176ed draft test a
- $ hg bundle2 --debug --rev '8+7+5+4' ../rev.hg2
+ $ hg bundle2 --debug --config progress.debug=true --config devel.bundle2.debug=true --rev '8+7+5+4' ../rev.hg2
4 changesets found
list of changesets:
32af7686d403cf45b5d95f2d70cebea587ac806a
9520eea781bcca16c1e15acc0ba14335a0e8e5ba
eea13746799a9e0bfd88f29d3c2e9dc9389f524f
02de42196ebee42ef284b6780a87cdc96e8eaab6
- start emission of HG20 stream
- bundle parameter:
- start of parts
- bundle part: "changegroup"
+ bundle2-output-bundle: "HG20", 1 parts total
+ bundle2-output: start emission of HG20 stream
+ bundle2-output: bundle parameter:
+ bundle2-output: start of parts
+ bundle2-output: bundle part: "changegroup"
+ bundle2-output-part: "changegroup" (advisory) streamed payload
+ bundle2-output: part 0: "changegroup"
+ bundle2-output: header chunk size: 18
bundling: 1/4 changesets (25.00%)
bundling: 2/4 changesets (50.00%)
bundling: 3/4 changesets (75.00%)
@@ -726,7 +775,9 @@
bundling: D 1/3 files (33.33%)
bundling: E 2/3 files (66.67%)
bundling: H 3/3 files (100.00%)
- end of bundle
+ bundle2-output: payload chunk size: 1555
+ bundle2-output: closing payload chunk
+ bundle2-output: end of bundle
$ cat ../rev.hg2
HG20\x00\x00\x00\x00\x00\x00\x00\x12\x0bchangegroup\x00\x00\x00\x00\x00\x00\x00\x00\x06\x13\x00\x00\x00\xa42\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j_\xdd\xd9\x89W\xc8\xa5JMCm\xfe\x1d\xa9\xd8\x7f!\xa1\xb9{\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)6e1f4c47ecb533ffd0c8e52cdc88afb6cd39e20c (esc)
--- a/tests/test-bundle2-multiple-changegroups.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bundle2-multiple-changegroups.t Mon Jun 15 13:31:22 2015 -0500
@@ -67,9 +67,9 @@
$ cd ../clone
$ cat >> .hg/hgrc <<EOF
> [hooks]
- > pretxnchangegroup = sh -c "python \"$TESTDIR/printenv.py\" pretxnchangegroup"
- > changegroup = sh -c "python \"$TESTDIR/printenv.py\" changegroup"
- > incoming = sh -c "python \"$TESTDIR/printenv.py\" incoming"
+ > pretxnchangegroup = sh -c "printenv.py pretxnchangegroup"
+ > changegroup = sh -c "printenv.py changegroup"
+ > incoming = sh -c "printenv.py incoming"
> EOF
Pull the new commits in the clone
--- a/tests/test-bundle2-pushback.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bundle2-pushback.t Mon Jun 15 13:31:22 2015 -0500
@@ -63,11 +63,11 @@
$ hg push
pushing to ssh://user@dummy/server
searching for changes
- remote: pushback not enabled
remote: adding changesets
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
+ remote: pushback not enabled
$ hg bookmark
no bookmarks set
--- a/tests/test-bundle2-remote-changegroup.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-bundle2-remote-changegroup.t Mon Jun 15 13:31:22 2015 -0500
@@ -589,4 +589,4 @@
$ rm -rf clone
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
--- a/tests/test-check-code.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-check-code.t Mon Jun 15 13:31:22 2015 -0500
@@ -17,53 +17,6 @@
> ( 4-1 ) """, "( 1+1 )\" and ")
> a, '\\\\\\\\', "\\\\\\" x-2", "c-1"
> EOF
- $ cat > non-py24.py <<EOF
- > # Using builtins that does not exist in Python 2.4
- > if any():
- > x = all()
- > y = format(x)
- > # next(generator) is new in 2.6
- > z = next(x)
- > # but generator.next() is okay
- > x.next()
- > # and we can make our own next
- > def next(stuff):
- > pass
- >
- > # Do not complain about our own definition
- > def any(x):
- > pass
- >
- > # try/except/finally block does not exist in Python 2.4
- > try:
- > pass
- > except StandardError, inst:
- > pass
- > finally:
- > pass
- >
- > # nested try/finally+try/except is allowed
- > try:
- > try:
- > pass
- > except StandardError, inst:
- > pass
- > finally:
- > pass
- >
- > # yield inside a try/finally block is not allowed in Python 2.4
- > try:
- > pass
- > yield 1
- > finally:
- > pass
- > try:
- > yield
- > pass
- > finally:
- > pass
- >
- > EOF
$ cat > classstyle.py <<EOF
> class newstyle_class(object):
> pass
@@ -78,7 +31,7 @@
> pass
> EOF
$ check_code="$TESTDIR"/../contrib/check-code.py
- $ "$check_code" ./wrong.py ./correct.py ./quote.py ./non-py24.py ./classstyle.py
+ $ "$check_code" ./wrong.py ./correct.py ./quote.py ./classstyle.py
./wrong.py:1:
> def toto( arg1, arg2):
gratuitous whitespace in () or []
@@ -92,33 +45,12 @@
./quote.py:5:
> '"""', 42+1, """and
missing whitespace in expression
- ./non-py24.py:2:
- > if any():
- any/all/format not available in Python 2.4
- ./non-py24.py:3:
- > x = all()
- any/all/format not available in Python 2.4
- ./non-py24.py:4:
- > y = format(x)
- any/all/format not available in Python 2.4
- ./non-py24.py:6:
- > z = next(x)
- no next(foo) in Python 2.4 and 2.5, use foo.next() instead
- ./non-py24.py:18:
- > try:
- no try/except/finally in Python 2.4
- ./non-py24.py:35:
- > try:
- no yield inside try/finally in Python 2.4
- ./non-py24.py:40:
- > try:
- no yield inside try/finally in Python 2.4
./classstyle.py:4:
> class oldstyle_class:
old-style class, use class foo(object)
./classstyle.py:7:
> class empty():
- class foo() not available in Python 2.4, use class foo(object)
+ class foo() creates old style object, use class foo(object)
[1]
$ cat > python3-compat.py << EOF
> foo <> bar
--- a/tests/test-clone-update-order.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-clone-update-order.t Mon Jun 15 13:31:22 2015 -0500
@@ -14,7 +14,6 @@
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg branch other
marked working directory as branch other
- (branches are permanent and global, did you want a bookmark?)
$ echo good > bye
$ hg commit -Am other
adding bye
--- a/tests/test-clone.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-clone.t Mon Jun 15 13:31:22 2015 -0500
@@ -64,7 +64,7 @@
No update, with debug option:
#if hardlink
- $ hg --debug clone -U . ../c
+ $ hg --debug clone -U . ../c --config progress.debug=true
linking: 1
linking: 2
linking: 3
@@ -75,7 +75,7 @@
linking: 8
linked 8 files
#else
- $ hg --debug clone -U . ../c
+ $ hg --debug clone -U . ../c --config progress.debug=true
linking: 1
copying: 2
copying: 3
@@ -357,7 +357,6 @@
$ hg -R ua branch @
marked working directory as branch @
- (branches are permanent and global, did you want a bookmark?)
$ hg -R ua commit -m 'created branch @'
$ hg clone ua atbranch
updating to branch default
--- a/tests/test-command-template.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-command-template.t Mon Jun 15 13:31:22 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
@@ -952,11 +992,11 @@
$ hg log --style notexist
abort: style 'notexist' not found
- (available styles: bisect, changelog, compact, default, phases, xml)
+ (available styles: bisect, changelog, compact, default, phases, status, xml)
[255]
$ hg log -T list
- available styles: bisect, changelog, compact, default, phases, xml
+ available styles: bisect, changelog, compact, default, phases, status, xml
abort: specify a template
[255]
@@ -1898,6 +1938,8 @@
Age filter:
+ $ hg init unstable-hash
+ $ cd unstable-hash
$ hg log --template '{date|age}\n' > /dev/null || exit 1
>>> from datetime import datetime, timedelta
@@ -1911,6 +1953,15 @@
$ hg log -l1 --template '{date|age}\n'
7 years from now
+ $ cd ..
+ $ rm -rf unstable-hash
+
+Add a dummy commit to make up for the instability of the above:
+
+ $ echo a > a
+ $ hg add a
+ $ hg ci -m future
+
Count filter:
$ hg log -l1 --template '{node|count} {node|short|count}\n'
@@ -1953,6 +2004,476 @@
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"
+
+Check the status template
+
+ $ cat <<EOF >> $HGRCPATH
+ > [extensions]
+ > color=
+ > EOF
+
+ $ hg log -T status -r 10
+ changeset: 10:0f9759ec227a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Modify, add, remove, rename
+ files:
+ M third
+ A b
+ A fifth
+ R a
+ R fourth
+
+ $ hg log -T status -C -r 10
+ changeset: 10:0f9759ec227a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Modify, add, remove, rename
+ files:
+ M third
+ A b
+ A fifth
+ fourth
+ R a
+ R fourth
+
+ $ hg log -T status -C -r 10 -v
+ changeset: 10:0f9759ec227a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ description:
+ Modify, add, remove, rename
+
+ files:
+ M third
+ A b
+ A fifth
+ fourth
+ R a
+ R fourth
+
+ $ hg log -T status -C -r 10 --debug
+ changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c
+ tag: tip
+ phase: secret
+ parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ extra: branch=default
+ description:
+ Modify, add, remove, rename
+
+ files:
+ M third
+ A b
+ A fifth
+ fourth
+ R a
+ R fourth
+
+ $ hg log -T status -C -r 10 --quiet
+ 10:0f9759ec227a
+ $ hg --color=debug log -T status -r 10
+ [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
+ [log.tag|tag: tip]
+ [log.user|user: test]
+ [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
+ [log.summary|summary: Modify, add, remove, rename]
+ [ui.note log.files|files:]
+ [status.modified|M third]
+ [status.added|A b]
+ [status.added|A fifth]
+ [status.removed|R a]
+ [status.removed|R fourth]
+
+ $ hg --color=debug log -T status -C -r 10
+ [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
+ [log.tag|tag: tip]
+ [log.user|user: test]
+ [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
+ [log.summary|summary: Modify, add, remove, rename]
+ [ui.note log.files|files:]
+ [status.modified|M third]
+ [status.added|A b]
+ [status.added|A fifth]
+ [status.copied| fourth]
+ [status.removed|R a]
+ [status.removed|R fourth]
+
+ $ hg --color=debug log -T status -C -r 10 -v
+ [log.changeset changeset.secret|changeset: 10:0f9759ec227a]
+ [log.tag|tag: tip]
+ [log.user|user: test]
+ [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
+ [ui.note log.description|description:]
+ [ui.note log.description|Modify, add, remove, rename]
+
+ [ui.note log.files|files:]
+ [status.modified|M third]
+ [status.added|A b]
+ [status.added|A fifth]
+ [status.copied| fourth]
+ [status.removed|R a]
+ [status.removed|R fourth]
+
+ $ hg --color=debug log -T status -C -r 10 --debug
+ [log.changeset changeset.secret|changeset: 10:0f9759ec227a4859c2014a345cd8a859022b7c6c]
+ [log.tag|tag: tip]
+ [log.phase|phase: secret]
+ [log.parent changeset.secret|parent: 9:bf9dfba36635106d6a73ccc01e28b762da60e066]
+ [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
+ [ui.debug log.manifest|manifest: 8:89dd546f2de0a9d6d664f58d86097eb97baba567]
+ [log.user|user: test]
+ [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
+ [ui.debug log.extra|extra: branch=default]
+ [ui.note log.description|description:]
+ [ui.note log.description|Modify, add, remove, rename]
+
+ [ui.note log.files|files:]
+ [status.modified|M third]
+ [status.added|A b]
+ [status.added|A fifth]
+ [status.copied| fourth]
+ [status.removed|R a]
+ [status.removed|R fourth]
+
+ $ hg --color=debug log -T status -C -r 10 --quiet
+ [log.node|10:0f9759ec227a]
+
+Check the bisect template
+
+ $ hg bisect -g 1
+ $ hg bisect -b 3 --noupdate
+ Testing changeset 2:97054abb4ab8 (2 changesets remaining, ~1 tests)
+ $ hg log -T bisect -r 0:4
+ changeset: 0:1e4e1b8f71e0
+ bisect: good (implicit)
+ user: User Name <user@hostname>
+ date: Mon Jan 12 13:46:40 1970 +0000
+ summary: line 1
+
+ changeset: 1:b608e9d1a3f0
+ bisect: good
+ user: A. N. Other <other@place>
+ date: Tue Jan 13 17:33:20 1970 +0000
+ summary: other 1
+
+ changeset: 2:97054abb4ab8
+ bisect: untested
+ user: other@place
+ date: Wed Jan 14 21:20:00 1970 +0000
+ summary: no person
+
+ changeset: 3:10e46f2dcbf4
+ bisect: bad
+ user: person
+ date: Fri Jan 16 01:06:40 1970 +0000
+ summary: no user, no domain
+
+ changeset: 4:bbe44766e73d
+ bisect: bad (implicit)
+ branch: foo
+ user: person
+ date: Sat Jan 17 04:53:20 1970 +0000
+ summary: new branch
+
+ $ hg log --debug -T bisect -r 0:4
+ changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
+ bisect: good (implicit)
+ phase: public
+ parent: -1:0000000000000000000000000000000000000000
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0
+ user: User Name <user@hostname>
+ date: Mon Jan 12 13:46:40 1970 +0000
+ files+: a
+ extra: branch=default
+ description:
+ line 1
+ line 2
+
+
+ changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
+ bisect: good
+ phase: public
+ parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55
+ user: A. N. Other <other@place>
+ date: Tue Jan 13 17:33:20 1970 +0000
+ files+: b
+ extra: branch=default
+ description:
+ other 1
+ other 2
+
+ other 3
+
+
+ changeset: 2:97054abb4ab824450e9164180baf491ae0078465
+ bisect: untested
+ phase: public
+ parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1
+ user: other@place
+ date: Wed Jan 14 21:20:00 1970 +0000
+ files+: c
+ extra: branch=default
+ description:
+ no person
+
+
+ changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
+ bisect: bad
+ phase: public
+ parent: 2:97054abb4ab824450e9164180baf491ae0078465
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
+ user: person
+ date: Fri Jan 16 01:06:40 1970 +0000
+ files: c
+ extra: branch=default
+ description:
+ no user, no domain
+
+
+ changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74
+ bisect: bad (implicit)
+ branch: foo
+ phase: draft
+ parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47
+ parent: -1:0000000000000000000000000000000000000000
+ manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc
+ user: person
+ date: Sat Jan 17 04:53:20 1970 +0000
+ extra: branch=foo
+ description:
+ new branch
+
+
+ $ hg log -v -T bisect -r 0:4
+ changeset: 0:1e4e1b8f71e0
+ bisect: good (implicit)
+ user: User Name <user@hostname>
+ date: Mon Jan 12 13:46:40 1970 +0000
+ files: a
+ description:
+ line 1
+ line 2
+
+
+ changeset: 1:b608e9d1a3f0
+ bisect: good
+ user: A. N. Other <other@place>
+ date: Tue Jan 13 17:33:20 1970 +0000
+ files: b
+ description:
+ other 1
+ other 2
+
+ other 3
+
+
+ changeset: 2:97054abb4ab8
+ bisect: untested
+ user: other@place
+ date: Wed Jan 14 21:20:00 1970 +0000
+ files: c
+ description:
+ no person
+
+
+ changeset: 3:10e46f2dcbf4
+ bisect: bad
+ user: person
+ date: Fri Jan 16 01:06:40 1970 +0000
+ files: c
+ description:
+ no user, no domain
+
+
+ changeset: 4:bbe44766e73d
+ bisect: bad (implicit)
+ branch: foo
+ user: person
+ date: Sat Jan 17 04:53:20 1970 +0000
+ description:
+ new branch
+
+
+ $ hg --color=debug log -T bisect -r 0:4
+ [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
+ [log.bisect bisect.good|bisect: good (implicit)]
+ [log.user|user: User Name <user@hostname>]
+ [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
+ [log.summary|summary: line 1]
+
+ [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
+ [log.bisect bisect.good|bisect: good]
+ [log.user|user: A. N. Other <other@place>]
+ [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
+ [log.summary|summary: other 1]
+
+ [log.changeset changeset.public|changeset: 2:97054abb4ab8]
+ [log.bisect bisect.untested|bisect: untested]
+ [log.user|user: other@place]
+ [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
+ [log.summary|summary: no person]
+
+ [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
+ [log.bisect bisect.bad|bisect: bad]
+ [log.user|user: person]
+ [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
+ [log.summary|summary: no user, no domain]
+
+ [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
+ [log.bisect bisect.bad|bisect: bad (implicit)]
+ [log.branch|branch: foo]
+ [log.user|user: person]
+ [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
+ [log.summary|summary: new branch]
+
+ $ hg --color=debug log --debug -T bisect -r 0:4
+ [log.changeset changeset.public|changeset: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
+ [log.bisect bisect.good|bisect: good (implicit)]
+ [log.phase|phase: public]
+ [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
+ [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
+ [ui.debug log.manifest|manifest: 0:a0c8bcbbb45c63b90b70ad007bf38961f64f2af0]
+ [log.user|user: User Name <user@hostname>]
+ [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
+ [ui.debug log.files|files+: a]
+ [ui.debug log.extra|extra: branch=default]
+ [ui.note log.description|description:]
+ [ui.note log.description|line 1
+ line 2]
+
+
+ [log.changeset changeset.public|changeset: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
+ [log.bisect bisect.good|bisect: good]
+ [log.phase|phase: public]
+ [log.parent changeset.public|parent: 0:1e4e1b8f71e05681d422154f5421e385fec3454f]
+ [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
+ [ui.debug log.manifest|manifest: 1:4e8d705b1e53e3f9375e0e60dc7b525d8211fe55]
+ [log.user|user: A. N. Other <other@place>]
+ [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
+ [ui.debug log.files|files+: b]
+ [ui.debug log.extra|extra: branch=default]
+ [ui.note log.description|description:]
+ [ui.note log.description|other 1
+ other 2
+
+ other 3]
+
+
+ [log.changeset changeset.public|changeset: 2:97054abb4ab824450e9164180baf491ae0078465]
+ [log.bisect bisect.untested|bisect: untested]
+ [log.phase|phase: public]
+ [log.parent changeset.public|parent: 1:b608e9d1a3f0273ccf70fb85fd6866b3482bf965]
+ [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
+ [ui.debug log.manifest|manifest: 2:6e0e82995c35d0d57a52aca8da4e56139e06b4b1]
+ [log.user|user: other@place]
+ [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
+ [ui.debug log.files|files+: c]
+ [ui.debug log.extra|extra: branch=default]
+ [ui.note log.description|description:]
+ [ui.note log.description|no person]
+
+
+ [log.changeset changeset.public|changeset: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
+ [log.bisect bisect.bad|bisect: bad]
+ [log.phase|phase: public]
+ [log.parent changeset.public|parent: 2:97054abb4ab824450e9164180baf491ae0078465]
+ [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
+ [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
+ [log.user|user: person]
+ [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
+ [ui.debug log.files|files: c]
+ [ui.debug log.extra|extra: branch=default]
+ [ui.note log.description|description:]
+ [ui.note log.description|no user, no domain]
+
+
+ [log.changeset changeset.draft|changeset: 4:bbe44766e73d5f11ed2177f1838de10c53ef3e74]
+ [log.bisect bisect.bad|bisect: bad (implicit)]
+ [log.branch|branch: foo]
+ [log.phase|phase: draft]
+ [log.parent changeset.public|parent: 3:10e46f2dcbf4823578cf180f33ecf0b957964c47]
+ [log.parent changeset.public|parent: -1:0000000000000000000000000000000000000000]
+ [ui.debug log.manifest|manifest: 3:cb5a1327723bada42f117e4c55a303246eaf9ccc]
+ [log.user|user: person]
+ [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
+ [ui.debug log.extra|extra: branch=foo]
+ [ui.note log.description|description:]
+ [ui.note log.description|new branch]
+
+
+ $ hg --color=debug log -v -T bisect -r 0:4
+ [log.changeset changeset.public|changeset: 0:1e4e1b8f71e0]
+ [log.bisect bisect.good|bisect: good (implicit)]
+ [log.user|user: User Name <user@hostname>]
+ [log.date|date: Mon Jan 12 13:46:40 1970 +0000]
+ [ui.note log.files|files: a]
+ [ui.note log.description|description:]
+ [ui.note log.description|line 1
+ line 2]
+
+
+ [log.changeset changeset.public|changeset: 1:b608e9d1a3f0]
+ [log.bisect bisect.good|bisect: good]
+ [log.user|user: A. N. Other <other@place>]
+ [log.date|date: Tue Jan 13 17:33:20 1970 +0000]
+ [ui.note log.files|files: b]
+ [ui.note log.description|description:]
+ [ui.note log.description|other 1
+ other 2
+
+ other 3]
+
+
+ [log.changeset changeset.public|changeset: 2:97054abb4ab8]
+ [log.bisect bisect.untested|bisect: untested]
+ [log.user|user: other@place]
+ [log.date|date: Wed Jan 14 21:20:00 1970 +0000]
+ [ui.note log.files|files: c]
+ [ui.note log.description|description:]
+ [ui.note log.description|no person]
+
+
+ [log.changeset changeset.public|changeset: 3:10e46f2dcbf4]
+ [log.bisect bisect.bad|bisect: bad]
+ [log.user|user: person]
+ [log.date|date: Fri Jan 16 01:06:40 1970 +0000]
+ [ui.note log.files|files: c]
+ [ui.note log.description|description:]
+ [ui.note log.description|no user, no domain]
+
+
+ [log.changeset changeset.draft|changeset: 4:bbe44766e73d]
+ [log.bisect bisect.bad|bisect: bad (implicit)]
+ [log.branch|branch: foo]
+ [log.user|user: person]
+ [log.date|date: Sat Jan 17 04:53:20 1970 +0000]
+ [ui.note log.description|description:]
+ [ui.note log.description|new branch]
+
+
+ $ hg bisect --reset
+
Error on syntax:
$ echo 'x = "f' >> t
@@ -2249,6 +2770,39 @@
hg: parse error: date expects a date information
[255]
+Test integer literal:
+
+ $ hg log -Ra -r0 -T '{(0)}\n'
+ 0
+ $ hg log -Ra -r0 -T '{(123)}\n'
+ 123
+ $ hg log -Ra -r0 -T '{(-4)}\n'
+ -4
+ $ hg log -Ra -r0 -T '{(-)}\n'
+ hg: parse error at 2: integer literal without digits
+ [255]
+ $ hg log -Ra -r0 -T '{(-a)}\n'
+ hg: parse error at 2: integer literal without digits
+ [255]
+
+top-level integer literal is interpreted as symbol (i.e. variable name):
+
+ $ hg log -Ra -r0 -T '{1}\n'
+
+ $ hg log -Ra -r0 -T '{if("t", "{1}")}\n'
+
+ $ hg log -Ra -r0 -T '{1|stringify}\n'
+
+
+unless explicit symbol is expected:
+
+ $ hg log -Ra -r0 -T '{desc|1}\n'
+ hg: parse error: expected a symbol, got 'integer'
+ [255]
+ $ hg log -Ra -r0 -T '{1()}\n'
+ hg: parse error: expected a symbol, got 'integer'
+ [255]
+
Test string escaping:
$ hg log -R latesttag -r 0 --template '>\n<>\\n<{if(rev, "[>\n<>\\n<]")}>\n<>\\n<\n'
@@ -2280,6 +2834,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
@@ -2476,6 +3049,14 @@
1------------------- {node|short}
0------------------- test
+Test template string in pad function
+
+ $ hg log -r 0 -T '{pad("\{{rev}}", 10)} {author|user}\n'
+ {0} test
+
+ $ hg log -r 0 -T '{pad(r"\{rev}", 10)} {author|user}\n'
+ \0 test
+
Test ifcontains function
$ hg log --template '{rev} {ifcontains(rev, "2 two 0", "is in the string", "is not")}\n'
@@ -2527,20 +3108,20 @@
Rev: 0
Ancestor: 0
-Test current bookmark templating
+Test active bookmark templating
$ hg book foo
$ hg book bar
- $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, current, \"*\")} '}\n"
+ $ hg log --template "{rev} {bookmarks % '{bookmark}{ifeq(bookmark, active, \"*\")} '}\n"
2 bar* foo
1
0
- $ hg log --template "{rev} {currentbookmark}\n"
+ $ hg log --template "{rev} {activebookmark}\n"
2 bar
1
0
$ hg bookmarks --inactive bar
- $ hg log --template "{rev} {currentbookmark}\n"
+ $ hg log --template "{rev} {activebookmark}\n"
2
1
0
@@ -2565,7 +3146,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
|
@@ -2599,6 +3182,8 @@
o
|
o
+ |
+ o
o
|\
@@ -2624,7 +3209,9 @@
Test word function (including index out of bounds graceful failure)
$ hg log -Gv -R a --template "{word('1', desc)}"
- @
+ @ add,
+ |
+ o
|
o
|
@@ -2648,7 +3235,9 @@
Test word third parameter used as splitter
$ hg log -Gv -R a --template "{word('0', desc, 'o')}"
- @ future
+ @ M
+ |
+ o future
|
o third
|
@@ -2679,8 +3268,31 @@
hg: parse error: word expects two or three arguments, got 7
[255]
+Test word for integer literal
+
+ $ hg log -R a --template "{word(2, desc)}\n" -r0
+ line
+
Test word for invalid numbers
- $ hg log -Gv -R a --template "{word(2, desc)}"
- hg: parse error: Use strings like '3' for numbers passed to word function
+ $ hg log -Gv -R a --template "{word('a', desc)}"
+ hg: parse error: word expects an integer index
[255]
+
+Test indent and not adding to empty lines
+
+ $ hg log -T "-----\n{indent(desc, '>> ', ' > ')}\n" -r 0:1 -R a
+ -----
+ > line 1
+ >> line 2
+ -----
+ > other 1
+ >> other 2
+
+ >> other 3
+
+Test with non-strings like dates
+
+ $ hg log -T "{indent(date, ' ')}\n" -r 2:3 -R a
+ 1200000.00
+ 1300000.00
--- a/tests/test-commandserver.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-commandserver.t Mon Jun 15 13:31:22 2015 -0500
@@ -178,7 +178,7 @@
defaults.commit=-d "0 0"
defaults.shelve=--date "0 0"
defaults.tag=-d "0 0"
- devel.all=true
+ devel.all-warnings=true
largefiles.usercache=$TESTTMP/.cache/largefiles
ui.slash=True
ui.interactive=False
--- a/tests/test-commit-amend.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-commit-amend.t Mon Jun 15 13:31:22 2015 -0500
@@ -72,6 +72,7 @@
branch: default
commit: 1 added, 1 unknown
update: (current)
+ phases: 2 draft
$ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit --amend
transaction abort!
rollback completed
@@ -83,6 +84,7 @@
branch: default
commit: 1 added, 1 unknown
update: (current)
+ phases: 2 draft
Add new file:
$ hg ci --amend -m 'amend base1 new file'
@@ -371,7 +373,6 @@
$ hg ci -m 'branch foo'
$ hg branch default -f
marked working directory as branch default
- (branches are permanent and global, did you want a bookmark?)
$ hg ci --amend -m 'back to default'
saved backup bundle to $TESTTMP/.hg/strip-backup/8ac881fbf49d-fd962fef-amend-backup.hg (glob)
$ hg branches
@@ -846,7 +847,6 @@
$ hg up -q default
$ hg branch closewithamend
marked working directory as branch closewithamend
- (branches are permanent and global, did you want a bookmark?)
$ echo foo > foo
$ hg add foo
$ hg ci -m..
@@ -858,7 +858,6 @@
$ hg branch silliness
marked working directory as branch silliness
- (branches are permanent and global, did you want a bookmark?)
$ echo b >> b
$ hg ci --close-branch -m'open and close'
abort: can only close branch heads
--- a/tests/test-commit-interactive-curses.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-commit-interactive-curses.t Mon Jun 15 13:31:22 2015 -0500
@@ -65,14 +65,16 @@
a
a
-Committing only one hunk
+Committing only one hunk while aborting edition of hunk
- Untoggle all the hunks, go down to the second file
- unfold it
- go down to second hunk (1 for the first hunk, 1 for the first hunkline, 1 for the second hunk, 1 for the second hunklike)
- toggle the second hunk
+- edit the hunk and quit the editor imediately with non-zero status
- commit
+ $ printf "printf 'editor ran\n'; exit 1" > editor.sh
$ echo "x" > c
$ cat b >> c
$ echo "y" >> c
@@ -86,9 +88,12 @@
> KEY_DOWN
> KEY_DOWN
> TOGGLE
+ > e
> X
> EOF
- $ hg commit -i -m "one hunk" -d "0 0"
+ $ HGEDITOR="\"sh\" \"`pwd`/editor.sh\"" hg commit -i -m "one hunk" -d "0 0"
+ editor ran
+ $ rm editor.sh
$ hg tip
changeset: 2:7d10dfe755a8
tag: tip
--- a/tests/test-commit-interactive.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-commit-interactive.t Mon Jun 15 13:31:22 2015 -0500
@@ -81,6 +81,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 1 draft
Rename empty file
@@ -1290,6 +1291,33 @@
abort: error parsing patch: unhandled transition: range -> range
[255]
+Exiting editor with status 1, ignores the edit but does not stop the recording
+session
+
+ $ HGEDITOR=false hg commit -i <<EOF
+ > y
+ > e
+ > n
+ > EOF
+ diff --git a/editedfile b/editedfile
+ 1 hunks, 3 lines changed
+ examine changes to 'editedfile'? [Ynesfdaq?] y
+
+ @@ -1,3 +1,3 @@
+ -This is the first line
+ -This change will be committed
+ -This is the third line
+ +This change will not be committed
+ +This is the second line
+ +This line has been added
+ record this change to 'editedfile'? [Ynesfdaq?] e
+
+ editor exited with exit code 1
+ record this change to 'editedfile'? [Ynesfdaq?] n
+
+ no changes to record
+
+
random text in random positions is still an error
$ cat > editor.sh << '__EOF__'
--- a/tests/test-commit-multiple.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-commit-multiple.t Mon Jun 15 13:31:22 2015 -0500
@@ -52,7 +52,6 @@
1 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ hg branch release
marked working directory as branch release
- (branches are permanent and global, did you want a bookmark?)
$ hg transplant 2 3
applying [0-9a-f]{12} (re)
[0-9a-f]{12} transplanted to [0-9a-f]{12} (re)
--- a/tests/test-commit.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-commit.t Mon Jun 15 13:31:22 2015 -0500
@@ -302,7 +302,7 @@
$ cd commitmsg
$ echo changed > changed
$ echo removed > removed
- $ hg book currentbookmark
+ $ hg book activebookmark
$ hg ci -qAm init
$ hg rm removed
@@ -317,7 +317,7 @@
HG: --
HG: user: test
HG: branch 'default'
- HG: bookmark 'currentbookmark'
+ HG: bookmark 'activebookmark'
HG: added added
HG: changed changed
HG: removed removed
@@ -354,7 +354,7 @@
HG: --
HG: user: test
HG: branch 'default'
- HG: bookmark 'currentbookmark'
+ HG: bookmark 'activebookmark'
HG: subrepo sub
HG: added .hgsub
HG: added added
@@ -376,22 +376,22 @@
> [committemplate]
> changeset.commit.normal = HG: this is "commit.normal" template
> HG: {extramsg}
- > {if(currentbookmark,
- > "HG: bookmark '{currentbookmark}' is activated\n",
+ > {if(activebookmark,
+ > "HG: bookmark '{activebookmark}' is activated\n",
> "HG: no bookmark is activated\n")}{subrepos %
> "HG: subrepo '{subrepo}' is changed\n"}
>
> changeset.commit = HG: this is "commit" template
> HG: {extramsg}
- > {if(currentbookmark,
- > "HG: bookmark '{currentbookmark}' is activated\n",
+ > {if(activebookmark,
+ > "HG: bookmark '{activebookmark}' is activated\n",
> "HG: no bookmark is activated\n")}{subrepos %
> "HG: subrepo '{subrepo}' is changed\n"}
>
> changeset = HG: this is customized commit template
> HG: {extramsg}
- > {if(currentbookmark,
- > "HG: bookmark '{currentbookmark}' is activated\n",
+ > {if(activebookmark,
+ > "HG: bookmark '{activebookmark}' is activated\n",
> "HG: no bookmark is activated\n")}{subrepos %
> "HG: subrepo '{subrepo}' is changed\n"}
> EOF
@@ -404,7 +404,7 @@
$ HGEDITOR=cat hg commit -S -q
HG: this is "commit.normal" template
HG: Leave message empty to abort commit.
- HG: bookmark 'currentbookmark' is activated
+ HG: bookmark 'activebookmark' is activated
HG: subrepo 'sub' is changed
HG: subrepo 'sub2' is changed
abort: empty commit message
@@ -416,7 +416,7 @@
> # now, "changeset.commit" should be chosen for "hg commit"
> EOF
- $ hg bookmark --inactive currentbookmark
+ $ hg bookmark --inactive activebookmark
$ hg forget .hgsub
$ HGEDITOR=cat hg commit -q
HG: this is "commit" template
@@ -580,6 +580,18 @@
0 0 6 ..... 0 26d3ca0dfd18 000000000000 000000000000 (re)
1 6 7 ..... 1 d267bddd54f7 26d3ca0dfd18 000000000000 (re)
+Test making empty commits
+ $ hg commit --config ui.allowemptycommit=True -m "empty commit"
+ $ hg log -r . -v --stat
+ changeset: 2:d809f3644287
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ description:
+ empty commit
+
+
+
verify pathauditor blocks evil filepaths
$ cat > evil-commit.py <<EOF
> from mercurial import ui, hg, context, node
@@ -604,7 +616,7 @@
#endif
$ hg rollback -f
- repository tip rolled back to revision 1 (undo commit)
+ repository tip rolled back to revision 2 (undo commit)
$ cat > evil-commit.py <<EOF
> from mercurial import ui, hg, context, node
> notrc = "HG~1/hgrc"
@@ -622,7 +634,7 @@
[255]
$ hg rollback -f
- repository tip rolled back to revision 1 (undo commit)
+ repository tip rolled back to revision 2 (undo commit)
$ cat > evil-commit.py <<EOF
> from mercurial import ui, hg, context, node
> notrc = "HG8B6C~2/hgrc"
--- a/tests/test-completion.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-completion.t Mon Jun 15 13:31:22 2015 -0500
@@ -234,7 +234,7 @@
debugcommands:
debugcomplete: options
debugdag: tags, branches, dots, spaces
- debugdata: changelog, manifest
+ debugdata: changelog, manifest, dir
debugdate: extended
debugdirstate: nodates, datesort
debugdiscovery: old, nonheads, ssh, remotecmd, insecure
@@ -242,7 +242,7 @@
debugfsinfo:
debuggetbundle: head, common, type
debugignore:
- debugindex: changelog, manifest, format
+ debugindex: changelog, manifest, dir, format
debugindexdot:
debuginstall:
debugknown:
@@ -255,7 +255,7 @@
debugpvec:
debugrebuilddirstate: rev
debugrename: rev
- debugrevlog: changelog, manifest, dump
+ debugrevlog: changelog, manifest, dir, dump
debugrevspec: optimize
debugsetparents:
debugsub: rev
--- a/tests/test-convert-clonebranches.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-convert-clonebranches.t Mon Jun 15 13:31:22 2015 -0500
@@ -55,13 +55,11 @@
$ cd source
$ hg branch branch1
marked working directory as branch branch1
- (branches are permanent and global, did you want a bookmark?)
$ echo a > file1
$ hg ci -qAm c1
$ hg up -qC mergeab
$ hg branch branch2
marked working directory as branch branch2
- (branches are permanent and global, did you want a bookmark?)
$ echo a > file2
$ hg ci -qAm c2
$ hg merge branch1
@@ -69,7 +67,6 @@
(branch merge, don't forget to commit)
$ hg branch branch3
marked working directory as branch branch3
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -qAm c3
$ cd ..
--- a/tests/test-convert-cvs.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-convert-cvs.t Mon Jun 15 13:31:22 2015 -0500
@@ -121,7 +121,7 @@
1 ci0
0 import
filtering out empty revision
- repository tip rolled back to revision 1 (undo commit)
+ repository tip rolled back to revision 1 (undo convert)
updating tags
$ hgcat b/c
c
--- a/tests/test-convert-datesort.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-convert-datesort.t Mon Jun 15 13:31:22 2015 -0500
@@ -21,7 +21,6 @@
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg branch branchb
marked working directory as branch branchb
- (branches are permanent and global, did you want a bookmark?)
$ echo b >> b
$ hg ci -Am b0 -d '6 0'
adding b
@@ -42,7 +41,6 @@
$ echo c >> c
$ hg branch branchc
marked working directory as branch branchc
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -Am c0 -d '10 0'
adding c
$ hg up -C brancha
--- a/tests/test-convert-filemap.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-convert-filemap.t Mon Jun 15 13:31:22 2015 -0500
@@ -438,7 +438,7 @@
$ hg ci -m 'merging something'
$ cd ..
$ echo "53792d18237d2b64971fa571936869156655338d 6d955580116e82c4b029bd30f321323bae71a7f0" >> branchpruning-hg2/.hg/shamap
- $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2 --debug
+ $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2 --debug --config progress.debug=true
run hg source pre-conversion action
run hg sink pre-conversion action
scanning source...
@@ -477,7 +477,7 @@
2 add
1 rename
filtering out empty revision
- repository tip rolled back to revision 0 (undo commit)
+ repository tip rolled back to revision 0 (undo convert)
0 modify
$ glog -R renameundo2
o 1 "modify" files: a c
--- a/tests/test-convert-hg-sink.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-convert-hg-sink.t Mon Jun 15 13:31:22 2015 -0500
@@ -41,6 +41,7 @@
date: Thu Jan 01 00:00:00 1970 +0000
summary: add foo and bar
+ $ hg phase --public -r tip
$ cd ..
$ hg convert orig new 2>&1 | grep -v 'subversion python bindings could not be loaded'
initializing destination new repository
@@ -52,6 +53,16 @@
1 add foo/file
0 Added tag some-tag for changeset ad681a868e44
$ cd new
+ $ hg log -G --template '{rev} {node|short} ({phase}) "{desc}"\n'
+ o 3 593cbf6fb2b4 (public) "Added tag some-tag for changeset ad681a868e44"
+ |
+ o 2 ad681a868e44 (public) "add foo/file"
+ |
+ o 1 cbba8ecc03b7 (public) "remove foo"
+ |
+ o 0 327daa9251fa (public) "add foo and bar"
+
+
$ hg out ../orig
comparing with ../orig
searching for changes
@@ -132,7 +143,7 @@
$ glog()
> {
- > hg log -G --template '{rev} {node|short} "{desc}" files: {files}\n' $*
+ > hg log -G --template '{rev} {node|short} ({phase}) "{desc}" files: {files}\n' $*
> }
Create a tricky source repo
@@ -171,20 +182,21 @@
dir/c
dir/d
e
+ $ hg phase --public -r tip
$ glog
- @ 6 0613c8e59a3d "6: change a" files: a
+ @ 6 0613c8e59a3d (public) "6: change a" files: a
|
- o 5 717e9b37cdb7 "5: merge 2 and 3, copy b to dir/d" files: dir/d e
+ o 5 717e9b37cdb7 (public) "5: merge 2 and 3, copy b to dir/d" files: dir/d e
|\
- | o 4 86a55cb968d5 "4: change a" files: a
+ | o 4 86a55cb968d5 (public) "4: change a" files: a
| |
- o | 3 0e6e235919dd "3: copy a to e, change b" files: b e
+ o | 3 0e6e235919dd (public) "3: copy a to e, change b" files: b e
| |
- o | 2 0394b0d5e4f7 "2: add dir/c" files: dir/c
+ o | 2 0394b0d5e4f7 (public) "2: add dir/c" files: dir/c
|/
- o 1 333546584845 "1: add a and dir/b" files: a dir/b
+ o 1 333546584845 (public) "1: add a and dir/b" files: a dir/b
|
- o 0 d1a24e2ebd23 "0: add 0" files: 0
+ o 0 d1a24e2ebd23 (public) "0: add 0" files: 0
$ cd ..
@@ -209,15 +221,15 @@
Verify that conversion skipped rev 2:
$ glog -R dest
- o 4 78814e84a217 "6: change a" files: a
+ o 4 78814e84a217 (draft) "6: change a" files: a
|
- o 3 f7cff662c5e5 "5: merge 2 and 3, copy b to dir/d" files: e
+ o 3 f7cff662c5e5 (draft) "5: merge 2 and 3, copy b to dir/d" files: e
|\
- | o 2 ab40a95b0072 "4: change a" files: a
+ | o 2 ab40a95b0072 (draft) "4: change a" files: a
| |
- o | 1 bd51f17597bf "3: copy a to e, change b" files: b e
+ o | 1 bd51f17597bf (draft) "3: copy a to e, change b" files: b e
|/
- o 0 a4a1dae0fe35 "1: add a and dir/b" files: 0 a
+ o 0 a4a1dae0fe35 (draft) "1: add a and dir/b" files: 0 a
Verify mapping correct in both directions:
@@ -347,17 +359,17 @@
e
$ glog -r 6:
- @ 11 0c8927d1f7f4 "11: source change" files: a
+ @ 11 0c8927d1f7f4 (draft) "11: source change" files: a
|
- o 10 9ccb7ee8d261 "10: source merge" files: a
+ o 10 9ccb7ee8d261 (draft) "10: source merge" files: a
|\
- | o 9 f131b1518dba "9: source second branch" files: a
+ | o 9 f131b1518dba (draft) "9: source second branch" files: a
| |
- o | 8 669cf0e74b50 "8: source first branch" files: a
+ o | 8 669cf0e74b50 (draft) "8: source first branch" files: a
| |
- | o 7 e6d364a69ff1 "change in dest" files: dest
+ | o 7 e6d364a69ff1 (draft) "change in dest" files: dest
|/
- o 6 0613c8e59a3d "6: change a" files: a
+ o 6 0613c8e59a3d (public) "6: change a" files: a
|
$ cd ..
@@ -371,25 +383,25 @@
0 11: source change
$ glog -R dest
- o 9 8432d597b263 "11: source change" files: a
+ o 9 8432d597b263 (draft) "11: source change" files: a
|
- o 8 632ffacdcd6f "10: source merge" files: a
+ o 8 632ffacdcd6f (draft) "10: source merge" files: a
|\
- | o 7 049cfee90ee6 "9: source second branch" files: a
+ | o 7 049cfee90ee6 (draft) "9: source second branch" files: a
| |
- o | 6 9b6845e036e5 "8: source first branch" files: a
+ o | 6 9b6845e036e5 (draft) "8: source first branch" files: a
| |
- | @ 5 a2e0e3cc6d1d "change in dest" files: dest
+ | @ 5 a2e0e3cc6d1d (draft) "change in dest" files: dest
|/
- o 4 78814e84a217 "6: change a" files: a
+ o 4 78814e84a217 (draft) "6: change a" files: a
|
- o 3 f7cff662c5e5 "5: merge 2 and 3, copy b to dir/d" files: e
+ o 3 f7cff662c5e5 (draft) "5: merge 2 and 3, copy b to dir/d" files: e
|\
- | o 2 ab40a95b0072 "4: change a" files: a
+ | o 2 ab40a95b0072 (draft) "4: change a" files: a
| |
- o | 1 bd51f17597bf "3: copy a to e, change b" files: b e
+ o | 1 bd51f17597bf (draft) "3: copy a to e, change b" files: b e
|/
- o 0 a4a1dae0fe35 "1: add a and dir/b" files: 0 a
+ o 0 a4a1dae0fe35 (draft) "1: add a and dir/b" files: 0 a
$ cd ..
@@ -520,7 +532,7 @@
Conversion after rollback
$ hg -R a rollback -f
- repository tip rolled back to revision 2 (undo commit)
+ repository tip rolled back to revision 2 (undo convert)
$ hg convert --filemap filemap-b 0 a --config convert.hg.revs=1::
scanning source...
--- a/tests/test-convert-mtn.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-convert-mtn.t Mon Jun 15 13:31:22 2015 -0500
@@ -220,7 +220,7 @@
>>> fp = file('large-file', 'wb')
>>> for x in xrange(10000): fp.write('%d\n' % x)
>>> fp.close()
- $ $TESTDIR/md5sum.py large-file
+ $ md5sum.py large-file
5d6de8a95c3b6bf9e0ffb808ba5299c1 large-file
$ mtn add large-file
mtn: adding 'large-file' to workspace manifest
@@ -386,7 +386,7 @@
test large file support (> 32kB)
- $ $TESTDIR/md5sum.py large-file
+ $ md5sum.py large-file
5d6de8a95c3b6bf9e0ffb808ba5299c1 large-file
check branch closing
--- a/tests/test-convert-svn-encoding.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-convert-svn-encoding.t Mon Jun 15 13:31:22 2015 -0500
@@ -10,7 +10,7 @@
Convert while testing all possible outputs
- $ hg --debug convert svn-repo A-hg
+ $ hg --debug convert svn-repo A-hg --config progress.debug=1
initializing destination A-hg repository
reparent to file://*/svn-repo (glob)
run hg sink pre-conversion action
--- a/tests/test-convert-svn-sink.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-convert-svn-sink.t Mon Jun 15 13:31:22 2015 -0500
@@ -32,7 +32,7 @@
Modify
- $ "$TESTDIR/svn-safe-append.py" a a/a
+ $ svn-safe-append.py a a/a
$ hg --cwd a ci -d '1 0' -m 'modify a file'
$ hg --cwd a tip -q
1:e0e2b8a9156b
@@ -354,12 +354,12 @@
$ hg --cwd b ci -d '0 0' -Ambase
adding b
- $ "$TESTDIR/svn-safe-append.py" left-1 b/b
+ $ svn-safe-append.py left-1 b/b
$ echo left-1 > b/left-1
$ hg --cwd b ci -d '1 0' -Amleft-1
adding left-1
- $ "$TESTDIR/svn-safe-append.py" left-2 b/b
+ $ svn-safe-append.py left-2 b/b
$ echo left-2 > b/left-2
$ hg --cwd b ci -d '2 0' -Amleft-2
adding left-2
@@ -367,13 +367,13 @@
$ hg --cwd b up 0
1 files updated, 0 files merged, 2 files removed, 0 files unresolved
- $ "$TESTDIR/svn-safe-append.py" right-1 b/b
+ $ svn-safe-append.py right-1 b/b
$ echo right-1 > b/right-1
$ hg --cwd b ci -d '3 0' -Amright-1
adding right-1
created new head
- $ "$TESTDIR/svn-safe-append.py" right-2 b/b
+ $ svn-safe-append.py right-2 b/b
$ echo right-2 > b/right-2
$ hg --cwd b ci -d '4 0' -Amright-2
adding right-2
--- a/tests/test-convert-svn-source.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-convert-svn-source.t Mon Jun 15 13:31:22 2015 -0500
@@ -46,7 +46,7 @@
Transmitting file data .
Committed revision 2.
- $ "$TESTDIR/svn-safe-append.py" world 'letter .txt'
+ $ svn-safe-append.py world 'letter .txt'
$ svn ci -m world
Sending letter .txt
Transmitting file data .
@@ -56,7 +56,7 @@
Committed revision 4.
- $ "$TESTDIR/svn-safe-append.py" 'nice day today!' 'letter .txt'
+ $ svn-safe-append.py 'nice day today!' 'letter .txt'
$ svn ci -m "nice day"
Sending letter .txt
Transmitting file data .
@@ -86,7 +86,7 @@
Update svn repository again
$ cd B
- $ "$TESTDIR/svn-safe-append.py" "see second letter" 'letter .txt'
+ $ svn-safe-append.py "see second letter" 'letter .txt'
$ echo "nice to meet you" > letter2.txt
$ svn add letter2.txt
A letter2.txt
@@ -100,7 +100,7 @@
Committed revision 7.
- $ "$TESTDIR/svn-safe-append.py" "blah-blah-blah" letter2.txt
+ $ svn-safe-append.py "blah-blah-blah" letter2.txt
$ svn ci -m "work in progress"
Sending letter2.txt
Transmitting file data .
--- a/tests/test-convert.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-convert.t Mon Jun 15 13:31:22 2015 -0500
@@ -279,6 +279,12 @@
Mercurial Destination
#####################
+ The Mercurial destination will recognize Mercurial subrepositories in the
+ destination directory, and update the .hgsubstate file automatically if
+ the destination subrepositories contain the <dest>/<sub>/.hg/shamap file.
+ Converting a repository with subrepositories requires converting a single
+ repository at a time, from the bottom up.
+
The following options are supported:
convert.hg.clonebranches
--- a/tests/test-copy-move-merge.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-copy-move-merge.t Mon Jun 15 13:31:22 2015 -0500
@@ -35,13 +35,11 @@
preserving a for resolve of c
removing a
b: remote moved from a -> m
- updating: b 1/2 files (50.00%)
picked tool 'internal:merge' for b (binary False symlink False)
merging a and b to b
my b@add3f11052fa+ other b@17c05bb7fcb6 ancestor a@b8bf91eeebbc
premerge successful
c: remote moved from a -> m
- updating: c 2/2 files (100.00%)
picked tool 'internal:merge' for c (binary False symlink False)
merging a and c to c
my c@add3f11052fa+ other c@17c05bb7fcb6 ancestor a@b8bf91eeebbc
--- a/tests/test-copy.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-copy.t Mon Jun 15 13:31:22 2015 -0500
@@ -19,6 +19,7 @@
branch: default
commit: 1 copied
update: (current)
+ phases: 1 draft
$ hg --debug commit -m "2"
committing files:
b
@@ -85,13 +86,13 @@
copy: a
copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
- $ "$TESTDIR/md5sum.py" .hg/store/data/b.i
+ $ md5sum.py .hg/store/data/b.i
4999f120a3b88713bbefddd195cf5133 .hg/store/data/b.i
$ hg cat b > bsum
- $ "$TESTDIR/md5sum.py" bsum
+ $ md5sum.py bsum
60b725f10c9c85c70d97880dfe8191b3 bsum
$ hg cat a > asum
- $ "$TESTDIR/md5sum.py" asum
+ $ md5sum.py asum
60b725f10c9c85c70d97880dfe8191b3 asum
$ hg verify
checking changesets
--- a/tests/test-debugbuilddag.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-debugbuilddag.t Mon Jun 15 13:31:22 2015 -0500
@@ -10,37 +10,20 @@
\r (no-eol) (esc)
building [ ] 0/12\r (no-eol) (esc)
building [ ] 0/12\r (no-eol) (esc)
- building [ ] 0/12\r (no-eol) (esc)
- building [ ] 0/12\r (no-eol) (esc)
- building [==> ] 1/12\r (no-eol) (esc)
- building [==> ] 1/12\r (no-eol) (esc)
building [==> ] 1/12\r (no-eol) (esc)
building [==> ] 1/12\r (no-eol) (esc)
building [======> ] 2/12\r (no-eol) (esc)
- building [======> ] 2/12\r (no-eol) (esc)
- building [=========> ] 3/12\r (no-eol) (esc)
building [=========> ] 3/12\r (no-eol) (esc)
building [=============> ] 4/12\r (no-eol) (esc)
building [=============> ] 4/12\r (no-eol) (esc)
building [=============> ] 4/12\r (no-eol) (esc)
- building [=============> ] 4/12\r (no-eol) (esc)
- building [=============> ] 4/12\r (no-eol) (esc)
- building [=============> ] 4/12\r (no-eol) (esc)
- building [================> ] 5/12\r (no-eol) (esc)
building [================> ] 5/12\r (no-eol) (esc)
building [====================> ] 6/12\r (no-eol) (esc)
- building [====================> ] 6/12\r (no-eol) (esc)
- building [=======================> ] 7/12\r (no-eol) (esc)
building [=======================> ] 7/12\r (no-eol) (esc)
building [===========================> ] 8/12\r (no-eol) (esc)
building [===========================> ] 8/12\r (no-eol) (esc)
- building [===========================> ] 8/12\r (no-eol) (esc)
- building [===========================> ] 8/12\r (no-eol) (esc)
- building [==============================> ] 9/12\r (no-eol) (esc)
building [==============================> ] 9/12\r (no-eol) (esc)
building [==================================> ] 10/12\r (no-eol) (esc)
- building [==================================> ] 10/12\r (no-eol) (esc)
- building [=====================================> ] 11/12\r (no-eol) (esc)
building [=====================================> ] 11/12\r (no-eol) (esc)
\r (no-eol) (esc)
--- a/tests/test-devel-warnings.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-devel-warnings.t Mon Jun 15 13:31:22 2015 -0500
@@ -3,7 +3,7 @@
> """A small extension that acquire locks in the wrong order
> """
>
- > from mercurial import cmdutil
+ > from mercurial import cmdutil, repair
>
> cmdtable = {}
> command = cmdutil.command(cmdtable)
@@ -38,13 +38,22 @@
> wl = repo.wlock(wait=False)
> wl.release()
> lo.release()
+ >
+ > @command('stripintr', [], '')
+ > def stripintr(ui, repo):
+ > lo = repo.lock()
+ > tr = repo.transaction('foobar')
+ > try:
+ > repair.strip(repo.ui, repo, [repo['.'].node()])
+ > finally:
+ > lo.release()
> EOF
$ cat << EOF >> $HGRCPATH
> [extensions]
> buggylocking=$TESTTMP/buggylocking.py
> [devel]
- > all=1
+ > all-warnings=1
> EOF
$ hg init lock-checker
@@ -87,4 +96,14 @@
$TESTTMP/buggylocking.py:* in buggylocking (glob)
$ hg properlocking
$ hg nowaitlocking
+
+ $ echo a > a
+ $ hg add a
+ $ hg commit -m a
+ $ hg stripintr
+ saved backup bundle to $TESTTMP/lock-checker/.hg/strip-backup/cb9a9f314b8b-cc5ccb0b-backup.hg (glob)
+ abort: programming error: cannot strip from inside a transaction
+ (contact your extension maintainer)
+ [255]
+
$ cd ..
--- a/tests/test-doctest.py Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-doctest.py Mon Jun 15 13:31:22 2015 -0500
@@ -21,6 +21,7 @@
testmod('mercurial.minirst')
testmod('mercurial.patch')
testmod('mercurial.pathutil')
+testmod('mercurial.parser')
testmod('mercurial.revset')
testmod('mercurial.store')
testmod('mercurial.subrepo')
--- a/tests/test-double-merge.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-double-merge.t Mon Jun 15 13:31:22 2015 -0500
@@ -38,13 +38,11 @@
preserving foo for resolve of bar
preserving foo for resolve of foo
bar: remote copied from foo -> m
- updating: bar 1/2 files (50.00%)
picked tool 'internal:merge' for bar (binary False symlink False)
merging foo and bar to bar
my bar@6a0df1dad128+ other bar@484bf6903104 ancestor foo@e6dc8efe11cc
premerge successful
foo: versions differ -> m
- updating: foo 2/2 files (100.00%)
picked tool 'internal:merge' for foo (binary False symlink False)
merging foo
my foo@6a0df1dad128+ other foo@484bf6903104 ancestor foo@e6dc8efe11cc
--- a/tests/test-encoding-align.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-encoding-align.t Mon Jun 15 13:31:22 2015 -0500
@@ -119,12 +119,10 @@
$ hg book -f $S
$ hg branch $M
marked working directory as branch MIDDLE_
- (branches are permanent and global, did you want a bookmark?)
$ hg tag $M
$ hg book -f $M
$ hg branch $L
marked working directory as branch \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d (esc)
- (branches are permanent and global, did you want a bookmark?)
$ hg tag $L
$ hg book -f $L
--- a/tests/test-fetch.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-fetch.t Mon Jun 15 13:31:22 2015 -0500
@@ -168,7 +168,6 @@
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg -R nbase branch b
marked working directory as branch b
- (branches are permanent and global, did you want a bookmark?)
$ echo b > nbase/b
$ hg -R nbase ci -Am b
adding b
@@ -363,7 +362,6 @@
adding b
$ hg --cwd ib1 branch -f default
marked working directory as branch default
- (branches are permanent and global, did you want a bookmark?)
$ echo c > ib1/c
$ hg --cwd ib1 ci -Am newdefault
adding c
--- a/tests/test-fileset.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-fileset.t Mon Jun 15 13:31:22 2015 -0500
@@ -16,15 +16,21 @@
Test operators and basic patterns
- $ fileset a1
+ $ fileset -v a1
+ ('symbol', 'a1')
a1
- $ fileset 'a*'
+ $ fileset -v 'a*'
+ ('symbol', 'a*')
a1
a2
- $ fileset '"re:a\d"'
+ $ fileset -v '"re:a\d"'
+ ('string', 're:a\\d')
a1
a2
- $ fileset 'a1 or a2'
+ $ fileset -v 'a1 or a2'
+ (or
+ ('symbol', 'a1')
+ ('symbol', 'a2'))
a1
a2
$ fileset 'a1 | a2'
@@ -174,16 +180,54 @@
$ hg -R sub add sub/suba
$ hg -R sub ci -m sub
$ echo 'sub = sub' > .hgsub
+ $ hg init sub2
+ $ echo b > sub2/b
+ $ hg -R sub2 ci -Am sub2
+ adding b
+ $ echo 'sub2 = sub2' >> .hgsub
$ fileset 'subrepo()'
$ hg add .hgsub
$ fileset 'subrepo()'
sub
+ sub2
$ fileset 'subrepo("sub")'
sub
$ fileset 'subrepo("glob:*")'
sub
+ sub2
$ hg ci -m subrepo
+Test that .hgsubstate is updated as appropriate during a conversion. The
+saverev property is enough to alter the hashes of the subrepo.
+
+ $ hg init ../converted
+ $ hg --config extensions.convert= convert --config convert.hg.saverev=True \
+ > sub ../converted/sub
+ initializing destination ../converted/sub repository
+ scanning source...
+ sorting...
+ converting...
+ 0 sub
+ $ hg clone -U sub2 ../converted/sub2
+ $ hg --config extensions.convert= convert --config convert.hg.saverev=True \
+ > . ../converted
+ scanning source...
+ sorting...
+ converting...
+ 4 addfiles
+ 3 manychanges
+ 2 diverging
+ 1 merge
+ 0 subrepo
+ no ".hgsubstate" updates will be made for "sub2"
+ $ hg up -q -R ../converted -r tip
+ $ hg --cwd ../converted cat sub/suba sub2/b -r tip
+ a
+ b
+ $ oldnode=`hg log -r tip -T "{node}\n"`
+ $ newnode=`hg log -R ../converted -r tip -T "{node}\n"`
+ $ [[ "$oldnode" != "$newnode" ]] || echo "nothing changed"
+
Test with a revision
$ hg log -G --template '{rev} {desc}\n'
@@ -235,6 +279,7 @@
$ fileset -r4 'subrepo("re:su.*")'
sub
+ sub2
$ fileset -r4 'subrepo("sub")'
sub
$ fileset -r4 'b2 or c1'
--- a/tests/test-globalopts.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-globalopts.t Mon Jun 15 13:31:22 2015 -0500
@@ -88,6 +88,7 @@
[255]
$ hg -R b ann a/a
abort: a/a not under root '$TESTTMP/b' (glob)
+ (consider using '--cwd b')
[255]
$ hg log
abort: no repository found in '$TESTTMP' (.hg not found)!
--- a/tests/test-glog.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-glog.t Mon Jun 15 13:31:22 2015 -0500
@@ -89,7 +89,7 @@
> if opts.get('print_revset'):
> expr = cmdutil.getgraphlogrevs(repo, pats, opts)[1]
> if expr:
- > tree = revset.parse(expr)[0]
+ > tree = revset.parse(expr)
> else:
> tree = []
> ui.write('%r\n' % (opts.get('rev', []),))
@@ -1469,13 +1469,12 @@
(group
(group
(or
- (or
- (func
- ('symbol', 'branch')
- ('string', 'default'))
- (func
- ('symbol', 'branch')
- ('string', 'branch')))
+ (func
+ ('symbol', 'branch')
+ ('string', 'default'))
+ (func
+ ('symbol', 'branch')
+ ('string', 'branch'))
(func
('symbol', 'branch')
('string', 'branch')))))
--- a/tests/test-gpg.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-gpg.t Mon Jun 15 13:31:22 2015 -0500
@@ -38,7 +38,7 @@
verify that this test has not modified the trustdb.gpg file back in
the main hg working dir
- $ "$TESTDIR/md5sum.py" "$TESTDIR/gpg/trustdb.gpg"
+ $ md5sum.py "$TESTDIR/gpg/trustdb.gpg"
f6b9c78c65fa9536e7512bb2ceb338ae */gpg/trustdb.gpg (glob)
don't leak any state to next test run
--- a/tests/test-graft.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-graft.t Mon Jun 15 13:31:22 2015 -0500
@@ -154,7 +154,6 @@
ancestor: 68795b066622, local: ef0ef43d49e7+, remote: 5d205f8b35b6
preserving b for resolve of b
b: local copied/moved from a -> m
- updating: b 1/1 files (100.00%)
picked tool 'internal:merge' for b (binary False symlink False)
merging b and a to b
my b@ef0ef43d49e7+ other a@5d205f8b35b6 ancestor a@68795b066622
@@ -170,7 +169,6 @@
ancestor: 4c60f11aa304, local: 6b9e5368ca4e+, remote: 97f8bfe72746
e: remote is newer -> g
getting e
- updating: e 1/1 files (100.00%)
b: remote unchanged -> k
committing files:
e
@@ -184,10 +182,8 @@
preserving e for resolve of e
d: remote is newer -> g
getting d
- updating: d 1/2 files (50.00%)
b: remote unchanged -> k
e: versions differ -> m
- updating: e 2/2 files (100.00%)
picked tool 'internal:merge' for e (binary False symlink False)
merging e
my e@1905859650ec+ other e@9c233e8e184d ancestor e@68795b066622
--- a/tests/test-hardlinks.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hardlinks.t Mon Jun 15 13:31:22 2015 -0500
@@ -57,7 +57,7 @@
Create hardlinked clone r2:
- $ hg clone -U --debug r1 r2
+ $ hg clone -U --debug r1 r2 --config progress.debug=true
linking: 1
linking: 2
linking: 3
--- a/tests/test-help.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-help.t Mon Jun 15 13:31:22 2015 -0500
@@ -264,7 +264,6 @@
notify hooks for sending email push notifications
pager browse command output with an external pager
patchbomb command to send changesets as (a series of) patch emails
- progress show progress bars for some actions
purge command to delete untracked files from the working
directory
record commands to interactively select changes for
@@ -1251,7 +1250,7 @@
$ hg serve -R "$TESTTMP/test" -n test -p $HGPORT -d --pid-file=hg.pid
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help"
+ $ get-with-headers.py 127.0.0.1:$HGPORT "help"
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -1802,7 +1801,7 @@
</html>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/add"
+ $ get-with-headers.py 127.0.0.1:$HGPORT "help/add"
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -1962,7 +1961,7 @@
</html>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/remove"
+ $ get-with-headers.py 127.0.0.1:$HGPORT "help/remove"
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -2155,7 +2154,7 @@
</html>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT "help/revisions"
+ $ get-with-headers.py 127.0.0.1:$HGPORT "help/revisions"
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -2250,6 +2249,6 @@
</html>
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
#endif
--- a/tests/test-hghave.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hghave.t Mon Jun 15 13:31:22 2015 -0500
@@ -1,3 +1,3 @@
Testing that hghave does not crash when checking features
- $ "$TESTDIR/hghave" --test-features 2>/dev/null
+ $ hghave --test-features 2>/dev/null
--- a/tests/test-hgignore.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgignore.t Mon Jun 15 13:31:22 2015 -0500
@@ -167,3 +167,78 @@
? a.c
? a.o
? syntax
+
+Check using 'include:' in ignore file
+
+ $ hg purge --all --config extensions.purge=
+ $ touch foo.included
+
+ $ echo ".*.included" > otherignore
+ $ hg status -I "include:otherignore"
+ ? foo.included
+
+ $ echo "include:otherignore" >> .hgignore
+ $ hg status
+ A dir/b.o
+ ? .hgignore
+ ? otherignore
+
+Check recursive uses of 'include:'
+
+ $ echo "include:nestedignore" >> otherignore
+ $ echo "glob:*ignore" > nestedignore
+ $ hg status
+ A dir/b.o
+
+ $ cp otherignore goodignore
+ $ echo "include:badignore" >> otherignore
+ $ hg status
+ skipping unreadable pattern file 'badignore': No such file or directory
+ A dir/b.o
+
+ $ mv goodignore otherignore
+
+Check including subincludes
+
+ $ hg revert -q --all
+ $ hg purge --all --config extensions.purge=
+ $ echo ".hgignore" > .hgignore
+ $ mkdir dir1 dir2
+ $ touch dir1/file1 dir1/file2 dir2/file1 dir2/file2
+ $ echo "subinclude:dir2/.hgignore" >> .hgignore
+ $ echo "glob:file*2" > dir2/.hgignore
+ $ hg status
+ ? dir1/file1
+ ? dir1/file2
+ ? dir2/file1
+
+Check including subincludes with regexs
+
+ $ echo "subinclude:dir1/.hgignore" >> .hgignore
+ $ echo "regexp:f.le1" > dir1/.hgignore
+
+ $ hg status
+ ? dir1/file2
+ ? dir2/file1
+
+Check multiple levels of sub-ignores
+
+ $ mkdir dir1/subdir
+ $ touch dir1/subdir/subfile1 dir1/subdir/subfile3 dir1/subdir/subfile4
+ $ echo "subinclude:subdir/.hgignore" >> dir1/.hgignore
+ $ echo "glob:subfil*3" >> dir1/subdir/.hgignore
+
+ $ hg status
+ ? dir1/file2
+ ? dir1/subdir/subfile4
+ ? dir2/file1
+
+Check include subignore at the same level
+
+ $ mv dir1/subdir/.hgignore dir1/.hgignoretwo
+ $ echo "regexp:f.le1" > dir1/.hgignore
+ $ echo "subinclude:.hgignoretwo" >> dir1/.hgignore
+ $ echo "glob:file*2" > dir1/.hgignoretwo
+
+ $ hg status | grep file2
+ [1]
--- a/tests/test-hgweb-bundle.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgweb-bundle.t Mon Jun 15 13:31:22 2015 -0500
@@ -27,7 +27,7 @@
Ensure we're serving from the bundle
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/?style=raw')
+ $ (get-with-headers.py localhost:$HGPORT 'file/tip/?style=raw')
200 Script output follows
--- a/tests/test-hgweb-commands.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgweb-commands.t Mon Jun 15 13:31:22 2015 -0500
@@ -26,7 +26,6 @@
$ hg ci -Ambranch
$ hg branch unstable
marked working directory as branch unstable
- (branches are permanent and global, did you want a bookmark?)
>>> open('msg', 'wb').write('branch commit with null character: \0\n')
$ hg ci -l msg
$ rm msg
@@ -54,7 +53,7 @@
Logs and changes
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log/?style=atom'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log/?style=atom'
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -240,7 +239,7 @@
</entry>
</feed>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log/?style=rss'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log/?style=rss'
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -414,7 +413,7 @@
</channel>
</rss> (no-eol)
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log/1/?style=atom'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log/1/?style=atom'
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -514,7 +513,7 @@
</entry>
</feed>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log/1/?style=rss'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log/1/?style=rss'
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -608,7 +607,7 @@
</channel>
</rss> (no-eol)
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log/1/foo/?style=atom'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log/1/foo/?style=atom'
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -663,7 +662,7 @@
</entry>
</feed>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log/1/foo/?style=rss'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log/1/foo/?style=rss'
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -684,7 +683,7 @@
</channel>
</rss>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'shortlog/'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'shortlog/'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -762,22 +761,34 @@
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/cad8025a2e87">branch commit with null character: </a><span class="branchhead">unstable</span> <span class="tag">tip</span> <span class="tag">something</span> </td>
+ <td class="description">
+ <a href="/rev/cad8025a2e87">branch commit with null character: </a>
+ <span class="branchhead">unstable</span> <span class="tag">tip</span> <span class="tag">something</span>
+ </td>
</tr>
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/1d22e65f027e">branch</a><span class="branchhead">stable</span> </td>
+ <td class="description">
+ <a href="/rev/1d22e65f027e">branch</a>
+ <span class="branchhead">stable</span>
+ </td>
</tr>
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/a4f92ed23982">Added tag 1.0 for changeset 2ef0ac749a14</a><span class="branchhead">default</span> </td>
+ <td class="description">
+ <a href="/rev/a4f92ed23982">Added tag 1.0 for changeset 2ef0ac749a14</a>
+ <span class="branchhead">default</span>
+ </td>
</tr>
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/2ef0ac749a14">base</a><span class="tag">1.0</span> <span class="tag">anotherthing</span> </td>
+ <td class="description">
+ <a href="/rev/2ef0ac749a14">base</a>
+ <span class="tag">1.0</span> <span class="tag">anotherthing</span>
+ </td>
</tr>
</tbody>
@@ -813,7 +824,7 @@
</body>
</html>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'rev/0/'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'rev/0/'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -942,7 +953,7 @@
</body>
</html>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'rev/1/?style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'rev/1/?style=raw'
200 Script output follows
@@ -959,7 +970,7 @@
@@ -0,0 +1,1 @@
+2ef0ac749a14e4f57a5a822464a0902c6f7f448f 1.0
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=base'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=base'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -986,6 +997,8 @@
<li><a href="/tags">tags</a></li>
<li><a href="/bookmarks">bookmarks</a></li>
<li><a href="/branches">branches</a></li>
+ </ul>
+ <ul>
<li><a href="/help">help</a></li>
</ul>
</div>
@@ -1024,7 +1037,10 @@
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/2ef0ac749a14">base</a><span class="tag">1.0</span> <span class="tag">anotherthing</span> </td>
+ <td class="description">
+ <a href="/rev/2ef0ac749a14">base</a>
+ <span class="tag">1.0</span> <span class="tag">anotherthing</span>
+ </td>
</tr>
</tbody>
@@ -1044,12 +1060,12 @@
</body>
</html>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=stable&style=raw' | grep 'revision:'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=stable&style=raw' | grep 'revision:'
revision: 2
Search with revset syntax
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=tip^&style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=tip^&style=raw'
200 Script output follows
@@ -1066,7 +1082,7 @@
branch: stable
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(all(),2)^&style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=last(all(),2)^&style=raw'
200 Script output follows
@@ -1090,7 +1106,7 @@
branch: default
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(all(,2)^&style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=last(all(,2)^&style=raw'
200 Script output follows
@@ -1100,7 +1116,7 @@
# Mode literal keyword search
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=last(al(),2)^&style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=last(al(),2)^&style=raw'
200 Script output follows
@@ -1110,7 +1126,7 @@
# Mode literal keyword search
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=bookmark(anotherthing)&style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=bookmark(anotherthing)&style=raw'
200 Script output follows
@@ -1128,7 +1144,7 @@
bookmark: anotherthing
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=bookmark(abc)&style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=bookmark(abc)&style=raw'
200 Script output follows
@@ -1138,7 +1154,7 @@
# Mode literal keyword search
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=deadbeef:&style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=deadbeef:&style=raw'
200 Script output follows
@@ -1149,7 +1165,7 @@
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=user("test")&style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=user("test")&style=raw'
200 Script output follows
@@ -1190,7 +1206,7 @@
bookmark: anotherthing
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'log?rev=user("re:test")&style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'log?rev=user("re:test")&style=raw'
200 Script output follows
@@ -1203,11 +1219,11 @@
File-related
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/1/foo/?style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file/1/foo/?style=raw'
200 Script output follows
foo
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'annotate/1/foo/?style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'annotate/1/foo/?style=raw'
200 Script output follows
@@ -1216,7 +1232,7 @@
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/1/?style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file/1/?style=raw'
200 Script output follows
@@ -1232,7 +1248,7 @@
$ hg parents --template "{node|short}\n" -r 1 foo
2ef0ac749a14
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/1/foo'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file/1/foo'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -1280,7 +1296,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>view foo @ 1:a4f92ed23982</h3>
+ <h3>view foo @ 1:a4f92ed23982 </h3>
<form class="search" action="/log">
@@ -1326,7 +1342,7 @@
</body>
</html>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'filediff/0/foo/?style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'filediff/0/foo/?style=raw'
200 Script output follows
@@ -1340,7 +1356,7 @@
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'filediff/1/foo/?style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'filediff/1/foo/?style=raw'
200 Script output follows
@@ -1356,7 +1372,7 @@
$ hg parents --template "{node|short}\n" -r 2 foo
2ef0ac749a14
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/2/foo'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file/2/foo'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -1404,7 +1420,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>view foo @ 2:1d22e65f027e</h3>
+ <h3>view foo @ 2:1d22e65f027e <span class="branchname">stable</span> </h3>
<form class="search" action="/log">
@@ -1454,23 +1470,23 @@
Overviews
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'raw-tags'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'raw-tags'
200 Script output follows
tip cad8025a2e87f88c06259790adfa15acb4080123
1.0 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'raw-branches'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'raw-branches'
200 Script output follows
unstable cad8025a2e87f88c06259790adfa15acb4080123 open
stable 1d22e65f027e5a0609357e7d8e7508cd2ba5d2fe inactive
default a4f92ed23982be056b9852de5dfe873eaac7f0de inactive
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'raw-bookmarks'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'raw-bookmarks'
200 Script output follows
anotherthing 2ef0ac749a14e4f57a5a822464a0902c6f7f448f
something cad8025a2e87f88c06259790adfa15acb4080123
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'summary/?style=gitweb'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'summary/?style=gitweb'
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -1509,7 +1525,7 @@
<a href="/tags?style=gitweb">tags</a> |
<a href="/bookmarks?style=gitweb">bookmarks</a> |
<a href="/branches?style=gitweb">branches</a> |
- <a href="/file/cad8025a2e87?style=gitweb">files</a> |
+ <a href="/file?style=gitweb">files</a> |
<a href="/help?style=gitweb">help</a>
<br/>
</div>
@@ -1672,7 +1688,7 @@
</body>
</html>
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/?style=gitweb'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'graph/?style=gitweb'
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -1819,7 +1835,7 @@
raw graph
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/?style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'graph/?style=raw'
200 Script output follows
@@ -1869,28 +1885,28 @@
capabilities
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities'; echo
+ $ get-with-headers.py 127.0.0.1:$HGPORT '?cmd=capabilities'; echo
200 Script output follows
lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1*%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 (glob)
heads
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=heads'
+ $ get-with-headers.py 127.0.0.1:$HGPORT '?cmd=heads'
200 Script output follows
cad8025a2e87f88c06259790adfa15acb4080123
branches
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=branches&nodes=0000000000000000000000000000000000000000'
+ $ get-with-headers.py 127.0.0.1:$HGPORT '?cmd=branches&nodes=0000000000000000000000000000000000000000'
200 Script output follows
0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
changegroup
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=changegroup&roots=0000000000000000000000000000000000000000'
+ $ get-with-headers.py 127.0.0.1:$HGPORT '?cmd=changegroup&roots=0000000000000000000000000000000000000000'
200 Script output follows
x\x9c\xbd\x94MHTQ\x14\xc7'+\x9d\xc66\x81\x89P\xc1\xa3\x14\xcct\xba\xef\xbe\xfb\xde\xbb\xcfr0\xb3"\x02\x11[%\x98\xdcO\xa7\xd2\x19\x98y\xd2\x07h"\x96\xa0e\xda\xa6lUY-\xca\x08\xa2\x82\x16\x96\xd1\xa2\xf0#\xc8\x95\x1b\xdd$!m*"\xc8\x82\xea\xbe\x9c\x01\x85\xc9\x996\x1d\xf8\xc1\xe3~\x9d\xff9\xef\x7f\xaf\xcf\xe7\xbb\x19\xfc4\xec^\xcb\x9b\xfbz\xa6\xbe\xb3\x90_\xef/\x8d\x9e\xad\xbe\xe4\xcb0\xd2\xec\xad\x12X:\xc8\x12\x12\xd9:\x95\xba \x1cG\xb7$\xc5\xc44\x1c(\x1d\x03\x03\xdb\x84\x0cK#\xe0\x8a\xb8\x1b\x00\x1a\x08p\xb2SF\xa3\x01\x8f\x00%q\xa1Ny{k!8\xe5t>[{\xe2j\xddl\xc3\xcf\xee\xd0\xddW\x9ff3U\x9djobj\xbb\x87E\x88\x05l\x001\x12\x18\x13\xc6 \xb7(\xe3\x02a\x80\x81\xcel.u\x9b\x1b\x8c\x91\x80Z\x0c\x15\x15 (esc)
@@ -1901,14 +1917,14 @@
stream_out
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=stream_out'
+ $ get-with-headers.py 127.0.0.1:$HGPORT '?cmd=stream_out'
200 Script output follows
1
failing unbundle, requires POST request
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=unbundle'
+ $ get-with-headers.py 127.0.0.1:$HGPORT '?cmd=unbundle'
405 push requires POST request
0
@@ -1917,7 +1933,7 @@
Static files
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'static/style.css'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'static/style.css'
200 Script output follows
a { text-decoration:none; }
@@ -2029,7 +2045,7 @@
Stop and restart with HGENCODING=cp932 and preferuncompressed
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ HGENCODING=cp932 hg serve --config server.preferuncompressed=True -n test \
> -p $HGPORT -d --pid-file=hg.pid -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
@@ -2041,7 +2057,7 @@
Graph json escape of multibyte character
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'graph/' > out
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'graph/' > out
>>> for line in open("out"):
... if line.startswith("var data ="):
... print line,
@@ -2049,7 +2065,7 @@
capabilities
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT '?cmd=capabilities'; echo
+ $ get-with-headers.py 127.0.0.1:$HGPORT '?cmd=capabilities'; echo
200 Script output follows
lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream-preferred stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1*%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024 (glob)
@@ -2059,7 +2075,7 @@
ERRORS ENCOUNTERED
$ cat errors.log
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ cd ..
@@ -2098,23 +2114,23 @@
Test paging
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT \
+ $ get-with-headers.py 127.0.0.1:$HGPORT \
> 'graph/?style=raw' | grep changeset
changeset: aed2d9c1d0e7
changeset: b60a39a85a01
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT \
+ $ get-with-headers.py 127.0.0.1:$HGPORT \
> 'graph/?style=raw&revcount=3' | grep changeset
changeset: aed2d9c1d0e7
changeset: b60a39a85a01
changeset: ada793dcc118
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT \
+ $ get-with-headers.py 127.0.0.1:$HGPORT \
> 'graph/e06180cbfb0?style=raw&revcount=3' | grep changeset
changeset: e06180cbfb0c
changeset: b4e73ffab476
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT \
+ $ get-with-headers.py 127.0.0.1:$HGPORT \
> 'graph/b4e73ffab47?style=raw&revcount=3' | grep changeset
changeset: b4e73ffab476
--- a/tests/test-hgweb-descend-empties.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgweb-descend-empties.t Mon Jun 15 13:31:22 2015 -0500
@@ -3,7 +3,7 @@
Test chains of near empty directories, terminating 3 different ways:
- a1: file at level 4 (deepest)
- b1: two dirs at level 3
-- e1: file at level 2
+- d1: file at level 2
Set up the repo
@@ -11,25 +11,25 @@
$ cd test
$ mkdir -p a1/a2/a3/a4
$ mkdir -p b1/b2/b3/b4
- $ mkdir -p b1/b2/c3/c4
+ $ mkdir -p b1/b2/b3/c4
$ mkdir -p d1/d2/d3/d4
$ echo foo > a1/a2/a3/a4/foo
$ echo foo > b1/b2/b3/b4/foo
- $ echo foo > b1/b2/c3/c4/foo
+ $ echo foo > b1/b2/b3/c4/foo
$ echo foo > d1/d2/d3/d4/foo
$ echo foo > d1/d2/foo
$ hg ci -Ama
adding a1/a2/a3/a4/foo
adding b1/b2/b3/b4/foo
- adding b1/b2/c3/c4/foo
+ adding b1/b2/b3/c4/foo
adding d1/d2/d3/d4/foo
adding d1/d2/foo
$ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
-manifest with descending
+manifest with descending (paper)
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -40,7 +40,7 @@
<link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
<script type="text/javascript" src="/static/mercurial.js"></script>
- <title>test: 9087c84a0f5d /</title>
+ <title>test: c9f45f7a1659 /</title>
</head>
<body>
@@ -51,14 +51,14 @@
<img src="/static/hglogo.png" alt="mercurial" /></a>
</div>
<ul>
- <li><a href="/shortlog/9087c84a0f5d">log</a></li>
- <li><a href="/graph/9087c84a0f5d">graph</a></li>
+ <li><a href="/shortlog/c9f45f7a1659">log</a></li>
+ <li><a href="/graph/c9f45f7a1659">graph</a></li>
<li><a href="/tags">tags</a></li>
<li><a href="/bookmarks">bookmarks</a></li>
<li><a href="/branches">branches</a></li>
</ul>
<ul>
- <li><a href="/rev/9087c84a0f5d">changeset</a></li>
+ <li><a href="/rev/c9f45f7a1659">changeset</a></li>
<li class="active">browse</li>
</ul>
<ul>
@@ -71,7 +71,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>directory / @ 0:9087c84a0f5d <span class="tag">tip</span> </h3>
+ <h3>directory / @ 0:c9f45f7a1659 <span class="tag">tip</span> </h3>
<form class="search" action="/log">
@@ -90,17 +90,17 @@
</thead>
<tbody class="stripes2">
<tr class="fileline">
- <td class="name"><a href="/file/9087c84a0f5d/">[up]</a></td>
+ <td class="name"><a href="/file/c9f45f7a1659/">[up]</a></td>
<td class="size"></td>
<td class="permissions">drwxr-xr-x</td>
</tr>
<tr class="fileline">
<td class="name">
- <a href="/file/9087c84a0f5d/a1">
+ <a href="/file/c9f45f7a1659/a1">
<img src="/static/coal-folder.png" alt="dir."/> a1/
</a>
- <a href="/file/9087c84a0f5d/a1/a2/a3/a4">
+ <a href="/file/c9f45f7a1659/a1/a2/a3/a4">
a2/a3/a4
</a>
</td>
@@ -109,11 +109,11 @@
</tr>
<tr class="fileline">
<td class="name">
- <a href="/file/9087c84a0f5d/b1">
+ <a href="/file/c9f45f7a1659/b1">
<img src="/static/coal-folder.png" alt="dir."/> b1/
</a>
- <a href="/file/9087c84a0f5d/b1/b2">
- b2
+ <a href="/file/c9f45f7a1659/b1/b2/b3">
+ b2/b3
</a>
</td>
<td class="size"></td>
@@ -121,10 +121,126 @@
</tr>
<tr class="fileline">
<td class="name">
- <a href="/file/9087c84a0f5d/d1">
+ <a href="/file/c9f45f7a1659/d1">
<img src="/static/coal-folder.png" alt="dir."/> d1/
</a>
- <a href="/file/9087c84a0f5d/d1/d2">
+ <a href="/file/c9f45f7a1659/d1/d2">
+ d2
+ </a>
+ </td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+
+ </tbody>
+ </table>
+ </div>
+ </div>
+ <script type="text/javascript">process_dates()</script>
+
+
+ </body>
+ </html>
+
+
+manifest with descending (coal)
+
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file?style=coal'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style-coal.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: c9f45f7a1659 /</title>
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="menu">
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" alt="mercurial" /></a>
+ </div>
+ <ul>
+ <li><a href="/shortlog/c9f45f7a1659?style=coal">log</a></li>
+ <li><a href="/graph/c9f45f7a1659?style=coal">graph</a></li>
+ <li><a href="/tags?style=coal">tags</a></li>
+ <li><a href="/bookmarks?style=coal">bookmarks</a></li>
+ <li><a href="/branches?style=coal">branches</a></li>
+ </ul>
+ <ul>
+ <li><a href="/rev/c9f45f7a1659?style=coal">changeset</a></li>
+ <li class="active">browse</li>
+ </ul>
+ <ul>
+
+ </ul>
+ <ul>
+ <li><a href="/help?style=coal">help</a></li>
+ </ul>
+ </div>
+
+ <div class="main">
+ <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
+ <h3>directory / @ 0:c9f45f7a1659 <span class="tag">tip</span> </h3>
+
+ <form class="search" action="/log">
+ <input type="hidden" name="style" value="coal" />
+ <p><input name="rev" id="search1" type="text" size="30" /></p>
+ <div id="hint">Find changesets by keywords (author, files, the commit message), revision
+ number or hash, or <a href="/help/revsets">revset expression</a>.</div>
+ </form>
+
+ <table class="bigtable">
+ <thead>
+ <tr>
+ <th class="name">name</th>
+ <th class="size">size</th>
+ <th class="permissions">permissions</th>
+ </tr>
+ </thead>
+ <tbody class="stripes2">
+ <tr class="fileline">
+ <td class="name"><a href="/file/c9f45f7a1659/?style=coal">[up]</a></td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+
+ <tr class="fileline parity1">
+ <td class="name">
+ <a href="/file/c9f45f7a1659/a1?style=coal">
+ <img src="/static/coal-folder.png" alt="dir."/> a1/
+ </a>
+ <a href="/file/c9f45f7a1659/a1/a2/a3/a4?style=coal">
+ a2/a3/a4
+ </a>
+ </td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+ <tr class="fileline parity0">
+ <td class="name">
+ <a href="/file/c9f45f7a1659/b1?style=coal">
+ <img src="/static/coal-folder.png" alt="dir."/> b1/
+ </a>
+ <a href="/file/c9f45f7a1659/b1/b2/b3?style=coal">
+ b2/b3
+ </a>
+ </td>
+ <td class="size"></td>
+ <td class="permissions">drwxr-xr-x</td>
+ </tr>
+ <tr class="fileline parity1">
+ <td class="name">
+ <a href="/file/c9f45f7a1659/d1?style=coal">
+ <img src="/static/coal-folder.png" alt="dir."/> d1/
+ </a>
+ <a href="/file/c9f45f7a1659/d1/d2?style=coal">
d2
</a>
</td>
@@ -143,6 +259,307 @@
</html>
+manifest with descending (monoblue)
+
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file?style=monoblue'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow"/>
+ <link rel="stylesheet" href="/static/style-monoblue.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: files</title>
+ <link rel="alternate" type="application/atom+xml" href="/atom-log" title="Atom feed for test"/>
+ <link rel="alternate" type="application/rss+xml" href="/rss-log" title="RSS feed for test"/>
+ </head>
+
+ <body>
+ <div id="container">
+ <div class="page-header">
+ <h1 class="breadcrumb"><a href="/">Mercurial</a> / files</h1>
+
+ <form action="/log">
+ <input type="hidden" name="style" value="monoblue" />
+ <dl class="search">
+ <dt><label>Search: </label></dt>
+ <dd><input type="text" name="rev" /></dd>
+ </dl>
+ </form>
+
+ <ul class="page-nav">
+ <li><a href="/summary?style=monoblue">summary</a></li>
+ <li><a href="/shortlog?style=monoblue">shortlog</a></li>
+ <li><a href="/changelog?style=monoblue">changelog</a></li>
+ <li><a href="/graph/c9f45f7a1659?style=monoblue">graph</a></li>
+ <li><a href="/tags?style=monoblue">tags</a></li>
+ <li><a href="/bookmarks?style=monoblue">bookmarks</a></li>
+ <li><a href="/branches?style=monoblue">branches</a></li>
+ <li class="current">files</li>
+ <li><a href="/help?style=monoblue">help</a></li>
+ </ul>
+ </div>
+
+ <ul class="submenu">
+ <li><a href="/rev/c9f45f7a1659?style=monoblue">changeset</a></li>
+
+ </ul>
+
+ <h2 class="no-link no-border">files</h2>
+ <p class="files">/ <span class="logtags"><span class="branchtag" title="default">default</span> <span class="tagtag" title="tip">tip</span> </span></p>
+
+ <table>
+ <tr class="parity0">
+ <td>drwxr-xr-x</td>
+ <td></td>
+ <td></td>
+ <td><a href="/file/c9f45f7a1659/?style=monoblue">[up]</a></td>
+ <td class="link"> </td>
+ </tr>
+
+ <tr class="parity1">
+ <td>drwxr-xr-x</td>
+ <td></td>
+ <td></td>
+ <td>
+ <a href="/file/c9f45f7a1659/a1?style=monoblue">a1</a>
+ <a href="/file/c9f45f7a1659/a1/a2/a3/a4?style=monoblue">a2/a3/a4</a>
+ </td>
+ <td><a href="/file/c9f45f7a1659/a1?style=monoblue">files</a></td>
+ </tr>
+ <tr class="parity0">
+ <td>drwxr-xr-x</td>
+ <td></td>
+ <td></td>
+ <td>
+ <a href="/file/c9f45f7a1659/b1?style=monoblue">b1</a>
+ <a href="/file/c9f45f7a1659/b1/b2/b3?style=monoblue">b2/b3</a>
+ </td>
+ <td><a href="/file/c9f45f7a1659/b1?style=monoblue">files</a></td>
+ </tr>
+ <tr class="parity1">
+ <td>drwxr-xr-x</td>
+ <td></td>
+ <td></td>
+ <td>
+ <a href="/file/c9f45f7a1659/d1?style=monoblue">d1</a>
+ <a href="/file/c9f45f7a1659/d1/d2?style=monoblue">d2</a>
+ </td>
+ <td><a href="/file/c9f45f7a1659/d1?style=monoblue">files</a></td>
+ </tr>
+
+ </table>
+
+ <script type="text/javascript">process_dates()</script>
+ <div class="page-footer">
+ <p>Mercurial Repository: test</p>
+ <ul class="rss-logo">
+ <li><a href="/rss-log">RSS</a></li>
+ <li><a href="/atom-log">Atom</a></li>
+ </ul>
+
+ </div>
+
+ <div id="powered-by">
+ <p><a href="http://mercurial.selenic.com/" title="Mercurial"><img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a></p>
+ </div>
+
+ <div id="corner-top-left"></div>
+ <div id="corner-top-right"></div>
+ <div id="corner-bottom-left"></div>
+ <div id="corner-bottom-right"></div>
+
+ </div>
+
+ </body>
+ </html>
+
+
+manifest with descending (gitweb)
+
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file?style=gitweb'
+ 200 Script output follows
+
+ <?xml version="1.0" encoding="ascii"?>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png" />
+ <meta name="robots" content="index, nofollow"/>
+ <link rel="stylesheet" href="/static/style-gitweb.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: files</title>
+ <link rel="alternate" type="application/atom+xml"
+ href="/atom-log" title="Atom feed for test"/>
+ <link rel="alternate" type="application/rss+xml"
+ href="/rss-log" title="RSS feed for test"/>
+ </head>
+ <body>
+
+ <div class="page_header">
+ <a href="http://mercurial.selenic.com/" title="Mercurial" style="float: right;">Mercurial</a>
+ <a href="/">Mercurial</a> / files
+ </div>
+
+ <div class="page_nav">
+ <a href="/summary?style=gitweb">summary</a> |
+ <a href="/shortlog?style=gitweb">shortlog</a> |
+ <a href="/log?style=gitweb">changelog</a> |
+ <a href="/graph?style=gitweb">graph</a> |
+ <a href="/tags?style=gitweb">tags</a> |
+ <a href="/bookmarks?style=gitweb">bookmarks</a> |
+ <a href="/branches?style=gitweb">branches</a> |
+ files |
+ <a href="/rev/c9f45f7a1659?style=gitweb">changeset</a> |
+ <a href="/help?style=gitweb">help</a>
+ <br/>
+ </div>
+
+ <div class="title">/ <span class="logtags"><span class="branchtag" title="default">default</span> <span class="tagtag" title="tip">tip</span> </span></div>
+ <table cellspacing="0">
+ <tr class="parity0">
+ <td style="font-family:monospace">drwxr-xr-x</td>
+ <td style="font-family:monospace"></td>
+ <td style="font-family:monospace"></td>
+ <td><a href="/file/c9f45f7a1659/?style=gitweb">[up]</a></td>
+ <td class="link"> </td>
+ </tr>
+
+ <tr class="parity1">
+ <td style="font-family:monospace">drwxr-xr-x</td>
+ <td style="font-family:monospace"></td>
+ <td style="font-family:monospace"></td>
+ <td>
+ <a href="/file/c9f45f7a1659/a1?style=gitweb">a1</a>
+ <a href="/file/c9f45f7a1659/a1/a2/a3/a4?style=gitweb">a2/a3/a4</a>
+ </td>
+ <td class="link">
+ <a href="/file/c9f45f7a1659/a1?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="parity0">
+ <td style="font-family:monospace">drwxr-xr-x</td>
+ <td style="font-family:monospace"></td>
+ <td style="font-family:monospace"></td>
+ <td>
+ <a href="/file/c9f45f7a1659/b1?style=gitweb">b1</a>
+ <a href="/file/c9f45f7a1659/b1/b2/b3?style=gitweb">b2/b3</a>
+ </td>
+ <td class="link">
+ <a href="/file/c9f45f7a1659/b1?style=gitweb">files</a>
+ </td>
+ </tr>
+ <tr class="parity1">
+ <td style="font-family:monospace">drwxr-xr-x</td>
+ <td style="font-family:monospace"></td>
+ <td style="font-family:monospace"></td>
+ <td>
+ <a href="/file/c9f45f7a1659/d1?style=gitweb">d1</a>
+ <a href="/file/c9f45f7a1659/d1/d2?style=gitweb">d2</a>
+ </td>
+ <td class="link">
+ <a href="/file/c9f45f7a1659/d1?style=gitweb">files</a>
+ </td>
+ </tr>
+
+ </table>
+
+ <script type="text/javascript">process_dates()</script>
+ <div class="page_footer">
+ <div class="page_footer_text">test</div>
+ <div class="rss_logo">
+ <a href="/rss-log">RSS</a>
+ <a href="/atom-log">Atom</a>
+ </div>
+ <br />
+
+ </div>
+ </body>
+ </html>
+
+
+manifest with descending (spartan)
+
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file?style=spartan'
+ 200 Script output follows
+
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+ <html>
+ <head>
+ <link rel="icon" href="/static/hgicon.png" type="image/png">
+ <meta name="robots" content="index, nofollow" />
+ <link rel="stylesheet" href="/static/style.css" type="text/css" />
+ <script type="text/javascript" src="/static/mercurial.js"></script>
+
+ <title>test: files for changeset c9f45f7a1659</title>
+ </head>
+ <body>
+
+ <div class="buttons">
+ <a href="/log/0?style=spartan">changelog</a>
+ <a href="/shortlog/0?style=spartan">shortlog</a>
+ <a href="/graph?style=spartan">graph</a>
+ <a href="/tags?style=spartan">tags</a>
+ <a href="/branches?style=spartan">branches</a>
+ <a href="/rev/c9f45f7a1659?style=spartan">changeset</a>
+
+ <a href="/help?style=spartan">help</a>
+ </div>
+
+ <h2><a href="/">Mercurial</a> / files for changeset <a href="/rev/c9f45f7a1659">c9f45f7a1659</a>: /</h2>
+
+ <table cellpadding="0" cellspacing="0">
+ <tr class="parity0">
+ <td><tt>drwxr-xr-x</tt>
+ <td>
+ <td>
+ <td><a href="/file/c9f45f7a1659/?style=spartan">[up]</a>
+ </tr>
+
+ <tr class="parity1">
+ <td><tt>drwxr-xr-x</tt>
+ <td>
+ <td>
+ <td>
+ <a href="/file/c9f45f7a1659/a1?style=spartan">a1/</a>
+ <a href="/file/c9f45f7a1659/a1/a2/a3/a4?style=spartan">
+ a2/a3/a4
+ </a>
+ <tr class="parity0">
+ <td><tt>drwxr-xr-x</tt>
+ <td>
+ <td>
+ <td>
+ <a href="/file/c9f45f7a1659/b1?style=spartan">b1/</a>
+ <a href="/file/c9f45f7a1659/b1/b2/b3?style=spartan">
+ b2/b3
+ </a>
+ <tr class="parity1">
+ <td><tt>drwxr-xr-x</tt>
+ <td>
+ <td>
+ <td>
+ <a href="/file/c9f45f7a1659/d1?style=spartan">d1/</a>
+ <a href="/file/c9f45f7a1659/d1/d2?style=spartan">
+ d2
+ </a>
+
+ </table>
+ <script type="text/javascript">process_dates()</script>
+
+ <div class="logo">
+ <a href="http://mercurial.selenic.com/">
+ <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
+ </div>
+
+ </body>
+ </html>
+
+
$ cat errors.log
$ cd ..
--- a/tests/test-hgweb-diffs.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgweb-diffs.t Mon Jun 15 13:31:22 2015 -0500
@@ -36,7 +36,7 @@
revision
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
+ $ get-with-headers.py localhost:$HGPORT 'rev/0'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -168,7 +168,7 @@
raw revision
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
+ $ get-with-headers.py localhost:$HGPORT 'raw-rev/0'
200 Script output follows
@@ -201,7 +201,7 @@
$ hg parents --template "{node|short}\n" -r tip b
0cd96de13884
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/b'
+ $ get-with-headers.py localhost:$HGPORT 'diff/tip/b'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -249,7 +249,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>diff b @ 1:559edbd9ed20</h3>
+ <h3>diff b @ 1:559edbd9ed20 <span class="tag">tip</span> </h3>
<form class="search" action="/log">
<p></p>
@@ -302,13 +302,13 @@
set up hgweb with git diffs
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ hg serve --config 'diff.git=1' -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
revision
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
+ $ get-with-headers.py localhost:$HGPORT 'rev/0'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -442,7 +442,7 @@
revision
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
+ $ get-with-headers.py localhost:$HGPORT 'raw-rev/0'
200 Script output follows
@@ -477,7 +477,7 @@
$ hg parents --template "{node|short}\n" -r tip a
0cd96de13884
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/a'
+ $ get-with-headers.py localhost:$HGPORT 'diff/tip/a'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -525,7 +525,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>diff a @ 1:559edbd9ed20</h3>
+ <h3>diff a @ 1:559edbd9ed20 <span class="tag">tip</span> </h3>
<form class="search" action="/log">
<p></p>
@@ -580,7 +580,7 @@
$ hg log --template "{rev}:{node|short}\n" -r 0
0:0cd96de13884
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/0/a'
+ $ get-with-headers.py localhost:$HGPORT 'comparison/0/a'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -628,7 +628,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>comparison a @ 0:0cd96de13884</h3>
+ <h3>comparison a @ 0:0cd96de13884 </h3>
<form class="search" action="/log">
<p></p>
@@ -707,7 +707,7 @@
$ hg log --template "{rev}:{node|short}\n" -r tip
2:d73db4d812ff
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
+ $ get-with-headers.py localhost:$HGPORT 'comparison/tip/a'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -755,7 +755,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>comparison a @ 2:d73db4d812ff</h3>
+ <h3>comparison a @ 2:d73db4d812ff <span class="tag">tip</span> </h3>
<form class="search" action="/log">
<p></p>
@@ -836,7 +836,7 @@
$ hg log --template "{rev}:{node|short}\n" -r tip
3:20e80271eb7a
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
+ $ get-with-headers.py localhost:$HGPORT 'comparison/tip/a'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -884,7 +884,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>comparison a @ 3:20e80271eb7a</h3>
+ <h3>comparison a @ 3:20e80271eb7a <span class="tag">tip</span> </h3>
<form class="search" action="/log">
<p></p>
@@ -971,7 +971,7 @@
$ hg parents --template "{rev}:{node|short}\n" -r tip e
4:402bea3b0976
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/e'
+ $ get-with-headers.py localhost:$HGPORT 'comparison/tip/e'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -1019,7 +1019,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>comparison e @ 5:41d9fc4a6ae1</h3>
+ <h3>comparison e @ 5:41d9fc4a6ae1 <span class="tag">tip</span> </h3>
<form class="search" action="/log">
<p></p>
@@ -1094,7 +1094,7 @@
raw revision with diff block numbers
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ cat <<EOF > .hg/hgrc
> [web]
> templates = rawdiff
@@ -1114,7 +1114,7 @@
> EOF
$ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
+ $ get-with-headers.py localhost:$HGPORT 'raw-rev/0'
200 Script output follows
Block: 1
@@ -1131,7 +1131,7 @@
@@ -0,0 +1,1 @@
+b
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ rm .hg/hgrc rawdiff/map
$ rmdir rawdiff
$ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
--- a/tests/test-hgweb-empty.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgweb-empty.t Mon Jun 15 13:31:22 2015 -0500
@@ -6,7 +6,7 @@
$ cd test
$ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'shortlog')
+ $ (get-with-headers.py localhost:$HGPORT 'shortlog')
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -117,7 +117,7 @@
$ echo babar
babar
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log')
+ $ (get-with-headers.py localhost:$HGPORT 'log')
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -226,7 +226,7 @@
</body>
</html>
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'graph')
+ $ (get-with-headers.py localhost:$HGPORT 'graph')
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -380,7 +380,7 @@
</body>
</html>
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file')
+ $ (get-with-headers.py localhost:$HGPORT 'file')
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
--- a/tests/test-hgweb-filelog.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgweb-filelog.t Mon Jun 15 13:31:22 2015 -0500
@@ -8,8 +8,13 @@
$ echo a > a
$ hg ci -Am "first a"
adding a
+ $ hg tag -r 1 a-tag
+ $ hg bookmark -r 1 a-bookmark
$ hg rm a
$ hg ci -m "del a"
+ $ hg branch a-branch
+ marked working directory as branch a-branch
+ (branches are permanent and global, did you want a bookmark?)
$ echo b > a
$ hg ci -Am "second a"
adding a
@@ -20,69 +25,86 @@
$ echo c >> c
$ hg ci -m "change c"
$ hg log -p
- changeset: 6:b7682196df1c
+ changeset: 7:46c1a66bd8fc
+ branch: a-branch
tag: tip
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: change c
- diff -r 1a6696706df2 -r b7682196df1c c
+ diff -r c9637d3cc8ef -r 46c1a66bd8fc c
--- a/c Thu Jan 01 00:00:00 1970 +0000
+++ b/c Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +1,2 @@
b
+c
- changeset: 5:1a6696706df2
+ changeset: 6:c9637d3cc8ef
+ branch: a-branch
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: mv b
- diff -r 52e848cdcd88 -r 1a6696706df2 b
+ diff -r 958bd88be4eb -r c9637d3cc8ef b
--- a/b Thu Jan 01 00:00:00 1970 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-b
- diff -r 52e848cdcd88 -r 1a6696706df2 c
+ diff -r 958bd88be4eb -r c9637d3cc8ef c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/c Thu Jan 01 00:00:00 1970 +0000
@@ -0,0 +1,1 @@
+b
- changeset: 4:52e848cdcd88
+ changeset: 5:958bd88be4eb
+ branch: a-branch
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: del2 a
- diff -r 01de2d66a28d -r 52e848cdcd88 a
+ diff -r 3f41bc784e7e -r 958bd88be4eb a
--- a/a Thu Jan 01 00:00:00 1970 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-b
- changeset: 3:01de2d66a28d
+ changeset: 4:3f41bc784e7e
+ branch: a-branch
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: second a
- diff -r be3ebcc91739 -r 01de2d66a28d a
+ diff -r 292258f86fdf -r 3f41bc784e7e a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/a Thu Jan 01 00:00:00 1970 +0000
@@ -0,0 +1,1 @@
+b
- changeset: 2:be3ebcc91739
+ changeset: 3:292258f86fdf
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: del a
- diff -r 5ed941583260 -r be3ebcc91739 a
+ diff -r 94c9dd5ca9b4 -r 292258f86fdf a
--- a/a Thu Jan 01 00:00:00 1970 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-a
+ changeset: 2:94c9dd5ca9b4
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: Added tag a-tag for changeset 5ed941583260
+
+ diff -r 5ed941583260 -r 94c9dd5ca9b4 .hgtags
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/.hgtags Thu Jan 01 00:00:00 1970 +0000
+ @@ -0,0 +1,1 @@
+ +5ed941583260248620985524192fdc382ef57c36 a-tag
+
changeset: 1:5ed941583260
+ bookmark: a-bookmark
+ tag: a-tag
user: test
date: Thu Jan 01 00:00:00 1970 +0000
summary: first a
@@ -109,7 +131,7 @@
tip - two revisions
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/tip/a')
+ $ (get-with-headers.py localhost:$HGPORT 'log/tip/a')
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -135,29 +157,29 @@
<img src="/static/hglogo.png" alt="mercurial" /></a>
</div>
<ul>
- <li><a href="/shortlog/01de2d66a28d">log</a></li>
- <li><a href="/graph/01de2d66a28d">graph</a></li>
+ <li><a href="/shortlog/3f41bc784e7e">log</a></li>
+ <li><a href="/graph/3f41bc784e7e">graph</a></li>
<li><a href="/tags">tags</a></li>
<li><a href="/bookmarks">bookmarks</a></li>
<li><a href="/branches">branches</a></li>
</ul>
<ul>
- <li><a href="/rev/01de2d66a28d">changeset</a></li>
- <li><a href="/file/01de2d66a28d">browse</a></li>
+ <li><a href="/rev/3f41bc784e7e">changeset</a></li>
+ <li><a href="/file/3f41bc784e7e">browse</a></li>
</ul>
<ul>
- <li><a href="/file/01de2d66a28d/a">file</a></li>
- <li><a href="/diff/01de2d66a28d/a">diff</a></li>
- <li><a href="/comparison/01de2d66a28d/a">comparison</a></li>
- <li><a href="/annotate/01de2d66a28d/a">annotate</a></li>
+ <li><a href="/file/3f41bc784e7e/a">file</a></li>
+ <li><a href="/diff/3f41bc784e7e/a">diff</a></li>
+ <li><a href="/comparison/3f41bc784e7e/a">comparison</a></li>
+ <li><a href="/annotate/3f41bc784e7e/a">annotate</a></li>
<li class="active">file log</li>
- <li><a href="/raw-file/01de2d66a28d/a">raw</a></li>
+ <li><a href="/raw-file/3f41bc784e7e/a">raw</a></li>
</ul>
<ul>
<li><a href="/help">help</a></li>
</ul>
<div class="atom-logo">
- <a href="/atom-log/01de2d66a28d/a" title="subscribe to atom feed">
+ <a href="/atom-log/3f41bc784e7e/a" title="subscribe to atom feed">
<img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
</a>
</div>
@@ -175,8 +197,8 @@
</form>
<div class="navigate">
- <a href="/log/01de2d66a28d/a?revcount=30">less</a>
- <a href="/log/01de2d66a28d/a?revcount=120">more</a>
+ <a href="/log/3f41bc784e7e/a?revcount=30">less</a>
+ <a href="/log/3f41bc784e7e/a?revcount=120">more</a>
| <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
<table class="bigtable">
@@ -191,20 +213,26 @@
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/01de2d66a28d">second a</a></td>
+ <td class="description">
+ <a href="/rev/3f41bc784e7e">second a</a>
+ <span class="branchname">a-branch</span>
+ </td>
</tr>
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/5ed941583260">first a</a></td>
+ <td class="description">
+ <a href="/rev/5ed941583260">first a</a>
+ <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
+ </td>
</tr>
</tbody>
</table>
<div class="navigate">
- <a href="/log/01de2d66a28d/a?revcount=30">less</a>
- <a href="/log/01de2d66a28d/a?revcount=120">more</a>
+ <a href="/log/3f41bc784e7e/a?revcount=30">less</a>
+ <a href="/log/3f41bc784e7e/a?revcount=120">more</a>
| <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
</div>
@@ -220,7 +248,7 @@
second version - two revisions
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/3/a')
+ $ (get-with-headers.py localhost:$HGPORT 'log/4/a')
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -246,29 +274,29 @@
<img src="/static/hglogo.png" alt="mercurial" /></a>
</div>
<ul>
- <li><a href="/shortlog/01de2d66a28d">log</a></li>
- <li><a href="/graph/01de2d66a28d">graph</a></li>
+ <li><a href="/shortlog/3f41bc784e7e">log</a></li>
+ <li><a href="/graph/3f41bc784e7e">graph</a></li>
<li><a href="/tags">tags</a></li>
<li><a href="/bookmarks">bookmarks</a></li>
<li><a href="/branches">branches</a></li>
</ul>
<ul>
- <li><a href="/rev/01de2d66a28d">changeset</a></li>
- <li><a href="/file/01de2d66a28d">browse</a></li>
+ <li><a href="/rev/3f41bc784e7e">changeset</a></li>
+ <li><a href="/file/3f41bc784e7e">browse</a></li>
</ul>
<ul>
- <li><a href="/file/01de2d66a28d/a">file</a></li>
- <li><a href="/diff/01de2d66a28d/a">diff</a></li>
- <li><a href="/comparison/01de2d66a28d/a">comparison</a></li>
- <li><a href="/annotate/01de2d66a28d/a">annotate</a></li>
+ <li><a href="/file/3f41bc784e7e/a">file</a></li>
+ <li><a href="/diff/3f41bc784e7e/a">diff</a></li>
+ <li><a href="/comparison/3f41bc784e7e/a">comparison</a></li>
+ <li><a href="/annotate/3f41bc784e7e/a">annotate</a></li>
<li class="active">file log</li>
- <li><a href="/raw-file/01de2d66a28d/a">raw</a></li>
+ <li><a href="/raw-file/3f41bc784e7e/a">raw</a></li>
</ul>
<ul>
<li><a href="/help">help</a></li>
</ul>
<div class="atom-logo">
- <a href="/atom-log/01de2d66a28d/a" title="subscribe to atom feed">
+ <a href="/atom-log/3f41bc784e7e/a" title="subscribe to atom feed">
<img class="atom-logo" src="/static/feed-icon-14x14.png" alt="atom feed" />
</a>
</div>
@@ -286,8 +314,8 @@
</form>
<div class="navigate">
- <a href="/log/01de2d66a28d/a?revcount=30">less</a>
- <a href="/log/01de2d66a28d/a?revcount=120">more</a>
+ <a href="/log/3f41bc784e7e/a?revcount=30">less</a>
+ <a href="/log/3f41bc784e7e/a?revcount=120">more</a>
| <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a> </div>
<table class="bigtable">
@@ -302,20 +330,26 @@
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/01de2d66a28d">second a</a></td>
+ <td class="description">
+ <a href="/rev/3f41bc784e7e">second a</a>
+ <span class="branchname">a-branch</span>
+ </td>
</tr>
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/5ed941583260">first a</a></td>
+ <td class="description">
+ <a href="/rev/5ed941583260">first a</a>
+ <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
+ </td>
</tr>
</tbody>
</table>
<div class="navigate">
- <a href="/log/01de2d66a28d/a?revcount=30">less</a>
- <a href="/log/01de2d66a28d/a?revcount=120">more</a>
+ <a href="/log/3f41bc784e7e/a?revcount=30">less</a>
+ <a href="/log/3f41bc784e7e/a?revcount=120">more</a>
| <a href="/log/5ed941583260/a">(0)</a> <a href="/log/tip/a">tip</a>
</div>
@@ -331,7 +365,7 @@
first deleted - one revision
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/2/a')
+ $ (get-with-headers.py localhost:$HGPORT 'log/3/a')
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -413,7 +447,10 @@
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/5ed941583260">first a</a></td>
+ <td class="description">
+ <a href="/rev/5ed941583260">first a</a>
+ <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
+ </td>
</tr>
</tbody>
@@ -437,7 +474,7 @@
first version - one revision
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/1/a')
+ $ (get-with-headers.py localhost:$HGPORT 'log/1/a')
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -519,7 +556,10 @@
<tr>
<td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>
<td class="author">test</td>
- <td class="description"><a href="/rev/5ed941583260">first a</a></td>
+ <td class="description">
+ <a href="/rev/5ed941583260">first a</a>
+ <span class="tag">a-tag</span> <span class="tag">a-bookmark</span>
+ </td>
</tr>
</tbody>
@@ -543,7 +583,7 @@
before addition - error
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/0/a')
+ $ (get-with-headers.py localhost:$HGPORT 'log/0/a')
404 Not Found
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -609,7 +649,7 @@
should show base link, use spartan because it shows it
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log/tip/c?style=spartan')
+ $ (get-with-headers.py localhost:$HGPORT 'log/tip/c?style=spartan')
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
@@ -634,8 +674,8 @@
<a href="/graph?style=spartan">graph</a>
<a href="/tags?style=spartan">tags</a>
<a href="/branches?style=spartan">branches</a>
- <a href="/file/b7682196df1c/c?style=spartan">file</a>
- <a href="/annotate/b7682196df1c/c?style=spartan">annotate</a>
+ <a href="/file/46c1a66bd8fc/c?style=spartan">file</a>
+ <a href="/annotate/46c1a66bd8fc/c?style=spartan">annotate</a>
<a href="/help?style=spartan">help</a>
<a type="application/rss+xml" href="/rss-log/tip/c">rss</a>
<a type="application/atom+xml" href="/atom-log/tip/c" title="Atom feed for test:c">atom</a>
@@ -643,19 +683,19 @@
<h2><a href="/">Mercurial</a> / c revision history</h2>
- <p>navigate: <small class="navigate"><a href="/log/1a6696706df2/c?style=spartan">(0)</a> <a href="/log/tip/c?style=spartan">tip</a> </small></p>
+ <p>navigate: <small class="navigate"><a href="/log/c9637d3cc8ef/c?style=spartan">(0)</a> <a href="/log/tip/c?style=spartan">tip</a> </small></p>
<table class="logEntry parity0">
<tr>
<th class="label"><span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span>:</th>
- <th class="firstline"><a href="/rev/b7682196df1c?style=spartan">change c</a></th>
+ <th class="firstline"><a href="/rev/46c1a66bd8fc?style=spartan">change c</a></th>
</tr>
<tr>
<th class="revision">revision 1:</th>
<td class="node">
- <a href="/file/b7682196df1c/c?style=spartan">b7682196df1c</a>
- <a href="/diff/b7682196df1c/c?style=spartan">(diff)</a>
- <a href="/annotate/b7682196df1c/c?style=spartan">(annotate)</a>
+ <a href="/file/46c1a66bd8fc/c?style=spartan">46c1a66bd8fc</a>
+ <a href="/diff/46c1a66bd8fc/c?style=spartan">(diff)</a>
+ <a href="/annotate/46c1a66bd8fc/c?style=spartan">(annotate)</a>
</td>
</tr>
@@ -673,14 +713,14 @@
<table class="logEntry parity1">
<tr>
<th class="label"><span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span>:</th>
- <th class="firstline"><a href="/rev/1a6696706df2?style=spartan">mv b</a></th>
+ <th class="firstline"><a href="/rev/c9637d3cc8ef?style=spartan">mv b</a></th>
</tr>
<tr>
<th class="revision">revision 0:</th>
<td class="node">
- <a href="/file/1a6696706df2/c?style=spartan">1a6696706df2</a>
- <a href="/diff/1a6696706df2/c?style=spartan">(diff)</a>
- <a href="/annotate/1a6696706df2/c?style=spartan">(annotate)</a>
+ <a href="/file/c9637d3cc8ef/c?style=spartan">c9637d3cc8ef</a>
+ <a href="/diff/c9637d3cc8ef/c?style=spartan">(diff)</a>
+ <a href="/annotate/c9637d3cc8ef/c?style=spartan">(annotate)</a>
</td>
</tr>
@@ -718,7 +758,7 @@
rss log
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rss-log/tip/a')
+ $ (get-with-headers.py localhost:$HGPORT 'rss-log/tip/a')
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -731,7 +771,7 @@
<description>a revision history</description>
<item>
<title>second a</title>
- <link>http://*:$HGPORT/log01de2d66a28d/a</link> (glob)
+ <link>http://*:$HGPORT/log3f41bc784e7e/a</link> (glob)
<description><![CDATA[second a]]></description>
<author>test</author>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate>
@@ -749,7 +789,7 @@
atom log
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'atom-log/tip/a')
+ $ (get-with-headers.py localhost:$HGPORT 'atom-log/tip/a')
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -760,9 +800,9 @@
<updated>1970-01-01T00:00:00+00:00</updated>
<entry>
- <title>second a</title>
- <id>http://*:$HGPORT/#changeset-01de2d66a28df5549090991dccda788726948517</id> (glob)
- <link href="http://*:$HGPORT/rev/01de2d66a28d"/> (glob)
+ <title>[a-branch] second a</title>
+ <id>http://*:$HGPORT/#changeset-3f41bc784e7e73035c6d47112c6cc7efb673adf8</id> (glob)
+ <link href="http://*:$HGPORT/rev/3f41bc784e7e"/> (glob)
<author>
<name>test</name>
<email>test</email>
@@ -773,11 +813,11 @@
<table xmlns="http://www.w3.org/1999/xhtml">
<tr>
<th style="text-align:left;">changeset</th>
- <td>01de2d66a28d</td>
+ <td>3f41bc784e7e</td>
</tr>
<tr>
<th style="text-align:left;">branch</th>
- <td></td>
+ <td>a-branch</td>
</tr>
<tr>
<th style="text-align:left;">bookmark</th>
@@ -824,11 +864,11 @@
</tr>
<tr>
<th style="text-align:left;">bookmark</th>
- <td></td>
+ <td>a-bookmark</td>
</tr>
<tr>
<th style="text-align:left;">tag</th>
- <td></td>
+ <td>a-tag</td>
</tr>
<tr>
<th style="text-align:left;">user</th>
--- a/tests/test-hgweb-json.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgweb-json.t Mon Jun 15 13:31:22 2015 -0500
@@ -2,7 +2,7 @@
#require serve
$ request() {
- > $TESTDIR/get-with-headers.py --json localhost:$HGPORT "$1"
+ > get-with-headers.py --json localhost:$HGPORT "$1"
> }
$ hg init test
--- a/tests/test-hgweb-raw.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgweb-raw.t Mon Jun 15 13:31:22 2015 -0500
@@ -17,9 +17,9 @@
$ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid
$ cat hg.pid >> $DAEMON_PIDS
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '?f=bf0ff59095c9;file=sub/some%20text%25.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
+ $ (get-with-headers.py localhost:$HGPORT '?f=bf0ff59095c9;file=sub/some%20text%25.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
- $ "$TESTDIR/killdaemons.py" hg.pid
+ $ killdaemons.py hg.pid
$ cat getoutput.txt
200 Script output follows
@@ -39,8 +39,8 @@
> --config web.guessmime=True
$ cat hg.pid >> $DAEMON_PIDS
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '?f=bf0ff59095c9;file=sub/some%20text%25.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
- $ "$TESTDIR/killdaemons.py" hg.pid
+ $ (get-with-headers.py localhost:$HGPORT '?f=bf0ff59095c9;file=sub/some%20text%25.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
+ $ killdaemons.py hg.pid
$ cat getoutput.txt
200 Script output follows
--- a/tests/test-hgweb-removed.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgweb-removed.t Mon Jun 15 13:31:22 2015 -0500
@@ -17,7 +17,7 @@
revision
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip'
+ $ get-with-headers.py localhost:$HGPORT 'rev/tip'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -137,7 +137,7 @@
diff removed file
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/a'
+ $ get-with-headers.py localhost:$HGPORT 'diff/tip/a'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -185,7 +185,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>diff a @ 1:c78f6c5cbea9</h3>
+ <h3>diff a @ 1:c78f6c5cbea9 <span class="tag">tip</span> </h3>
<form class="search" action="/log">
<p></p>
--- a/tests/test-hgweb.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgweb.t Mon Jun 15 13:31:22 2015 -0500
@@ -15,7 +15,7 @@
manifest
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/?style=raw')
+ $ (get-with-headers.py localhost:$HGPORT 'file/tip/?style=raw')
200 Script output follows
@@ -23,7 +23,7 @@
-rw-r--r-- 4 foo
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/da?style=raw')
+ $ (get-with-headers.py localhost:$HGPORT 'file/tip/da?style=raw')
200 Script output follows
@@ -33,14 +33,14 @@
plain file
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/foo?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'file/tip/foo?style=raw'
200 Script output follows
foo
should give a 404 - static file that does not exist
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'static/bogus'
+ $ get-with-headers.py localhost:$HGPORT 'static/bogus'
404 Not Found
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -106,7 +106,7 @@
should give a 404 - bad revision
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/spam/foo?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'file/spam/foo?style=raw'
404 Not Found
@@ -115,40 +115,40 @@
should give a 400 - bad command
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/foo?cmd=spam&style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'file/tip/foo?cmd=spam&style=raw'
400* (glob)
error: no such method: spam
[1]
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT '?cmd=spam'
+ $ get-with-headers.py --headeronly localhost:$HGPORT '?cmd=spam'
400 no such method: spam
[1]
should give a 400 - bad command as a part of url path (issue4071)
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'spam'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'spam'
400 no such method: spam
[1]
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'raw-spam'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'raw-spam'
400 no such method: spam
[1]
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'spam/tip/foo'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'spam/tip/foo'
400 no such method: spam
[1]
should give a 404 - file does not exist
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/bork?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'file/tip/bork?style=raw'
404 Not Found
error: bork@2ef0ac749a14: not found in manifest
[1]
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/bork'
+ $ get-with-headers.py localhost:$HGPORT 'file/tip/bork'
404 Not Found
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -211,7 +211,7 @@
</html>
[1]
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/bork?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'diff/tip/bork?style=raw'
404 Not Found
@@ -220,7 +220,7 @@
try bad style
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/?style=foobar')
+ $ (get-with-headers.py localhost:$HGPORT 'file/tip/?style=foobar')
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -321,7 +321,7 @@
stop and restart
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log
$ cat hg.pid >> $DAEMON_PIDS
@@ -332,7 +332,7 @@
static file
- $ "$TESTDIR/get-with-headers.py" --twice localhost:$HGPORT 'static/style-gitweb.css' - date etag server
+ $ get-with-headers.py --twice localhost:$HGPORT 'static/style-gitweb.css' - date etag server
200 Script output follows
content-length: 5372
content-type: text/css
@@ -540,7 +540,7 @@
$ echo bar >> foo
$ hg ci -msecret --secret
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'log?style=raw'
200 Script output follows
@@ -557,7 +557,7 @@
$ hg phase --draft tip
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'log?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'log?style=raw'
200 Script output follows
@@ -594,27 +594,27 @@
> mimetype = 'text/plain'
> EOF
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log \
> --config web.style=fallback --config web.templates=x/templates
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT "?style=`pwd`/x"
+ $ get-with-headers.py localhost:$HGPORT "?style=`pwd`/x"
200 Script output follows
fall back to default
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=..'
+ $ get-with-headers.py localhost:$HGPORT '?style=..'
200 Script output follows
fall back to default
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=./..'
+ $ get-with-headers.py localhost:$HGPORT '?style=./..'
200 Script output follows
fall back to default
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=.../.../'
+ $ get-with-headers.py localhost:$HGPORT '?style=.../.../'
200 Script output follows
fall back to default
@@ -625,18 +625,18 @@
Uncaught exceptions result in a logged error and canned HTTP response
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ hg --config extensions.hgweberror=$TESTDIR/hgweberror.py serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
- $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'raiseerror' transfer-encoding content-type
+ $ get-with-headers.py localhost:$HGPORT 'raiseerror' transfer-encoding content-type
500 Internal Server Error
transfer-encoding: chunked
Internal Server Error (no-eol)
[1]
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ head -1 errors.log
.* Exception happened during processing request '/raiseerror': (re)
@@ -644,7 +644,7 @@
$ hg --config extensions.hgweberror=$TESTDIR/hgweberror.py serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
- $ $TESTDIR/get-with-headers.py localhost:$HGPORT 'raiseerror?partialresponse=1' transfer-encoding content-type
+ $ get-with-headers.py localhost:$HGPORT 'raiseerror?partialresponse=1' transfer-encoding content-type
200 Script output follows
transfer-encoding: chunked
content-type: text/plain
@@ -652,5 +652,5 @@
partial content
Internal Server Error (no-eol)
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ cd ..
--- a/tests/test-hgwebdir.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgwebdir.t Mon Jun 15 13:31:22 2015 -0500
@@ -84,7 +84,7 @@
should give a 404 - file does not exist
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/file/tip/bork?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'a/file/tip/bork?style=raw'
404 Not Found
@@ -93,25 +93,25 @@
should succeed
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=raw'
+ $ get-with-headers.py localhost:$HGPORT '?style=raw'
200 Script output follows
/a/
/b/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/file/tip/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'a/file/tip/a?style=raw'
200 Script output follows
a
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'b/file/tip/b?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'b/file/tip/b?style=raw'
200 Script output follows
b
should give a 404 - repo is not published
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'c/file/tip/c?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'c/file/tip/c?style=raw'
404 Not Found
@@ -120,14 +120,14 @@
atom-log without basedir
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/atom-log' | grep '<link'
+ $ get-with-headers.py localhost:$HGPORT 'a/atom-log' | grep '<link'
<link rel="self" href="http://*:$HGPORT/a/atom-log"/> (glob)
<link rel="alternate" href="http://*:$HGPORT/a/"/> (glob)
<link href="http://*:$HGPORT/a/rev/8580ff50825a"/> (glob)
rss-log without basedir
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'a/rss-log' | grep '<guid'
+ $ get-with-headers.py localhost:$HGPORT 'a/rss-log' | grep '<guid'
<guid isPermaLink="true">http://*:$HGPORT/a/rev/8580ff50825a</guid> (glob)
$ cat > paths.conf <<EOF
> [paths]
@@ -145,7 +145,7 @@
should succeed, slashy names
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 '?style=raw'
200 Script output follows
@@ -184,7 +184,7 @@
/astar/
/astar/.hg/patches/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=paper'
+ $ get-with-headers.py localhost:$HGPORT1 '?style=paper'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -672,19 +672,19 @@
</body>
</html>
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 't?style=raw'
200 Script output follows
/t/a/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 't/?style=raw'
200 Script output follows
/t/a/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=paper'
+ $ get-with-headers.py localhost:$HGPORT1 't/?style=paper'
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -743,7 +743,7 @@
</body>
</html>
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a?style=atom'
+ $ get-with-headers.py localhost:$HGPORT1 't/a?style=atom'
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -800,7 +800,7 @@
</entry>
</feed>
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a/?style=atom'
+ $ get-with-headers.py localhost:$HGPORT1 't/a/?style=atom'
200 Script output follows
<?xml version="1.0" encoding="ascii"?>
@@ -857,14 +857,14 @@
</entry>
</feed>
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/a/file/tip/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 't/a/file/tip/a?style=raw'
200 Script output follows
a
Test [paths] '*' extension
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'coll/?style=raw'
200 Script output follows
@@ -875,14 +875,14 @@
/coll/notrepo/e/
/coll/notrepo/f/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
200 Script output follows
a
Test [paths] '**' extension
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/?style=raw'
200 Script output follows
@@ -896,14 +896,14 @@
/rcoll/notrepo/f/
/rcoll/notrepo/f/f2/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
200 Script output follows
d
Test collapse = True
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ cat >> paths.conf <<EOF
> [web]
> collapse=true
@@ -912,7 +912,7 @@
$ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
> -A access-paths.log -E error-paths-3.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'coll/?style=raw'
200 Script output follows
@@ -922,11 +922,11 @@
/coll/c/
/coll/notrepo/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
200 Script output follows
a
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/?style=raw'
200 Script output follows
@@ -937,7 +937,7 @@
/rcoll/c/
/rcoll/notrepo/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
200 Script output follows
d
@@ -952,7 +952,7 @@
> hidden = True
> EOF
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
200 Script output follows
@@ -963,7 +963,7 @@
Subrepo parent not hidden
$ mv $root/notrepo/f/.hg/hgrc.bak $root/notrepo/f/.hg/hgrc
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
200 Script output follows
@@ -975,28 +975,28 @@
Test repositories inside intermediate directories
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/e/file/tip/e?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/notrepo/e/file/tip/e?style=raw'
200 Script output follows
e
Test subrepositories inside intermediate directories
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/f/f2/file/tip/f2?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/notrepo/f/f2/file/tip/f2?style=raw'
200 Script output follows
f2
Test descend = False
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ cat >> paths.conf <<EOF
> descend=false
> EOF
$ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
> -A access-paths.log -E error-paths-4.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'coll/?style=raw'
200 Script output follows
@@ -1004,11 +1004,11 @@
/coll/b/
/coll/c/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'coll/a/file/tip/a?style=raw'
200 Script output follows
a
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/?style=raw'
200 Script output follows
@@ -1016,14 +1016,14 @@
/rcoll/b/
/rcoll/c/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/b/d/file/tip/d?style=raw'
200 Script output follows
d
Test intermediate directories
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/notrepo/?style=raw'
200 Script output follows
@@ -1033,14 +1033,14 @@
Test repositories inside intermediate directories
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/e/file/tip/e?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/notrepo/e/file/tip/e?style=raw'
200 Script output follows
e
Test subrepositories inside intermediate directories
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 'rcoll/notrepo/f/f2/file/tip/f2?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 'rcoll/notrepo/f/f2/file/tip/f2?style=raw'
200 Script output follows
f2
@@ -1050,7 +1050,7 @@
$ hg id http://localhost:$HGPORT1/astar
8580ff50825a
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ cat > paths.conf <<EOF
> [paths]
> t/a = $root/a
@@ -1060,7 +1060,7 @@
$ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
> -A access-paths.log -E error-paths-5.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 '?style=raw'
200 Script output follows
@@ -1068,7 +1068,7 @@
/t/b/
/c/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 't/?style=raw'
200 Script output follows
@@ -1078,7 +1078,7 @@
Test collapse = True
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ cat >> paths.conf <<EOF
> [web]
> collapse=true
@@ -1086,14 +1086,14 @@
$ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
> -A access-paths.log -E error-paths-6.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 '?style=raw'
200 Script output follows
/t/
/c/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 't/?style=raw'
200 Script output follows
@@ -1103,27 +1103,27 @@
test descend = False
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ cat >> paths.conf <<EOF
> descend=false
> EOF
$ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
> -A access-paths.log -E error-paths-7.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 '?style=raw'
200 Script output follows
/c/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 't/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 't/?style=raw'
200 Script output follows
/t/a/
/t/b/
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ cat > paths.conf <<EOF
> [paths]
> nostore = $root/nostore
@@ -1135,7 +1135,7 @@
test inexistent and inaccessible repo should be ignored silently
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 ''
+ $ get-with-headers.py localhost:$HGPORT1 ''
200 Script output follows
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
@@ -1192,7 +1192,7 @@
collections: should succeed
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '?style=raw'
+ $ get-with-headers.py localhost:$HGPORT2 '?style=raw'
200 Script output follows
@@ -1203,31 +1203,31 @@
/notrepo/e/
/notrepo/f/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/file/tip/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT2 'a/file/tip/a?style=raw'
200 Script output follows
a
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'b/file/tip/b?style=raw'
+ $ get-with-headers.py localhost:$HGPORT2 'b/file/tip/b?style=raw'
200 Script output follows
b
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'c/file/tip/c?style=raw'
+ $ get-with-headers.py localhost:$HGPORT2 'c/file/tip/c?style=raw'
200 Script output follows
c
atom-log with basedir /
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/atom-log' | grep '<link'
+ $ get-with-headers.py localhost:$HGPORT2 'a/atom-log' | grep '<link'
<link rel="self" href="http://hg.example.com:8080/a/atom-log"/>
<link rel="alternate" href="http://hg.example.com:8080/a/"/>
<link href="http://hg.example.com:8080/a/rev/8580ff50825a"/>
rss-log with basedir /
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/rss-log' | grep '<guid'
+ $ get-with-headers.py localhost:$HGPORT2 'a/rss-log' | grep '<guid'
<guid isPermaLink="true">http://hg.example.com:8080/a/rev/8580ff50825a</guid>
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
> --pid-file=hg.pid --webdir-conf collections.conf \
> -A access-collections-2.log -E error-collections-2.log
@@ -1235,14 +1235,14 @@
atom-log with basedir /foo/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/atom-log' | grep '<link'
+ $ get-with-headers.py localhost:$HGPORT2 'a/atom-log' | grep '<link'
<link rel="self" href="http://hg.example.com:8080/foo/a/atom-log"/>
<link rel="alternate" href="http://hg.example.com:8080/foo/a/"/>
<link href="http://hg.example.com:8080/foo/a/rev/8580ff50825a"/>
rss-log with basedir /foo/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 'a/rss-log' | grep '<guid'
+ $ get-with-headers.py localhost:$HGPORT2 'a/rss-log' | grep '<guid'
<guid isPermaLink="true">http://hg.example.com:8080/foo/a/rev/8580ff50825a</guid>
paths errors 1
--- a/tests/test-hgwebdirsym.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hgwebdirsym.t Mon Jun 15 13:31:22 2015 -0500
@@ -33,7 +33,7 @@
should succeed
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=raw'
+ $ get-with-headers.py localhost:$HGPORT '?style=raw'
200 Script output follows
@@ -41,34 +41,34 @@
/b/
/c/
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'al/file/tip/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'al/file/tip/a?style=raw'
200 Script output follows
a
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'b/file/tip/b?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'b/file/tip/b?style=raw'
200 Script output follows
b
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'c/file/tip/c?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'c/file/tip/c?style=raw'
200 Script output follows
c
should fail
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/al/file/tip/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'circle/al/file/tip/a?style=raw'
404 Not Found
error: repository circle/al/file/tip/a not found
[1]
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/b/file/tip/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'circle/b/file/tip/a?style=raw'
404 Not Found
error: repository circle/b/file/tip/a not found
[1]
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'circle/c/file/tip/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'circle/c/file/tip/a?style=raw'
404 Not Found
--- a/tests/test-highlight.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-highlight.t Mon Jun 15 13:31:22 2015 -0500
@@ -55,7 +55,7 @@
hgweb filerevision, html
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/primes.py') \
+ $ (get-with-headers.py localhost:$HGPORT 'file/tip/primes.py') \
> | sed "s/class=\"k\"/class=\"kn\"/g" | sed "s/class=\"mf\"/class=\"mi\"/g"
200 Script output follows
@@ -105,7 +105,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>view primes.py @ 0:853dcd4de2a6</h3>
+ <h3>view primes.py @ 0:853dcd4de2a6 <span class="tag">tip</span> </h3>
<form class="search" action="/log">
@@ -185,7 +185,7 @@
hgweb fileannotate, html
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/primes.py') \
+ $ (get-with-headers.py localhost:$HGPORT 'annotate/tip/primes.py') \
> | sed "s/class=\"k\"/class=\"kn\"/g" | sed "s/class=\"mi\"/class=\"mf\"/g"
200 Script output follows
@@ -236,7 +236,7 @@
<div class="main">
<h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
- <h3>annotate primes.py @ 0:853dcd4de2a6</h3>
+ <h3>annotate primes.py @ 0:853dcd4de2a6 <span class="tag">tip</span> </h3>
<form class="search" action="/log">
@@ -515,7 +515,7 @@
hgweb fileannotate, raw
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/primes.py?style=raw') \
+ $ (get-with-headers.py localhost:$HGPORT 'annotate/tip/primes.py?style=raw') \
> | sed "s/test@//" > a
$ echo "200 Script output follows" > b
$ echo "" >> b
@@ -529,7 +529,7 @@
hgweb filerevision, raw
- $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/primes.py?style=raw') \
+ $ (get-with-headers.py localhost:$HGPORT 'file/tip/primes.py?style=raw') \
> > a
$ echo "200 Script output follows" > b
$ echo "" >> b
@@ -538,7 +538,7 @@
hgweb highlightcss friendly
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'highlightcss' > out
+ $ get-with-headers.py localhost:$HGPORT 'highlightcss' > out
$ head -n 4 out
200 Script output follows
@@ -549,7 +549,7 @@
errors encountered
$ cat errors.log
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
Change the pygments style
@@ -565,7 +565,7 @@
hgweb highlightcss fruity
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'highlightcss' > out
+ $ get-with-headers.py localhost:$HGPORT 'highlightcss' > out
$ head -n 4 out
200 Script output follows
@@ -583,13 +583,13 @@
$ hg ci -Ama
adding eucjp.txt
$ hgserveget () {
- > "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ > killdaemons.py
> echo % HGENCODING="$1" hg serve
> HGENCODING="$1" hg serve -p $HGPORT -d -n test --pid-file=hg.pid -E errors.log
> cat hg.pid >> $DAEMON_PIDS
>
> echo % hgweb filerevision, html
- > "$TESTDIR/get-with-headers.py" localhost:$HGPORT "file/tip/$2" \
+ > get-with-headers.py localhost:$HGPORT "file/tip/$2" \
> | grep '<div class="parity0 source">'
> echo % errors encountered
> cat errors.log
--- a/tests/test-histedit-edit.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-histedit-edit.t Mon Jun 15 13:31:22 2015 -0500
@@ -246,6 +246,7 @@
branch: default
commit: 1 added (new branch head)
update: 1 new changesets (update)
+ phases: 7 draft
hist: 1 remaining (histedit --continue)
(test also that editor is invoked if histedit is continued for
@@ -435,3 +436,32 @@
$ HGEDITOR=true hg histedit --continue
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
saved backup bundle to $TESTTMP/r0/.hg/strip-backup/cb9a9f314b8b-cc5ccb0b-backup.hg (glob)
+
+ $ hg log -G
+ @ changeset: 0:0efcea34f18a
+ tag: tip
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: a
+
+ $ echo foo >> b
+ $ hg addr
+ adding b
+ $ hg ci -m 'add b'
+ $ echo foo >> a
+ $ hg ci -m 'extend a'
+ $ hg phase --public 1
+Attempting to fold a change into a public change should not work:
+ $ cat > ../edit.sh <<EOF
+ > cat "\$1" | sed s/pick/fold/ > tmp
+ > mv tmp "\$1"
+ > EOF
+ $ HGEDITOR="sh ../edit.sh" hg histedit 2
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ reverting a
+ 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ abort: cannot fold into public change 18aa70c8ad22
+ [255]
+TODO: this abort shouldn't be required, but it is for now to leave the repo in
+a clean state.
+ $ hg histedit --abort
--- a/tests/test-histedit-no-change.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-histedit-no-change.t Mon Jun 15 13:31:22 2015 -0500
@@ -183,6 +183,7 @@
branch: default
commit: 1 added, 1 unknown (new branch head)
update: 6 new changesets (update)
+ phases: 7 draft
hist: 2 remaining (histedit --continue)
$ hg histedit --abort 2>&1 | fixbundle
--- a/tests/test-histedit-obsolete.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-histedit-obsolete.t Mon Jun 15 13:31:22 2015 -0500
@@ -219,7 +219,8 @@
o 0:cb9a9f314b8b (public) a
$ hg histedit -r '.~2'
- abort: cannot edit immutable changeset: cb9a9f314b8b
+ abort: cannot edit public changeset: cb9a9f314b8b
+ (see "hg help phases" for details)
[255]
--- a/tests/test-hook.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hook.t Mon Jun 15 13:31:22 2015 -0500
@@ -1,6 +1,13 @@
commit hooks can see env vars
(and post-transaction one are run unlocked)
+ $ cat << EOF >> $HGRCPATH
+ > [experimental]
+ > # drop me once bundle2 is the default,
+ > # added to get test change early.
+ > bundle2-exp = True
+ > EOF
+
$ cat > $TESTTMP/txnabort.checkargs.py <<EOF
> def showargs(ui, repo, hooktype, **kwargs):
> ui.write('%s python hook: %s\n' % (hooktype, ','.join(sorted(kwargs))))
@@ -10,19 +17,19 @@
$ cd a
$ cat > .hg/hgrc <<EOF
> [hooks]
- > commit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit"
- > commit.b = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" commit.b"
- > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= python \"$TESTDIR/printenv.py\" precommit"
- > pretxncommit = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxncommit"
+ > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py commit"
+ > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py commit.b"
+ > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
+ > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
> pretxncommit.tip = hg -q tip
- > pre-identify = python "$TESTDIR/printenv.py" pre-identify 1
- > pre-cat = python "$TESTDIR/printenv.py" pre-cat
- > post-cat = python "$TESTDIR/printenv.py" post-cat
- > pretxnopen = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxnopen"
- > pretxnclose = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" pretxnclose"
- > txnclose = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" txnclose"
+ > pre-identify = printenv.py pre-identify 1
+ > pre-cat = printenv.py pre-cat
+ > post-cat = printenv.py post-cat
+ > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
+ > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
+ > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
> txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
- > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= python \"$TESTDIR/printenv.py\" txnabort"
+ > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
> txnclose.checklock = sh -c "hg debuglock > /dev/null"
> EOF
$ echo a > a
@@ -46,9 +53,9 @@
$ cat > .hg/hgrc <<EOF
> [hooks]
- > prechangegroup = python "$TESTDIR/printenv.py" prechangegroup
- > changegroup = python "$TESTDIR/printenv.py" changegroup
- > incoming = python "$TESTDIR/printenv.py" incoming
+ > prechangegroup = printenv.py prechangegroup
+ > changegroup = printenv.py changegroup
+ > incoming = printenv.py incoming
> EOF
pretxncommit and commit hooks can see both parents of merge
@@ -121,8 +128,8 @@
$ cd ../a
$ cat >> .hg/hgrc <<EOF
- > pretag = python "$TESTDIR/printenv.py" pretag
- > tag = sh -c "HG_PARENT1= HG_PARENT2= python \"$TESTDIR/printenv.py\" tag"
+ > pretag = printenv.py pretag
+ > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
> EOF
$ hg tag -d '3 0' a
pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
@@ -141,7 +148,7 @@
pretag hook can forbid tagging
- $ echo "pretag.forbid = python \"$TESTDIR/printenv.py\" pretag.forbid 1" >> .hg/hgrc
+ $ echo "pretag.forbid = printenv.py pretag.forbid 1" >> .hg/hgrc
$ hg tag -d '4 0' fa
pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
@@ -157,7 +164,7 @@
more there after
$ echo "pretxncommit.forbid0 = hg tip -q" >> .hg/hgrc
- $ echo "pretxncommit.forbid1 = python \"$TESTDIR/printenv.py\" pretxncommit.forbid 1" >> .hg/hgrc
+ $ echo "pretxncommit.forbid1 = printenv.py pretxncommit.forbid 1" >> .hg/hgrc
$ echo z > z
$ hg add z
$ hg -q tip
@@ -195,7 +202,7 @@
precommit hook can prevent commit
- $ echo "precommit.forbid = python \"$TESTDIR/printenv.py\" precommit.forbid 1" >> .hg/hgrc
+ $ echo "precommit.forbid = printenv.py precommit.forbid 1" >> .hg/hgrc
$ hg commit -m 'fail' -d '4 0'
precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
@@ -206,14 +213,14 @@
preupdate hook can prevent update
- $ echo "preupdate = python \"$TESTDIR/printenv.py\" preupdate" >> .hg/hgrc
+ $ echo "preupdate = printenv.py preupdate" >> .hg/hgrc
$ hg update 1
preupdate hook: HG_PARENT1=ab228980c14d
0 files updated, 0 files merged, 2 files removed, 0 files unresolved
update hook
- $ echo "update = python \"$TESTDIR/printenv.py\" update" >> .hg/hgrc
+ $ echo "update = printenv.py update" >> .hg/hgrc
$ hg update
preupdate hook: HG_PARENT1=539e4b31b6dc
update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
@@ -221,38 +228,38 @@
pushkey hook
- $ echo "pushkey = python \"$TESTDIR/printenv.py\" pushkey" >> .hg/hgrc
+ $ echo "pushkey = printenv.py pushkey" >> .hg/hgrc
$ cd ../b
$ hg bookmark -r null foo
$ hg push -B foo ../a
pushing to ../a
searching for changes
no changes found
- pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmarks (glob)
- pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmarks (glob)
- txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmarks (glob)
+ pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
+ pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_PENDING=$TESTTMP/a HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
+ txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
exporting bookmark foo
[1]
$ cd ../a
listkeys hook
- $ echo "listkeys = python \"$TESTDIR/printenv.py\" listkeys" >> .hg/hgrc
+ $ echo "listkeys = printenv.py listkeys" >> .hg/hgrc
$ hg bookmark -r null bar
$ cd ../b
$ hg pull -B bar ../a
pulling from ../a
listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
- listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
no changes found
+ listkeys hook: HG_NAMESPACE=phase HG_VALUES={}
+ adding remote bookmark bar
listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
- adding remote bookmark bar
$ cd ../a
test that prepushkey can prevent incoming keys
- $ echo "prepushkey = python \"$TESTDIR/printenv.py\" prepushkey.forbid 1" >> .hg/hgrc
+ $ echo "prepushkey = printenv.py prepushkey.forbid 1" >> .hg/hgrc
$ cd ../b
$ hg bookmark -r null baz
$ hg push -B baz ../a
@@ -261,16 +268,16 @@
listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
no changes found
- listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
- prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000
+ pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
+ prepushkey.forbid hook: HG_BUNDLE2=1 HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_SOURCE=push HG_TXNID=TXN:* HG_URL=push (glob)
pushkey-abort: prepushkey hook exited with status 1
- exporting bookmark baz failed!
- [1]
+ abort: exporting bookmark baz failed!
+ [255]
$ cd ../a
test that prelistkeys can prevent listing keys
- $ echo "prelistkeys = python \"$TESTDIR/printenv.py\" prelistkeys.forbid 1" >> .hg/hgrc
+ $ echo "prelistkeys = printenv.py prelistkeys.forbid 1" >> .hg/hgrc
$ hg bookmark -r null quux
$ cd ../b
$ hg pull -B quux ../a
@@ -288,7 +295,7 @@
3:07f3376c1e65
$ cat > .hg/hgrc <<EOF
> [hooks]
- > prechangegroup.forbid = python "$TESTDIR/printenv.py" prechangegroup.forbid 1
+ > prechangegroup.forbid = printenv.py prechangegroup.forbid 1
> EOF
$ hg pull ../a
pulling from ../a
@@ -303,7 +310,7 @@
$ cat > .hg/hgrc <<EOF
> [hooks]
> pretxnchangegroup.forbid0 = hg tip -q
- > pretxnchangegroup.forbid1 = python "$TESTDIR/printenv.py" pretxnchangegroup.forbid 1
+ > pretxnchangegroup.forbid1 = printenv.py pretxnchangegroup.forbid 1
> EOF
$ hg pull ../a
pulling from ../a
@@ -326,15 +333,15 @@
$ rm .hg/hgrc
$ cat > ../a/.hg/hgrc <<EOF
> [hooks]
- > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
- > outgoing = python "$TESTDIR/printenv.py" outgoing
+ > preoutgoing = printenv.py preoutgoing
+ > outgoing = printenv.py outgoing
> EOF
$ hg pull ../a
pulling from ../a
searching for changes
preoutgoing hook: HG_SOURCE=pull
+ outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
adding changesets
- outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
@@ -345,7 +352,7 @@
preoutgoing hook can prevent outgoing changes
- $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> ../a/.hg/hgrc
+ $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> ../a/.hg/hgrc
$ hg pull ../a
pulling from ../a
searching for changes
@@ -359,8 +366,8 @@
$ cd ..
$ cat > a/.hg/hgrc <<EOF
> [hooks]
- > preoutgoing = python "$TESTDIR/printenv.py" preoutgoing
- > outgoing = python "$TESTDIR/printenv.py" outgoing
+ > preoutgoing = printenv.py preoutgoing
+ > outgoing = printenv.py outgoing
> EOF
$ hg clone a c
preoutgoing hook: HG_SOURCE=clone
@@ -371,7 +378,7 @@
preoutgoing hook can prevent outgoing changes for local clones
- $ echo "preoutgoing.forbid = python \"$TESTDIR/printenv.py\" preoutgoing.forbid 1" >> a/.hg/hgrc
+ $ echo "preoutgoing.forbid = printenv.py preoutgoing.forbid 1" >> a/.hg/hgrc
$ hg clone a zzz
preoutgoing hook: HG_SOURCE=clone
preoutgoing.forbid hook: HG_SOURCE=clone
--- a/tests/test-http-branchmap.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-http-branchmap.t Mon Jun 15 13:31:22 2015 -0500
@@ -54,7 +54,7 @@
date: Thu Jan 01 00:00:00 1970 +0000
summary: foo
- $ "$TESTDIR/killdaemons.py" hg.pid
+ $ killdaemons.py hg.pid
verify 7e7d56fe4833 (encoding fallback in branchmap to maintain compatibility with 1.3.x)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-http-bundle1.t Mon Jun 15 13:31:22 2015 -0500
@@ -0,0 +1,333 @@
+#require serve
+
+This test is a duplicate of 'test-http.t', feel free to factor out
+parts that are not bundle1/bundle2 specific.
+
+ $ cat << EOF >> $HGRCPATH
+ > [experimental]
+ > # This test is dedicated to interaction through old bundle
+ > bundle2-exp = False
+ > EOF
+
+ $ hg init test
+ $ cd test
+ $ echo foo>foo
+ $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
+ $ echo foo>foo.d/foo
+ $ echo bar>foo.d/bAr.hg.d/BaR
+ $ echo bar>foo.d/baR.d.hg/bAR
+ $ hg commit -A -m 1
+ adding foo
+ adding foo.d/bAr.hg.d/BaR
+ adding foo.d/baR.d.hg/bAR
+ adding foo.d/foo
+ $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
+ $ hg --config server.uncompressed=False serve -p $HGPORT1 -d --pid-file=../hg2.pid
+
+Test server address cannot be reused
+
+#if windows
+ $ hg serve -p $HGPORT1 2>&1
+ abort: cannot start server at ':$HGPORT1': * (glob)
+ [255]
+#else
+ $ hg serve -p $HGPORT1 2>&1
+ abort: cannot start server at ':$HGPORT1': Address already in use
+ [255]
+#endif
+ $ cd ..
+ $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
+
+clone via stream
+
+ $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
+ streaming all changes
+ 6 files to transfer, 606 bytes of data
+ transferred * bytes in * seconds (*/sec) (glob)
+ searching for changes
+ no changes found
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg verify -R copy
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 1 changesets, 4 total revisions
+
+try to clone via stream, should use pull instead
+
+ $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 4 changes to 4 files
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+clone via pull
+
+ $ hg clone http://localhost:$HGPORT1/ copy-pull
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 4 changes to 4 files
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg verify -R copy-pull
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 4 files, 1 changesets, 4 total revisions
+ $ cd test
+ $ echo bar > bar
+ $ hg commit -A -d '1 0' -m 2
+ adding bar
+ $ cd ..
+
+clone over http with --update
+
+ $ hg clone http://localhost:$HGPORT1/ updated --update 0
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 5 changes to 5 files
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg log -r . -R updated
+ changeset: 0:8b6053c928fe
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: 1
+
+ $ rm -rf updated
+
+incoming via HTTP
+
+ $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 4 changes to 4 files
+ updating to branch default
+ 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd partial
+ $ touch LOCAL
+ $ hg ci -qAm LOCAL
+ $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
+ comparing with http://localhost:$HGPORT1/
+ searching for changes
+ 2
+ $ cd ..
+
+pull
+
+ $ cd copy-pull
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
+ $ hg pull
+ pulling from http://localhost:$HGPORT1/
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=http://localhost:$HGPORT1/ (glob)
+ (run 'hg update' to get a working copy)
+ $ cd ..
+
+clone from invalid URL
+
+ $ hg clone http://localhost:$HGPORT/bad
+ abort: HTTP Error 404: Not Found
+ [255]
+
+test http authentication
++ use the same server to test server side streaming preference
+
+ $ cd test
+ $ cat << EOT > userpass.py
+ > import base64
+ > from mercurial.hgweb import common
+ > def perform_authentication(hgweb, req, op):
+ > auth = req.env.get('HTTP_AUTHORIZATION')
+ > if not auth:
+ > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
+ > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
+ > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
+ > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
+ > def extsetup():
+ > common.permhooks.insert(0, perform_authentication)
+ > EOT
+ $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid \
+ > --config server.preferuncompressed=True \
+ > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
+ $ cat pid >> $DAEMON_PIDS
+
+ $ cat << EOF > get_pass.py
+ > import getpass
+ > def newgetpass(arg):
+ > return "pass"
+ > getpass.getpass = newgetpass
+ > EOF
+
+ $ hg id http://localhost:$HGPORT2/
+ abort: http authorization required for http://localhost:$HGPORT2/
+ [255]
+ $ hg id http://localhost:$HGPORT2/
+ abort: http authorization required for http://localhost:$HGPORT2/
+ [255]
+ $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
+ http authorization required for http://localhost:$HGPORT2/
+ realm: mercurial
+ user: user
+ password: 5fed3813f7f5
+ $ hg id http://user:pass@localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ echo '[auth]' >> .hg/hgrc
+ $ echo 'l.schemes=http' >> .hg/hgrc
+ $ echo 'l.prefix=lo' >> .hg/hgrc
+ $ echo 'l.username=user' >> .hg/hgrc
+ $ echo 'l.password=pass' >> .hg/hgrc
+ $ hg id http://localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ hg id http://localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ hg id http://user@localhost:$HGPORT2/
+ 5fed3813f7f5
+ $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
+ streaming all changes
+ 7 files to transfer, 916 bytes of data
+ transferred * bytes in * seconds (*/sec) (glob)
+ searching for changes
+ no changes found
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+--pull should override server's preferuncompressed
+ $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 2 changesets with 5 changes to 5 files
+ updating to branch default
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ hg id http://user2@localhost:$HGPORT2/
+ abort: http authorization required for http://localhost:$HGPORT2/
+ [255]
+ $ hg id http://user:pass2@localhost:$HGPORT2/
+ abort: HTTP Error 403: no
+ [255]
+
+ $ hg -R dest tag -r tip top
+ $ hg -R dest push http://user:pass@localhost:$HGPORT2/
+ pushing to http://user:***@localhost:$HGPORT2/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ $ hg rollback -q
+
+ $ cut -c38- ../access.log
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=branchmap HTTP/1.1" 200 -
+ "GET /?cmd=stream_out HTTP/1.1" 401 -
+ "GET /?cmd=stream_out HTTP/1.1" 200 -
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
+ "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=bookmarks
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
+ "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D
+ "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces
+ "GET /?cmd=capabilities HTTP/1.1" 200 -
+ "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872
+ "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
+ "GET /?cmd=branchmap HTTP/1.1" 200 -
+ "GET /?cmd=branchmap HTTP/1.1" 200 -
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
+ "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=686173686564+5eb5abfefeea63c80dd7553bcc3783f37e0c5524
+ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
+
+ $ cd ..
+
+clone of serve with repo in root and unserved subrepo (issue2970)
+
+ $ hg --cwd test init sub
+ $ echo empty > test/sub/empty
+ $ hg --cwd test/sub add empty
+ $ hg --cwd test/sub commit -qm 'add empty'
+ $ hg --cwd test/sub tag -r 0 something
+ $ echo sub = sub > test/.hgsub
+ $ hg --cwd test add .hgsub
+ $ hg --cwd test commit -qm 'add subrepo'
+ $ hg clone http://localhost:$HGPORT noslash-clone
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 7 changes to 7 files
+ updating to branch default
+ abort: HTTP Error 404: Not Found
+ [255]
+ $ hg clone http://localhost:$HGPORT/ slash-clone
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 7 changes to 7 files
+ updating to branch default
+ abort: HTTP Error 404: Not Found
+ [255]
+
+check error log
+
+ $ cat error.log
--- a/tests/test-http-proxy.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-http-proxy.t Mon Jun 15 13:31:22 2015 -0500
@@ -1,4 +1,10 @@
#require serve
+ $ cat << EOF >> $HGRCPATH
+ > [experimental]
+ > # drop me once bundle2 is the default,
+ > # added to get test change early.
+ > bundle2-exp = True
+ > EOF
$ hg init a
$ cd a
@@ -8,7 +14,7 @@
$ hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=hg.pid
$ cat hg.pid >> $DAEMON_PIDS
$ cd ..
- $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
+ $ tinyproxy.py $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
$ while [ ! -f proxy.pid ]; do sleep 0; done
$ cat proxy.pid >> $DAEMON_PIDS
@@ -103,26 +109,22 @@
* - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=branchmap HTTP/1.1" - - (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=stream_out HTTP/1.1" - - (glob)
- * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=83180e7845de420a1bb46896fd5fe05294f8d629&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
- *- - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
- *- - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
- *- - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
- *- - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
- * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
- * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
- * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
- * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
- * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
- * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
- * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
+ * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
* - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
--- a/tests/test-http.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-http.t Mon Jun 15 13:31:22 2015 -0500
@@ -119,7 +119,7 @@
$ cd copy-pull
$ echo '[hooks]' >> .hg/hgrc
- $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
+ $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
$ hg pull
pulling from http://localhost:$HGPORT1/
searching for changes
@@ -166,7 +166,6 @@
> getpass.getpass = newgetpass
> EOF
-#if python243
$ hg id http://localhost:$HGPORT2/
abort: http authorization required for http://localhost:$HGPORT2/
[255]
@@ -180,7 +179,6 @@
password: 5fed3813f7f5
$ hg id http://user:pass@localhost:$HGPORT2/
5fed3813f7f5
-#endif
$ echo '[auth]' >> .hg/hgrc
$ echo 'l.schemes=http' >> .hg/hgrc
$ echo 'l.prefix=lo' >> .hg/hgrc
@@ -192,7 +190,6 @@
5fed3813f7f5
$ hg id http://user@localhost:$HGPORT2/
5fed3813f7f5
-#if python243
$ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
streaming all changes
7 files to transfer, 916 bytes of data
@@ -264,14 +261,13 @@
"GET /?cmd=branchmap HTTP/1.1" 200 -
"GET /?cmd=stream_out HTTP/1.1" 401 -
"GET /?cmd=stream_out HTTP/1.1" 200 -
- "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
"GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d
+ "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
"GET /?cmd=capabilities HTTP/1.1" 200 -
- "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=bookmarks
- "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
"GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D
- "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d
+ "GET /?cmd=getbundle HTTP/1.1" 401 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
+ "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
@@ -288,10 +284,9 @@
"GET /?cmd=branchmap HTTP/1.1" 200 -
"GET /?cmd=branchmap HTTP/1.1" 200 -
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
- "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=686173686564+5eb5abfefeea63c80dd7553bcc3783f37e0c5524
+ "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
-#endif
$ cd ..
clone of serve with repo in root and unserved subrepo (issue2970)
--- a/tests/test-https.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-https.t Mon Jun 15 13:31:22 2015 -0500
@@ -81,6 +81,53 @@
> EOT
$ cat priv.pem pub-expired.pem > server-expired.pem
+Client certificates created with:
+ openssl genrsa -aes128 -passout pass:1234 -out client-key.pem 512
+ openssl rsa -in client-key.pem -passin pass:1234 -out client-key-decrypted.pem
+ printf '.\n.\n.\n.\n.\n.\nhg-client@localhost\n.\n.\n' | \
+ openssl req -new -key client-key.pem -passin pass:1234 -out client-csr.pem
+ openssl x509 -req -days 9000 -in client-csr.pem -CA pub.pem -CAkey priv.pem \
+ -set_serial 01 -out client-cert.pem
+
+ $ cat << EOT > client-key.pem
+ > -----BEGIN RSA PRIVATE KEY-----
+ > Proc-Type: 4,ENCRYPTED
+ > DEK-Info: AES-128-CBC,C8B8F103A61A336FB0716D1C0F8BB2E8
+ >
+ > JolMlCFjEW3q3JJjO9z99NJWeJbFgF5DpUOkfSCxH56hxxtZb9x++rBvBZkxX1bF
+ > BAIe+iI90+jdCLwxbILWuFcrJUaLC5WmO14XDKYVmr2eW9e4MiCYOlO0Q6a9rDFS
+ > jctRCfvubOXFHbBGLH8uKEMpXEkP7Lc60FiIukqjuQEivJjrQirVtZCGwyk3qUi7
+ > Eyh4Lo63IKGu8T1Bkmn2kaMvFhu7nC/CQLBjSq0YYI1tmCOkVb/3tPrz8oqgDJp2
+ > u7bLS3q0xDNZ52nVrKIoZC/UlRXGlPyzPpa70/jPIdfCbkwDaBpRVXc+62Pj2n5/
+ > CnO2xaKwfOG6pDvanBhFD72vuBOkAYlFZPiEku4sc2WlNggsSWCPCIFwzmiHjKIl
+ > bWmdoTq3nb7sNfnBbV0OCa7fS1dFwCm4R1NC7ELENu0=
+ > -----END RSA PRIVATE KEY-----
+ > EOT
+
+ $ cat << EOT > client-key-decrypted.pem
+ > -----BEGIN RSA PRIVATE KEY-----
+ > MIIBOgIBAAJBAJs4LS3glAYU92bg5kPgRPNW84ewB0fWJfAKccCp1ACHAdZPeaKb
+ > FCinVMYKAVbVqBkyrZ/Tyr8aSfMz4xO4+KsCAwEAAQJAeKDr25+Q6jkZHEbkLRP6
+ > AfMtR+Ixhk6TJT24sbZKIC2V8KuJTDEvUhLU0CAr1nH79bDqiSsecOiVCr2HHyfT
+ > AQIhAM2C5rHbTs9R3PkywFEqq1gU3ztCnpiWglO7/cIkuGBhAiEAwVpMSAf77kop
+ > 4h/1kWsgMALQTJNsXd4CEUK4BOxvJIsCIQCbarVAKBQvoT81jfX27AfscsxnKnh5
+ > +MjSvkanvdFZwQIgbbcTefwt1LV4trtz2SR0i0nNcOZmo40Kl0jIquKO3qkCIH01
+ > mJHzZr3+jQqeIFtr5P+Xqi30DJxgrnEobbJ0KFjY
+ > -----END RSA PRIVATE KEY-----
+ > EOT
+
+ $ cat << EOT > client-cert.pem
+ > -----BEGIN CERTIFICATE-----
+ > MIIBPjCB6QIBATANBgkqhkiG9w0BAQsFADAxMRIwEAYDVQQDDAlsb2NhbGhvc3Qx
+ > GzAZBgkqhkiG9w0BCQEWDGhnQGxvY2FsaG9zdDAeFw0xNTA1MDcwNjI5NDVaFw0z
+ > OTEyMjcwNjI5NDVaMCQxIjAgBgkqhkiG9w0BCQEWE2hnLWNsaWVudEBsb2NhbGhv
+ > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAmzgtLeCUBhT3ZuDmQ+BE81bzh7AH
+ > R9Yl8ApxwKnUAIcB1k95opsUKKdUxgoBVtWoGTKtn9PKvxpJ8zPjE7j4qwIDAQAB
+ > MA0GCSqGSIb3DQEBCwUAA0EAfBTqBG5pYhuGk+ZnyUufgS+d7Nk/sZAZjNdCAEj/
+ > NFPo5fR1jM6jlEWoWbeg298+SkjV7tfO+2nt0otUFkdM6A==
+ > -----END CERTIFICATE-----
+ > EOT
+
$ hg init test
$ cd test
$ echo foo>foo
@@ -154,7 +201,7 @@
$ cd copy-pull
$ echo '[hooks]' >> .hg/hgrc
- $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
+ $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
$ hg pull $DISABLEOSXDUMMYCERT
pulling from https://localhost:$HGPORT/
warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
@@ -255,11 +302,11 @@
5fed3813f7f5
HGPORT1 is reused below for tinyproxy tests. Kill that server.
- $ "$TESTDIR/killdaemons.py" hg1.pid
+ $ killdaemons.py hg1.pid
Prepare for connecting through proxy
- $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
+ $ tinyproxy.py $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
$ while [ ! -f proxy.pid ]; do sleep 0; done
$ cat proxy.pid >> $DAEMON_PIDS
@@ -297,3 +344,60 @@
pulling from https://localhost:$HGPORT2/
abort: error: *certificate verify failed* (glob)
[255]
+
+
+ $ killdaemons.py hg0.pid
+
+#if sslcontext
+
+Start patched hgweb that requires client certificates:
+
+ $ cat << EOT > reqclientcert.py
+ > import ssl
+ > from mercurial.hgweb import server
+ > class _httprequesthandlersslclientcert(server._httprequesthandlerssl):
+ > @staticmethod
+ > def preparehttpserver(httpserver, ssl_cert):
+ > sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
+ > sslcontext.verify_mode = ssl.CERT_REQUIRED
+ > sslcontext.load_cert_chain(ssl_cert)
+ > # verify clients by server certificate
+ > sslcontext.load_verify_locations(ssl_cert)
+ > httpserver.socket = sslcontext.wrap_socket(httpserver.socket,
+ > server_side=True)
+ > server._httprequesthandlerssl = _httprequesthandlersslclientcert
+ > EOT
+ $ cd test
+ $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV \
+ > --config extensions.reqclientcert=../reqclientcert.py
+ $ cat ../hg0.pid >> $DAEMON_PIDS
+ $ cd ..
+
+without client certificate:
+
+ $ P=`pwd` hg id https://localhost:$HGPORT/
+ abort: error: *handshake failure* (glob)
+ [255]
+
+with client certificate:
+
+ $ cat << EOT >> $HGRCPATH
+ > [auth]
+ > l.prefix = localhost
+ > l.cert = client-cert.pem
+ > l.key = client-key.pem
+ > EOT
+
+ $ P=`pwd` hg id https://localhost:$HGPORT/ \
+ > --config auth.l.key=client-key-decrypted.pem
+ 5fed3813f7f5
+
+ $ printf '1234\n' | env P=`pwd` hg id https://localhost:$HGPORT/ \
+ > --config ui.interactive=True --config ui.nontty=True
+ passphrase for client-key.pem: 5fed3813f7f5
+
+ $ env P=`pwd` hg id https://localhost:$HGPORT/
+ abort: error: * (glob)
+ [255]
+
+#endif
--- a/tests/test-hybridencode.py Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hybridencode.py Mon Jun 15 13:31:22 2015 -0500
@@ -460,3 +460,9 @@
'VWXYZ-1234567890-xxxxxxxxx-xxxxxxxxx-xxxxxxxx-xxxx'
'xxxxx-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwww'
'wwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww.i')
+
+print "paths outside data/ can be encoded"
+show('metadata/dir/00manifest.i')
+show('metadata/12345678/12345678/12345678/12345678/12345678/'
+ '12345678/12345678/12345678/12345678/12345678/12345678/'
+ '12345678/12345678/00manifest.i')
--- a/tests/test-hybridencode.py.out Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-hybridencode.py.out Mon Jun 15 13:31:22 2015 -0500
@@ -491,3 +491,10 @@
A = 'data/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/-xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPRSTUVWXYZ-1234567890-xxxxxxxxx-xxxxxxxxx-xxxxxxxx-xxxxxxxxx-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww-wwwwwwwww.i'
B = 'dh/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/-xxxxx93352aa50377751d9e5ebdf52da1e6e69a6887a6.i'
+paths outside data/ can be encoded
+A = 'metadata/dir/00manifest.i'
+B = 'metadata/dir/00manifest.i'
+
+A = 'metadata/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345678/00manifest.i'
+B = 'dh/ata/12345678/12345678/12345678/12345678/12345678/12345678/12345678/00manife0a4da1f89aa2aa9eb0896eb451288419049781b4.i'
+
--- a/tests/test-import.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-import.t Mon Jun 15 13:31:22 2015 -0500
@@ -990,6 +990,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 2 draft
$ hg diff --git -c tip
diff --git a/lib/place-holder b/lib/place-holder
@@ -1018,6 +1019,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 2 draft
$ hg diff --git -c tip
diff --git a/lib/place-holder b/lib/place-holder
--- a/tests/test-issue1802.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-issue1802.t Mon Jun 15 13:31:22 2015 -0500
@@ -58,7 +58,6 @@
branchmerge: True, force: False, partial: False
ancestor: a03b0deabf2b, local: d6fa54f68ae1+, remote: 2d8bcf2dda39
a: update permissions -> e
- updating: a 1/1 files (100.00%)
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
--- a/tests/test-issue522.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-issue522.t Mon Jun 15 13:31:22 2015 -0500
@@ -33,7 +33,6 @@
ancestor: bbd179dfa0a7, local: 71766447bdbb+, remote: 4d9e78aaceee
foo: remote is newer -> g
getting foo
- updating: foo 1/1 files (100.00%)
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
--- a/tests/test-issue672.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-issue672.t Mon Jun 15 13:31:22 2015 -0500
@@ -36,10 +36,8 @@
ancestor: 81f4b099af3d, local: c64f439569a9+, remote: c12dcd37c90a
1: other deleted -> r
removing 1
- updating: 1 1/2 files (50.00%)
1a: remote created -> g
getting 1a
- updating: 1a 2/2 files (100.00%)
2: remote unchanged -> k
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
(branch merge, don't forget to commit)
@@ -68,7 +66,6 @@
ancestor: c64f439569a9, local: e327dca35ac8+, remote: 746e9549ea96
preserving 1a for resolve of 1a
1a: local copied/moved from 1 -> m
- updating: 1a 1/1 files (100.00%)
picked tool 'internal:merge' for 1a (binary False symlink False)
merging 1a and 1 to 1a
my 1a@e327dca35ac8+ other 1@746e9549ea96 ancestor 1@81f4b099af3d
@@ -92,7 +89,6 @@
preserving 1 for resolve of 1a
removing 1
1a: remote moved from 1 -> m
- updating: 1a 1/1 files (100.00%)
picked tool 'internal:merge' for 1a (binary False symlink False)
merging 1 and 1a to 1a
my 1a@746e9549ea96+ other 1a@e327dca35ac8 ancestor 1@81f4b099af3d
--- a/tests/test-keyword.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-keyword.t Mon Jun 15 13:31:22 2015 -0500
@@ -980,14 +980,14 @@
$ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/a/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'file/tip/a/?style=raw'
200 Script output follows
expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
do not process $Id:
xxx $
$Xinfo: User Name <user@example.com>: firstline $
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'annotate/tip/a/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'annotate/tip/a/?style=raw'
200 Script output follows
@@ -999,7 +999,7 @@
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/tip/?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'rev/tip/?style=raw'
200 Script output follows
@@ -1019,7 +1019,7 @@
+xxx $
+$Xinfo$
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/bb948857c743/a?style=raw'
+ $ get-with-headers.py localhost:$HGPORT 'diff/bb948857c743/a?style=raw'
200 Script output follows
--- a/tests/test-known.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-known.t Mon Jun 15 13:31:22 2015 -0500
@@ -35,5 +35,5 @@
$ hg debugknown http://localhost:$HGPORT/
$ cat error.log
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
--- a/tests/test-largefiles-misc.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-largefiles-misc.t Mon Jun 15 13:31:22 2015 -0500
@@ -228,6 +228,7 @@
branch: default
commit: 1 subrepos
update: (current)
+ phases: 2 draft
$ hg st
$ hg st -S
A subrepo/large.txt
@@ -245,6 +246,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 3 draft
$ echo "rev 2" > subrepo/large.txt
$ hg st -S
M subrepo/large.txt
@@ -254,6 +256,7 @@
branch: default
commit: 1 subrepos
update: (current)
+ phases: 3 draft
$ hg ci -m "this commit should fail without -S"
abort: uncommitted changes in subrepository 'subrepo'
(use --subrepos for recursive commit)
@@ -567,6 +570,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 1 draft
largefiles: (no remote repo)
check messages when there is no files to upload:
@@ -581,6 +585,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 1 draft
largefiles: (no files to upload)
$ hg -R clone2 outgoing --large
comparing with $TESTTMP/issue3651/src (glob)
@@ -608,6 +613,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 2 draft
largefiles: 1 entities for 1 files to upload
$ hg -R clone2 outgoing --large
comparing with $TESTTMP/issue3651/src (glob)
@@ -643,6 +649,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 3 draft
largefiles: 1 entities for 3 files to upload
$ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
comparing with $TESTTMP/issue3651/src (glob)
@@ -656,7 +663,7 @@
$ hg -R clone2 cat -r 1 clone2/.hglf/b
89e6c98d92887913cadf06b2adb97f26cde4849b
- $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
+ $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
comparing with $TESTTMP/issue3651/src (glob)
query 1; heads
searching for changes
@@ -692,6 +699,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 6 draft
largefiles: 3 entities for 3 files to upload
$ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
comparing with $TESTTMP/issue3651/src (glob)
@@ -710,7 +718,7 @@
c801c9cfe94400963fcb683246217d5db77f9a9a
$ hg -R clone2 cat -r 4 clone2/.hglf/b
13f9ed0898e315bf59dc2973fec52037b6f441a2
- $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
+ $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
comparing with $TESTTMP/issue3651/src (glob)
query 1; heads
searching for changes
@@ -750,6 +758,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 6 draft
largefiles: 2 entities for 1 files to upload
$ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n"
comparing with $TESTTMP/issue3651/src (glob)
@@ -761,7 +770,7 @@
largefiles to upload (2 entities):
b
- $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug
+ $ hg -R clone2 outgoing --large -T "{rev}:{node|short}\n" --debug --config progress.debug=true
comparing with $TESTTMP/issue3651/src (glob)
query 1; heads
searching for changes
@@ -975,7 +984,7 @@
> EOF
$ hg -R pull-dst -q pull -u http://localhost:$HGPORT
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
#endif
Test overridden functions work correctly even for repos disabling
@@ -1017,7 +1026,7 @@
$ hg -R no-largefiles -q pull --rebase
Invoking status precommit hook
- ? normal3
+ M normal3
(test reverting)
--- a/tests/test-largefiles-wireproto.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-largefiles-wireproto.t Mon Jun 15 13:31:22 2015 -0500
@@ -106,16 +106,19 @@
[255]
used all HGPORTs, kill all daemons
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
#endif
vanilla clients locked out from largefiles ssh repos
$ hg --config extensions.largefiles=! clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/r4 r5
- abort: remote error:
-
- This repository uses the largefiles extension.
-
- Please enable it in your Mercurial config file.
+ remote:
+ remote: This repository uses the largefiles extension.
+ remote:
+ remote: Please enable it in your Mercurial config file.
+ remote:
+ remote: -
+ abort: remote error
+ (check previous remote output)
[255]
#if serve
@@ -264,7 +267,7 @@
largefiles pulled on update - no server side problems:
$ mv 02a439e5c31c526465ab1a0ca1f431f76b827b90 empty/.hg/largefiles/
- $ hg -R http-clone --debug up --config largefiles.usercache=http-clone-usercache
+ $ hg -R http-clone --debug up --config largefiles.usercache=http-clone-usercache --config progress.debug=true
resolving manifests
branchmerge: False, force: False, partial: False
ancestor: 000000000000, local: 000000000000+, remote: cf03e5bb9936
@@ -288,6 +291,6 @@
$ rm -rf empty http-clone*
used all HGPORTs, kill all daemons
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
#endif
--- a/tests/test-largefiles.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-largefiles.t Mon Jun 15 13:31:22 2015 -0500
@@ -19,6 +19,10 @@
> usercache=${USERCACHE}
> [hooks]
> precommit=sh -c "echo \\"Invoking status precommit hook\\"; hg status"
+ > [experimental]
+ > # drop me once bundle2 is the default,
+ > # added to get test change early.
+ > bundle2-exp = True
> EOF
Create the repo with a couple of revisions of both large and normal
@@ -67,6 +71,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 2 draft
largefiles: (no remote repo)
Commit preserved largefile contents.
@@ -191,7 +196,7 @@
$ hg serve -d -p $HGPORT --pid-file ../hg.pid
$ cat ../hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/?style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file/tip/?style=raw'
200 Script output follows
@@ -200,7 +205,7 @@
-rw-r--r-- 9 normal3
- $ "$TESTDIR/get-with-headers.py" 127.0.0.1:$HGPORT 'file/tip/sub/?style=raw'
+ $ get-with-headers.py 127.0.0.1:$HGPORT 'file/tip/sub/?style=raw'
200 Script output follows
@@ -208,7 +213,7 @@
-rw-r--r-- 9 normal4
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
#endif
Test archiving the various revisions. These hit corner cases known with
@@ -999,6 +1004,7 @@
branch: default
commit: (clean)
update: 7 new changesets (update)
+ phases: 8 draft
$ rm "${USERCACHE}"/*
$ hg clone --all-largefiles -u 1 a a-clone1
@@ -1021,6 +1027,7 @@
branch: default
commit: (clean)
update: 6 new changesets (update)
+ phases: 8 draft
$ rm "${USERCACHE}"/*
$ hg clone --all-largefiles -U a a-clone-u
@@ -1030,6 +1037,7 @@
branch: default
commit: (clean)
update: 8 new changesets (update)
+ phases: 8 draft
Show computed destination directory:
@@ -1094,18 +1102,18 @@
searching for changes
all local heads known remotely
6 changesets found
+ uncompressed size of bundle content:
+ 1333 (changelog)
+ 1599 (manifests)
+ 254 .hglf/large1
+ 564 .hglf/large3
+ 572 .hglf/sub/large4
+ 182 .hglf/sub2/large6
+ 182 .hglf/sub2/large7
+ 212 normal1
+ 457 normal3
+ 465 sub/normal4
adding changesets
- uncompressed size of bundle content:
- 1213 (changelog)
- 1479 (manifests)
- 234 .hglf/large1
- 504 .hglf/large3
- 512 .hglf/sub/large4
- 162 .hglf/sub2/large6
- 162 .hglf/sub2/large7
- 192 normal1
- 397 normal3
- 405 sub/normal4
adding manifests
adding file changes
added 6 changesets with 16 changes to 8 files
--- a/tests/test-lfconvert.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-lfconvert.t Mon Jun 15 13:31:22 2015 -0500
@@ -89,7 +89,7 @@
normal
$ cat sub/normal2
alsonormal
- $ "$TESTDIR/md5sum.py" large sub/maybelarge.dat
+ $ md5sum.py large sub/maybelarge.dat
ec87a838931d4d5d2e94a04644788a55 large
1276481102f218c981e0324180bafd9f sub/maybelarge.dat
@@ -115,7 +115,7 @@
$ echo blah >> normal3
$ echo blah >> sub/normal2
$ echo blah >> sub/maybelarge.dat
- $ "$TESTDIR/md5sum.py" sub/maybelarge.dat
+ $ md5sum.py sub/maybelarge.dat
1dd0b99ff80e19cff409702a1d3f5e15 sub/maybelarge.dat
$ hg commit -A -m"add normal3, modify sub/*"
adding normal3
@@ -193,7 +193,7 @@
$ cat stuff/normal2
alsonormal
blah
- $ "$TESTDIR/md5sum.py" stuff/maybelarge.dat
+ $ md5sum.py stuff/maybelarge.dat
1dd0b99ff80e19cff409702a1d3f5e15 stuff/maybelarge.dat
$ cat .hglf/stuff/maybelarge.dat
76236b6a2c6102826c61af4297dd738fb3b1de38
@@ -226,6 +226,7 @@
$ hg commit -m "add anotherlarge (should be a largefile)"
$ cat .hglf/anotherlarge
3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3
+ $ hg tag mytag
$ cd ..
round-trip: converting back to a normal (non-largefiles) repo with
@@ -233,25 +234,30 @@
$ cd largefiles-repo
$ hg lfconvert --to-normal . ../normal-repo
initializing destination ../normal-repo
+ 0 additional largefiles cached
+ scanning source...
+ sorting...
+ converting...
+ 7 add large, normal1
+ 6 add sub/*
+ 5 rename sub/ to stuff/
+ 4 add normal3, modify sub/*
+ 3 remove large, normal3
+ 2 merge
+ 1 add anotherlarge (should be a largefile)
+ 0 Added tag mytag for changeset abacddda7028
$ cd ../normal-repo
$ cat >> .hg/hgrc <<EOF
> [extensions]
> largefiles = !
> EOF
-# Hmmm: the changeset ID for rev 5 is different from the original
-# normal repo (../bigfile-repo), because the changelog filelist
-# differs between the two incarnations of rev 5: this repo includes
-# 'large' in the list, but ../bigfile-repo does not. Since rev 5
-# removes 'large' relative to the first parent in both repos, it seems
-# to me that lfconvert is doing a *better* job than
-# "hg remove" + "hg merge" + "hg commit".
-# $ hg -R ../bigfile-repo debugdata -c 5
-# $ hg debugdata -c 5
$ hg log -G --template "{rev}:{node|short} {desc|firstline}\n"
- o 6:1635824e6f59 add anotherlarge (should be a largefile)
+ o 7:b5fedc110b9d Added tag mytag for changeset 867ab992ecf4
|
- o 5:7215f8deeaaf merge
+ o 6:867ab992ecf4 add anotherlarge (should be a largefile)
+ |
+ o 5:4884f215abda merge
|\
| o 4:7285f817b77e remove large, normal3
| |
@@ -264,8 +270,9 @@
o 0:117b8328f97a add large, normal1
$ hg update
- 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg locate
+ .hgtags
anotherlarge
normal1
stuff/maybelarge.dat
@@ -284,15 +291,18 @@
scanning source...
sorting...
converting...
- 6 add large, normal1
- 5 add sub/*
- 4 rename sub/ to stuff/
- 3 add normal3, modify sub/*
- 2 remove large, normal3
- 1 merge
- 0 add anotherlarge (should be a largefile)
+ 7 add large, normal1
+ 6 add sub/*
+ 5 rename sub/ to stuff/
+ 4 add normal3, modify sub/*
+ 3 remove large, normal3
+ 2 merge
+ 1 add anotherlarge (should be a largefile)
+ 0 Added tag mytag for changeset abacddda7028
$ hg -R largefiles-repo-hg log -G --template "{rev}:{node|short} {desc|firstline}\n"
+ o 7:2f08f66459b7 Added tag mytag for changeset 17126745edfd
+ |
o 6:17126745edfd add anotherlarge (should be a largefile)
|
o 5:9cc5aa7204f0 merge
@@ -310,12 +320,20 @@
Verify will fail (for now) if the usercache is purged before converting, since
largefiles are not cached in the converted repo's local store by the conversion
process.
+ $ cd largefiles-repo-hg
+ $ cat >> .hg/hgrc <<EOF
+ > [experimental]
+ > evolution=createmarkers
+ > EOF
+ $ hg debugobsolete `hg log -r tip -T "{node}"`
+ $ cd ..
+
$ hg -R largefiles-repo-hg verify --large --lfa
checking changesets
checking manifests
crosschecking files in changesets and manifests
checking files
- 8 files, 7 changesets, 12 total revisions
+ 9 files, 8 changesets, 13 total revisions
searching 7 changesets for largefiles
changeset 0:d4892ec57ce2: large references missing $TESTTMP/largefiles-repo-hg/.hg/largefiles/2e000fa7e85759c7f4c254d4d9c33ef481e459a7 (glob)
changeset 1:334e5237836d: sub/maybelarge.dat references missing $TESTTMP/largefiles-repo-hg/.hg/largefiles/34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c (glob)
@@ -336,6 +354,18 @@
$ rm -f "${USERCACHE}"/*
$ hg lfconvert --to-normal issue3519 normalized3519
initializing destination normalized3519
+ 4 additional largefiles cached
+ scanning source...
+ sorting...
+ converting...
+ 7 add large, normal1
+ 6 add sub/*
+ 5 rename sub/ to stuff/
+ 4 add normal3, modify sub/*
+ 3 remove large, normal3
+ 2 merge
+ 1 add anotherlarge (should be a largefile)
+ 0 Added tag mytag for changeset abacddda7028
Ensure the abort message is useful if a largefile is entirely unavailable
$ rm -rf normalized3519
@@ -344,8 +374,20 @@
$ rm largefiles-repo/.hg/largefiles/*
$ hg lfconvert --to-normal issue3519 normalized3519
initializing destination normalized3519
+ anotherlarge: largefile 3b71f43ff30f4b15b5cd85dd9e95ebc7e84eb5a3 not available from file:/*/$TESTTMP/largefiles-repo (glob)
+ stuff/maybelarge.dat: largefile 76236b6a2c6102826c61af4297dd738fb3b1de38 not available from file:/*/$TESTTMP/largefiles-repo (glob)
+ stuff/maybelarge.dat: largefile 76236b6a2c6102826c61af4297dd738fb3b1de38 not available from file:/*/$TESTTMP/largefiles-repo (glob)
+ sub/maybelarge.dat: largefile 76236b6a2c6102826c61af4297dd738fb3b1de38 not available from file:/*/$TESTTMP/largefiles-repo (glob)
large: largefile 2e000fa7e85759c7f4c254d4d9c33ef481e459a7 not available from file:/*/$TESTTMP/largefiles-repo (glob)
- abort: missing largefile 'large' from revision d4892ec57ce212905215fad1d9018f56b99202ad
+ sub/maybelarge.dat: largefile 76236b6a2c6102826c61af4297dd738fb3b1de38 not available from file:/*/$TESTTMP/largefiles-repo (glob)
+ large: largefile 2e000fa7e85759c7f4c254d4d9c33ef481e459a7 not available from file:/*/$TESTTMP/largefiles-repo (glob)
+ stuff/maybelarge.dat: largefile 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c not available from file:/*/$TESTTMP/largefiles-repo (glob)
+ large: largefile 2e000fa7e85759c7f4c254d4d9c33ef481e459a7 not available from file:/*/$TESTTMP/largefiles-repo (glob)
+ sub/maybelarge.dat: largefile 34e163be8e43c5631d8b92e9c43ab0bf0fa62b9c not available from file:/*/$TESTTMP/largefiles-repo (glob)
+ large: largefile 2e000fa7e85759c7f4c254d4d9c33ef481e459a7 not available from file:/*/$TESTTMP/largefiles-repo (glob)
+ 0 additional largefiles cached
+ 11 largefiles failed to download
+ abort: all largefiles must be present locally
[255]
--- a/tests/test-log.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-log.t Mon Jun 15 13:31:22 2015 -0500
@@ -148,7 +148,7 @@
$ hg log -f -l1 --style something
abort: style 'something' not found
- (available styles: bisect, changelog, compact, default, phases, xml)
+ (available styles: bisect, changelog, compact, default, phases, status, xml)
[255]
-f, phases style
--- a/tests/test-manifestv2.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-manifestv2.t Mon Jun 15 13:31:22 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-merge-commit.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-merge-commit.t Mon Jun 15 13:31:22 2015 -0500
@@ -73,7 +73,6 @@
ancestor: 0f2ff26688b9, local: 2263c1be0967+, remote: 0555950ead28
preserving bar for resolve of bar
bar: versions differ -> m
- updating: bar 1/1 files (100.00%)
picked tool 'internal:merge' for bar (binary False symlink False)
merging bar
my bar@2263c1be0967+ other bar@0555950ead28 ancestor bar@0f2ff26688b9
@@ -160,7 +159,6 @@
ancestor: 0f2ff26688b9, local: 2263c1be0967+, remote: 3ffa6b9e35f0
preserving bar for resolve of bar
bar: versions differ -> m
- updating: bar 1/1 files (100.00%)
picked tool 'internal:merge' for bar (binary False symlink False)
merging bar
my bar@2263c1be0967+ other bar@3ffa6b9e35f0 ancestor bar@0f2ff26688b9
--- a/tests/test-merge-criss-cross.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-merge-criss-cross.t Mon Jun 15 13:31:22 2015 -0500
@@ -82,9 +82,7 @@
preserving f2 for resolve of f2
f1: remote is newer -> g
getting f1
- updating: f1 1/2 files (50.00%)
f2: versions differ -> m
- updating: f2 2/2 files (100.00%)
picked tool 'internal:dump' for f2 (binary False symlink False)
merging f2
my f2@3b08d01b0ab5+ other f2@adfe50279922 ancestor f2@40494bf2444c
@@ -151,7 +149,6 @@
f1: remote is newer -> g
getting f1
- updating: f1 1/1 files (100.00%)
f2: remote unchanged -> k
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
@@ -194,7 +191,6 @@
f2: remote is newer -> g
getting f2
- updating: f2 1/1 files (100.00%)
f1: remote unchanged -> k
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
@@ -259,7 +255,6 @@
f1: remote is newer -> g
getting f1
- updating: f1 1/1 files (100.00%)
f2: remote unchanged -> k
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
--- a/tests/test-merge-types.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-merge-types.t Mon Jun 15 13:31:22 2015 -0500
@@ -36,7 +36,6 @@
ancestor: c334dc3be0da, local: 521a1e40188f+, remote: 3574f3e69b1c
preserving a for resolve of a
a: versions differ -> m
- updating: a 1/1 files (100.00%)
picked tool 'internal:merge' for a (binary False symlink True)
merging a
my a@521a1e40188f+ other a@3574f3e69b1c ancestor a@c334dc3be0da
@@ -70,7 +69,6 @@
ancestor: c334dc3be0da, local: 3574f3e69b1c+, remote: 521a1e40188f
preserving a for resolve of a
a: versions differ -> m
- updating: a 1/1 files (100.00%)
picked tool 'internal:merge' for a (binary False symlink True)
merging a
my a@3574f3e69b1c+ other a@521a1e40188f ancestor a@c334dc3be0da
@@ -104,7 +102,6 @@
ancestor: c334dc3be0da, local: c334dc3be0da+, remote: 521a1e40188f
preserving a for resolve of a
a: versions differ -> m
- updating: a 1/1 files (100.00%)
(couldn't find merge tool hgmerge|tool hgmerge can't handle symlinks) (re)
picked tool ':prompt' for a (binary False symlink True)
no tool found to merge a
--- a/tests/test-merge1.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-merge1.t Mon Jun 15 13:31:22 2015 -0500
@@ -40,6 +40,7 @@
branch: default
commit: (interrupted update)
update: 1 new changesets (update)
+ phases: 2 draft
$ rmdir b
$ hg up
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
@@ -49,6 +50,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 2 draft
Prepare a basic merge
--- a/tests/test-merge7.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-merge7.t Mon Jun 15 13:31:22 2015 -0500
@@ -86,7 +86,6 @@
ancestor: 96b70246a118, local: 50c3a7e29886+, remote: 40d11a4173a8
preserving test.txt for resolve of test.txt
test.txt: versions differ -> m
- updating: test.txt 1/1 files (100.00%)
picked tool 'internal:merge' for test.txt (binary False symlink False)
merging test.txt
my test.txt@50c3a7e29886+ other test.txt@40d11a4173a8 ancestor test.txt@96b70246a118
--- a/tests/test-module-imports.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-module-imports.t Mon Jun 15 13:31:22 2015 -0500
@@ -1,9 +1,5 @@
#require test-repo
-This code uses the ast module, which was new in 2.6, so we'll skip
-this test on anything earlier.
- $ $PYTHON -c 'import sys ; assert sys.version_info >= (2, 6)' || exit 80
-
$ import_checker="$TESTDIR"/../contrib/import-checker.py
Run the doctests from the import checker, and make sure
@@ -20,10 +16,7 @@
hidden by deduplication algorithm in the cycle detector, so fixing
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
+ $ hg locate 'mercurial/**.py' 'hgext/**.py' | sed 's-\\-/-g' | python "$import_checker" -
mercurial/dispatch.py mixed imports
stdlib: commands
relative: error, extensions, fancyopts, hg, hook, util
@@ -38,5 +31,7 @@
relative: config, error, templatefilters, templatekw, util
mercurial/ui.py mixed imports
stdlib: formatter
- relative: config, error, scmutil, util
+ relative: config, error, progress, scmutil, util
Import cycle: mercurial.cmdutil -> mercurial.context -> mercurial.subrepo -> mercurial.cmdutil
+ Import cycle: hgext.largefiles.basestore -> hgext.largefiles.localstore -> hgext.largefiles.basestore
+ Import cycle: mercurial.commands -> mercurial.commandserver -> mercurial.dispatch -> mercurial.commands
--- a/tests/test-mq-qclone-http.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-mq-qclone-http.t Mon Jun 15 13:31:22 2015 -0500
@@ -34,7 +34,7 @@
$ hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf collections.conf \
> -A access-paths.log -E error-paths-1.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '?style=raw'
+ $ get-with-headers.py localhost:$HGPORT '?style=raw'
200 Script output follows
@@ -73,7 +73,7 @@
$ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf collections1.conf \
> -A access-paths.log -E error-paths-1.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '?style=raw'
+ $ get-with-headers.py localhost:$HGPORT1 '?style=raw'
200 Script output follows
@@ -112,7 +112,7 @@
$ hg serve -p $HGPORT2 -d --pid-file=hg.pid --webdir-conf collections2.conf \
> -A access-paths.log -E error-paths-1.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '?style=raw'
+ $ get-with-headers.py localhost:$HGPORT2 '?style=raw'
200 Script output follows
@@ -152,5 +152,5 @@
$ hg --cwd d log --mq --template '{rev} {desc|firstline}\n'
0 b.patch
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
--- a/tests/test-mq-qimport.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-mq-qimport.t Mon Jun 15 13:31:22 2015 -0500
@@ -289,4 +289,4 @@
$ cd ..
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
--- a/tests/test-mq-qnew.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-mq-qnew.t Mon Jun 15 13:31:22 2015 -0500
@@ -21,6 +21,7 @@
> hg qnew .mqfoo
> hg qnew 'foo#bar'
> hg qnew 'foo:bar'
+ > hg qnew "`echo foo; echo bar`"
>
> hg qinit -c
>
@@ -108,8 +109,9 @@
abort: ".." cannot be used as the name of a patch
abort: patch name cannot begin with ".hg"
abort: patch name cannot begin with ".mq"
- abort: "#" cannot be used in the name of a patch
- abort: ":" cannot be used in the name of a patch
+ abort: '#' cannot be used in the name of a patch
+ abort: ':' cannot be used in the name of a patch
+ abort: '\n' cannot be used in the name of a patch
% qnew with name containing slash
abort: path ends in directory separator: foo/ (glob)
abort: "foo" already exists as a directory
@@ -176,8 +178,9 @@
abort: ".." cannot be used as the name of a patch
abort: patch name cannot begin with ".hg"
abort: patch name cannot begin with ".mq"
- abort: "#" cannot be used in the name of a patch
- abort: ":" cannot be used in the name of a patch
+ abort: '#' cannot be used in the name of a patch
+ abort: ':' cannot be used in the name of a patch
+ abort: '\n' cannot be used in the name of a patch
% qnew with name containing slash
abort: path ends in directory separator: foo/ (glob)
abort: "foo" already exists as a directory
--- a/tests/test-mq-qpush-fail.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-mq-qpush-fail.t Mon Jun 15 13:31:22 2015 -0500
@@ -34,7 +34,23 @@
$ $PYTHON -c 'print "\xe9"' > message
$ cat .hg/patches/bad-patch >> message
$ mv message .hg/patches/bad-patch
- $ hg qpush -a && echo 'qpush succeeded?!'
+ $ cat > $TESTTMP/wrapplayback.py <<EOF
+ > import os
+ > from mercurial import extensions, transaction
+ > def wrapplayback(orig,
+ > journal, report, opener, vfsmap, entries, backupentries,
+ > unlink=True):
+ > orig(journal, report, opener, vfsmap, entries, backupentries, unlink)
+ > # Touching files truncated at "transaction.abort" causes
+ > # forcible re-loading invalidated filecache properties
+ > # (including repo.changelog)
+ > for f, o, _ignore in entries:
+ > if o or not unlink:
+ > os.utime(opener.join(f), (0.0, 0.0))
+ > def extsetup(ui):
+ > extensions.wrapfunction(transaction, '_playback', wrapplayback)
+ > EOF
+ $ hg qpush -a --config extensions.wrapplayback=$TESTTMP/wrapplayback.py && echo 'qpush succeeded?!'
applying patch1
applying patch2
applying bad-patch
--- a/tests/test-mq-safety.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-mq-safety.t Mon Jun 15 13:31:22 2015 -0500
@@ -25,17 +25,17 @@
$ hg phase --public qbase
$ echo babar >> foo
$ hg qref
- abort: cannot refresh immutable revision
+ abort: cannot refresh public revision
(see "hg help phases" for details)
[255]
$ hg revert -a
reverting foo
$ hg qpop
- abort: popping would remove an immutable revision
+ abort: popping would remove a public revision
(see "hg help phases" for details)
[255]
$ hg qfold bar
- abort: cannot refresh immutable revision
+ abort: cannot refresh public revision
(see "hg help phases" for details)
[255]
$ hg revert -a
--- a/tests/test-mq-subrepo.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-mq-subrepo.t Mon Jun 15 13:31:22 2015 -0500
@@ -106,6 +106,7 @@
[255]
% update substate when adding .hgsub w/clean updated subrepo
A .hgsub
+ A sub/a
% qnew -X path:no-effect -m0 0.diff
path sub
source sub
@@ -121,6 +122,7 @@
[255]
% update substate when modifying .hgsub w/clean updated subrepo
M .hgsub
+ A sub2/a
% qnew --cwd .. -R repo-2499-qnew -X path:no-effect -m1 1.diff
path sub
source sub
@@ -165,6 +167,7 @@
[255]
% update substate when adding .hgsub w/clean updated subrepo
A .hgsub
+ A sub/a
% qrefresh
path sub
source sub
@@ -181,6 +184,7 @@
[255]
% update substate when modifying .hgsub w/clean updated subrepo
M .hgsub
+ A sub2/a
% qrefresh
path sub
source sub
@@ -304,6 +308,7 @@
[255]
% update substate when adding .hgsub w/clean updated subrepo
A .hgsub
+ A sub/a
% qrecord --config ui.interactive=1 -m0 0.diff
diff --git a/.hgsub b/.hgsub
new file mode 100644
@@ -339,6 +344,7 @@
[255]
% update substate when modifying .hgsub w/clean updated subrepo
M .hgsub
+ A sub2/a
% qrecord --config ui.interactive=1 -m1 1.diff
diff --git a/.hgsub b/.hgsub
1 hunks, 1 lines changed
--- a/tests/test-mq-symlinks.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-mq-symlinks.t Mon Jun 15 13:31:22 2015 -0500
@@ -11,7 +11,7 @@
$ echo ccc > c
$ hg add a b c
$ hg qrefresh
- $ "$TESTDIR/readlink.py" a
+ $ readlink.py a
a -> a not a symlink
@@ -21,7 +21,7 @@
$ rm a
$ ln -s b a
$ hg qrefresh --git
- $ "$TESTDIR/readlink.py" a
+ $ readlink.py a
a -> b
$ hg qpop
@@ -30,7 +30,7 @@
$ hg qpush
applying symlink.patch
now at: symlink.patch
- $ "$TESTDIR/readlink.py" a
+ $ readlink.py a
a -> b
@@ -39,7 +39,7 @@
$ rm a
$ ln -s c a
$ hg qnew --git -f updatelink
- $ "$TESTDIR/readlink.py" a
+ $ readlink.py a
a -> c
$ hg qpop
popping updatelink
@@ -52,7 +52,7 @@
committing manifest
committing changelog
now at: updatelink
- $ "$TESTDIR/readlink.py" a
+ $ readlink.py a
a -> c
$ hg st
@@ -107,5 +107,5 @@
$ hg qpush
applying movelink
now at: movelink
- $ "$TESTDIR/readlink.py" linkb
+ $ readlink.py linkb
linkb -> linkb
--- a/tests/test-newbranch.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-newbranch.t Mon Jun 15 13:31:22 2015 -0500
@@ -25,7 +25,6 @@
$ hg ci -m "add branch name"
$ hg branch bar
marked working directory as branch bar
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -m "change branch name"
Branch shadowing:
@@ -37,7 +36,6 @@
$ hg branch -f default
marked working directory as branch default
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -m "clear branch name"
created new head
@@ -67,11 +65,9 @@
$ hg branch -f bar
marked working directory as branch bar
- (branches are permanent and global, did you want a bookmark?)
$ hg branch foo
marked working directory as branch foo
- (branches are permanent and global, did you want a bookmark?)
$ echo bleah > a
$ hg ci -m "modify a branch"
@@ -94,13 +90,11 @@
$ hg branch default
marked working directory as branch default
- (branches are permanent and global, did you want a bookmark?)
set (first) parent branch as branch name
$ hg branch foo
marked working directory as branch foo
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -m "merge"
@@ -215,7 +209,6 @@
$ hg branch foobar
marked working directory as branch foobar
- (branches are permanent and global, did you want a bookmark?)
$ hg up
abort: branch foobar not found
@@ -225,7 +218,6 @@
$ hg branch ff
marked working directory as branch ff
- (branches are permanent and global, did you want a bookmark?)
$ echo ff > ff
$ hg ci -Am'fast forward'
--- a/tests/test-obsolete.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-obsolete.t Mon Jun 15 13:31:22 2015 -0500
@@ -4,6 +4,10 @@
> publish=false
> [ui]
> logtemplate="{rev}:{node|short} ({phase}) [{tags} {bookmarks}] {desc|firstline}\n"
+ > [experimental]
+ > # drop me once bundle2 is the default,
+ > # added to get test change early.
+ > bundle2-exp = True
> EOF
$ mkcommit() {
> echo "$1" > "$1"
@@ -164,6 +168,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 3 draft
remote: 3 outgoing
$ hg summary --remote --hidden
@@ -172,6 +177,7 @@
branch: default
commit: (clean)
update: 3 new changesets, 4 branch heads (merge)
+ phases: 6 draft
remote: 3 outgoing
check that various commands work well with filtering
@@ -305,34 +311,35 @@
adding manifests
adding file changes
added 4 changesets with 4 changes to 4 files (+1 heads)
+ 5 new obsolescence markers
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg debugobsolete
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
- cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
+ 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
- 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
- 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
Rollback//Transaction support
$ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
$ hg debugobsolete
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
- cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
+ 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
- 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
- 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 (Thu Jan 01 00:22:20 1970 +0000) {'user': 'test'}
$ hg rollback -n
repository tip rolled back to revision 3 (undo debugobsolete)
$ hg rollback
repository tip rolled back to revision 3 (undo debugobsolete)
$ hg debugobsolete
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
- cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
+ 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
- 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
- 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
$ cd ..
@@ -346,6 +353,7 @@
adding manifests
adding file changes
added 4 changesets with 4 changes to 4 files (+1 heads)
+ 5 new obsolescence markers
$ hg -R tmpd debugobsolete | sort
1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
@@ -408,14 +416,15 @@
adding manifests
adding file changes
added 4 changesets with 4 changes to 4 files (+1 heads)
+ 5 new obsolescence markers
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg debugobsolete
1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
- cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
+ 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
- 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
- 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
On push
@@ -424,13 +433,14 @@
pushing to ../tmpc
searching for changes
no changes found
+ 1 new obsolescence markers
[1]
$ hg -R ../tmpc debugobsolete
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
- cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
+ 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
- 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
- 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
detect outgoing obsolete and unstable
@@ -506,6 +516,7 @@
adding manifests
adding file changes
added 6 changesets with 6 changes to 6 files (+1 heads)
+ 7 new obsolescence markers
no warning displayed
@@ -545,6 +556,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
+ 1 new obsolescence markers
test relevance computation
---------------------------------------
@@ -574,11 +586,11 @@
$ hg debugobsolete
1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
+ 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
- cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
+ 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
- 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
- 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
+ cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob)
@@ -646,37 +658,37 @@
check changelog view
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'shortlog/'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'shortlog/'
200 Script output follows
check graph view
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'graph'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'graph'
200 Script output follows
check filelog view
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar'
200 Script output follows
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/68'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/68'
200 Script output follows
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
404 Not Found
[1]
check that web.view config option:
- $ "$TESTDIR/killdaemons.py" hg.pid
+ $ killdaemons.py hg.pid
$ cat >> .hg/hgrc << EOF
> [web]
> view=all
> EOF
$ wait
$ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
200 Script output follows
- $ "$TESTDIR/killdaemons.py" hg.pid
+ $ killdaemons.py hg.pid
Checking _enable=False warning if obsolete marker exists
@@ -744,7 +756,7 @@
no changes found
[1]
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
#endif
@@ -762,6 +774,7 @@
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
+ 2 new obsolescence markers
$ hg out ../repo-issue3814
comparing with ../repo-issue3814
searching for changes
@@ -872,15 +885,84 @@
$ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/1'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/1'
404 Not Found
[1]
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'file/tip/bar'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'file/tip/bar'
200 Script output follows
- $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'annotate/tip/bar'
+ $ get-with-headers.py --headeronly localhost:$HGPORT 'annotate/tip/bar'
200 Script output follows
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
#endif
+Test heads computation on pending index changes with obsolescence markers
+ $ cd ..
+ $ cat >$TESTTMP/test_extension.py << EOF
+ > from mercurial import cmdutil
+ > from mercurial.i18n import _
+ >
+ > cmdtable = {}
+ > command = cmdutil.command(cmdtable)
+ > @command("amendtransient",[], _('hg amendtransient [rev]'))
+ > def amend(ui, repo, *pats, **opts):
+ > def commitfunc(ui, repo, message, match, opts):
+ > return repo.commit(message, repo['.'].user(), repo['.'].date(), match)
+ > opts['message'] = 'Test'
+ > opts['logfile'] = None
+ > cmdutil.amend(ui, repo, commitfunc, repo['.'], {}, pats, opts)
+ > print repo.changelog.headrevs()
+ > EOF
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > testextension=$TESTTMP/test_extension.py
+ > EOF
+ $ hg init repo-issue-nativerevs-pending-changes
+ $ cd repo-issue-nativerevs-pending-changes
+ $ mkcommit a
+ $ mkcommit b
+ $ hg up ".^"
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo aa > a
+ $ hg amendtransient
+ [1, 3]
+
+Test cache consistency for the visible filter
+1) We want to make sure that the cached filtered revs are invalidated when
+bookmarks change
+ $ cd ..
+ $ cat >$TESTTMP/test_extension.py << EOF
+ > from mercurial import cmdutil, extensions, bookmarks, repoview
+ > def _bookmarkchanged(orig, bkmstoreinst, *args, **kwargs):
+ > repo = bkmstoreinst._repo
+ > ret = orig(bkmstoreinst, *args, **kwargs)
+ > hidden1 = repoview.computehidden(repo)
+ > hidden = repoview.filterrevs(repo, 'visible')
+ > if sorted(hidden1) != sorted(hidden):
+ > print "cache inconsistency"
+ > return ret
+ > def extsetup(ui):
+ > extensions.wrapfunction(bookmarks.bmstore, 'write', _bookmarkchanged)
+ > EOF
+
+ $ hg init repo-cache-inconsistency
+ $ cd repo-issue-nativerevs-pending-changes
+ $ mkcommit a
+ a already tracked!
+ $ mkcommit b
+ $ hg id
+ 13bedc178fce tip
+ $ echo "hello" > b
+ $ hg commit --amend -m "message"
+ $ hg book bookb -r 13bedc178fce --hidden
+ $ hg log -r 13bedc178fce
+ 5:13bedc178fce (draft) [ bookb] add b
+ $ hg book -d bookb
+ $ hg log -r 13bedc178fce
+ abort: hidden revision '13bedc178fce'!
+ (use --hidden to access hidden revisions)
+ [255]
+
+
+
--- a/tests/test-patchbomb.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-patchbomb.t Mon Jun 15 13:31:22 2015 -0500
@@ -289,18 +289,11 @@
\r (no-eol) (esc)
sending [ ] 0/3\r (no-eol) (esc)
- sending [ ] 0/3\r (no-eol) (esc)
- \r (no-eol) (esc)
- \r (no-eol) (esc)
\r (no-eol) (esc)
\r (no-eol) (esc)
sending [==============> ] 1/3\r (no-eol) (esc)
- sending [==============> ] 1/3\r (no-eol) (esc)
\r (no-eol) (esc)
\r (no-eol) (esc)
- \r (no-eol) (esc)
- \r (no-eol) (esc)
- sending [=============================> ] 2/3\r (no-eol) (esc)
sending [=============================> ] 2/3\r (no-eol) (esc)
\r (esc)
sending [PATCH 0 of 2] test ...
--- a/tests/test-phases-exchange.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-phases-exchange.t Mon Jun 15 13:31:22 2015 -0500
@@ -1,5 +1,12 @@
#require killdaemons
+ $ cat << EOF >> $HGRCPATH
+ > [experimental]
+ > # drop me once bundle2 is the default,
+ > # added to get test change early.
+ > bundle2-exp = True
+ > EOF
+
$ hgph() { hg log -G --template "{rev} {phase} {desc} - {node|short}\n" $*; }
$ mkcommit() {
@@ -765,9 +772,9 @@
searching for changes
1 changesets found
uncompressed size of bundle content:
- 172 (changelog)
- 145 (manifests)
- 111 a-H
+ 192 (changelog)
+ 165 (manifests)
+ 131 a-H
adding changesets
adding manifests
adding file changes
@@ -1041,7 +1048,16 @@
$ cat ../beta.pid >> $DAEMON_PIDS
$ cd ../gamma
- $ hg pull http://localhost:$HGPORT/
+ $ hg pull http://localhost:$HGPORT/ --config experimental.bundle2-exp=True
+ pulling from http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ $ hg phase f54f1bb90ff3
+ 2: draft
+
+enforce bundle1
+
+ $ hg pull http://localhost:$HGPORT/ --config experimental.bundle2-exp=False
pulling from http://localhost:$HGPORT/
searching for changes
no changes found
@@ -1177,6 +1193,6 @@
$ cd ..
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
#endif
--- a/tests/test-phases.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-phases.t Mon Jun 15 13:31:22 2015 -0500
@@ -36,6 +36,8 @@
Draft commit are properly created over public one:
$ hg phase --public .
+ $ hg phase
+ 1: public
$ hglog
1 0 B
0 0 A
@@ -86,6 +88,9 @@
$ hg merge 4 # E
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
+ $ hg phase
+ 6: draft
+ 4: secret
$ hg ci -m "merge B' and E"
$ hglog
7 2 merge B' and E
@@ -242,6 +247,24 @@
1 0 B
0 0 A
+Test summary
+
+ $ hg summary -R clone-dest --verbose
+ parent: -1:000000000000 (no revision checked out)
+ branch: default
+ commit: (clean)
+ update: 5 new changesets (update)
+ $ hg summary -R initialrepo
+ parent: 7:17a481b3bccb tip
+ merge B' and E
+ branch: default
+ commit: (clean) (secret)
+ update: 1 new changesets, 2 branch heads (merge)
+ phases: 3 draft, 3 secret
+ $ hg summary -R initialrepo --quiet
+ parent: 7:17a481b3bccb tip
+ update: 1 new changesets, 2 branch heads (merge)
+
Test revset
$ cd initialrepo
--- a/tests/test-pull-branch.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-pull-branch.t Mon Jun 15 13:31:22 2015 -0500
@@ -33,7 +33,6 @@
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg branch branchB
marked working directory as branch branchB
- (branches are permanent and global, did you want a bookmark?)
$ echo b1 > foo
$ hg ci -mb1 # 3
@@ -141,7 +140,6 @@
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg branch branchC
marked working directory as branch branchC
- (branches are permanent and global, did you want a bookmark?)
$ echo b1 > bar
$ hg ci -Am "commit on branchC on tt"
adding bar
--- a/tests/test-pull-http.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-pull-http.t Mon Jun 15 13:31:22 2015 -0500
@@ -40,7 +40,7 @@
[ui]
# name and email (local to this repository, optional), e.g.
# username = Jane Doe <jdoe@example.com>
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
expect error, cloning not allowed
@@ -48,10 +48,14 @@
$ echo 'allowpull = false' >> .hg/hgrc
$ hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
$ cat hg.pid >> $DAEMON_PIDS
- $ hg clone http://localhost:$HGPORT/ test4
+ $ hg clone http://localhost:$HGPORT/ test4 --config experimental.bundle2-exp=True
+ requesting all changes
abort: authorization failed
[255]
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ hg clone http://localhost:$HGPORT/ test4 --config experimental.bundle2-exp=False
+ abort: authorization failed
+ [255]
+ $ killdaemons.py
serve errors
@@ -60,7 +64,7 @@
> hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
> cat hg.pid >> $DAEMON_PIDS
> hg --cwd ../test pull http://localhost:$HGPORT/
- > "$TESTDIR/killdaemons.py" hg.pid
+ > killdaemons.py hg.pid
> echo % serve errors
> cat errors.log
> }
@@ -69,6 +73,7 @@
$ req
pulling from http://localhost:$HGPORT/
+ searching for changes
abort: authorization failed
% serve errors
--- a/tests/test-push-hook-lock.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-push-hook-lock.t Mon Jun 15 13:31:22 2015 -0500
@@ -26,7 +26,7 @@
$ echo bar >> 3/foo
$ hg --cwd 3 ci -m bar
- $ hg --cwd 3 push ../2
+ $ hg --cwd 3 push ../2 --config experimental.bundle2-exp=False
pushing to ../2
searching for changes
adding changesets
@@ -36,3 +36,15 @@
lock: user *, process * (*s) (glob)
wlock: free
+ $ hg --cwd 1 --config extensions.strip= strip tip -q
+ $ hg --cwd 2 --config extensions.strip= strip tip -q
+ $ hg --cwd 3 push ../2 --config experimental.bundle2-exp=True
+ pushing to ../2
+ searching for changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 1 changesets with 1 changes to 1 files
+ lock: user *, process * (*s) (glob)
+ wlock: user *, process * (*s) (glob)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-push-http-bundle1.t Mon Jun 15 13:31:22 2015 -0500
@@ -0,0 +1,169 @@
+#require killdaemons
+
+This test checks behavior related to bundle1 that changed or is likely
+to change with bundle2. Feel free to factor out any part of the test
+which does not need to exist to keep bundle1 working.
+
+ $ cat << EOF >> $HGRCPATH
+ > [experimental]
+ > # This test is dedicated to interaction through old bundle
+ > bundle2-exp = False
+ > EOF
+
+ $ hg init test
+ $ cd test
+ $ echo a > a
+ $ hg ci -Ama
+ adding a
+ $ cd ..
+ $ hg clone test test2
+ updating to branch default
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd test2
+ $ echo a >> a
+ $ hg ci -mb
+ $ req() {
+ > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
+ > cat hg.pid >> $DAEMON_PIDS
+ > hg --cwd ../test2 push http://localhost:$HGPORT/
+ > exitstatus=$?
+ > killdaemons.py
+ > echo % serve errors
+ > cat errors.log
+ > return $exitstatus
+ > }
+ $ cd ../test
+
+expect ssl error
+
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: HTTP Error 403: ssl required
+ % serve errors
+ [255]
+
+expect authorization error
+
+ $ echo '[web]' > .hg/hgrc
+ $ echo 'push_ssl = false' >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ % serve errors
+ [255]
+
+expect authorization error: must have authorized user
+
+ $ echo 'allow_push = unperson' >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ % serve errors
+ [255]
+
+expect success
+
+ $ echo 'allow_push = *' >> .hg/hgrc
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo "changegroup = printenv.py changegroup 0" >> .hg/hgrc
+ $ echo "pushkey = printenv.py pushkey 0" >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
+ % serve errors
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo serve)
+
+expect success, server lacks the httpheader capability
+
+ $ CAP=httpheader
+ $ . "$TESTDIR/notcapable"
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
+ % serve errors
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo serve)
+
+expect success, server lacks the unbundlehash capability
+
+ $ CAP=unbundlehash
+ $ . "$TESTDIR/notcapable"
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
+ % serve errors
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo serve)
+
+expect push success, phase change failure
+
+ $ cat > .hg/hgrc <<EOF
+ > [web]
+ > push_ssl = false
+ > allow_push = *
+ > [hooks]
+ > prepushkey = printenv.py prepushkey 1
+ > EOF
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ % serve errors
+
+expect phase change success
+
+ $ echo "prepushkey = printenv.py prepushkey 0" >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ no changes found
+ % serve errors
+ [1]
+ $ hg rollback
+ repository tip rolled back to revision 0 (undo serve)
+
+expect authorization error: all users denied
+
+ $ echo '[web]' > .hg/hgrc
+ $ echo 'push_ssl = false' >> .hg/hgrc
+ $ echo 'deny_push = *' >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ % serve errors
+ [255]
+
+expect authorization error: some users denied, users must be authenticated
+
+ $ echo 'deny_push = unperson' >> .hg/hgrc
+ $ req
+ pushing to http://localhost:$HGPORT/
+ searching for changes
+ abort: authorization failed
+ % serve errors
+ [255]
+
+ $ cd ..
--- a/tests/test-push-http.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-push-http.t Mon Jun 15 13:31:22 2015 -0500
@@ -17,7 +17,7 @@
> cat hg.pid >> $DAEMON_PIDS
> hg --cwd ../test2 push http://localhost:$HGPORT/
> exitstatus=$?
- > "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ > killdaemons.py
> echo % serve errors
> cat errors.log
> return $exitstatus
@@ -58,8 +58,8 @@
$ echo 'allow_push = *' >> .hg/hgrc
$ echo '[hooks]' >> .hg/hgrc
- $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup 0" >> .hg/hgrc
- $ echo "pushkey = python \"$TESTDIR/printenv.py\" pushkey 0" >> .hg/hgrc
+ $ echo "changegroup = printenv.py changegroup 0" >> .hg/hgrc
+ $ echo "pushkey = printenv.py pushkey 0" >> .hg/hgrc
$ req
pushing to http://localhost:$HGPORT/
searching for changes
@@ -67,7 +67,8 @@
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
- remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
+ remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
+ remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
% serve errors
$ hg rollback
repository tip rolled back to revision 0 (undo serve)
@@ -83,7 +84,8 @@
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
- remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
+ remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
+ remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
% serve errors
$ hg rollback
repository tip rolled back to revision 0 (undo serve)
@@ -99,7 +101,8 @@
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
- remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
+ remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
+ remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
% serve errors
$ hg rollback
repository tip rolled back to revision 0 (undo serve)
@@ -111,7 +114,7 @@
> push_ssl = false
> allow_push = *
> [hooks]
- > prepushkey = python "$TESTDIR/printenv.py" prepushkey 1
+ > prepushkey = printenv.py prepushkey 1
> EOF
$ req
pushing to http://localhost:$HGPORT/
@@ -120,17 +123,26 @@
remote: adding manifests
remote: adding file changes
remote: added 1 changesets with 1 changes to 1 files
+ remote: prepushkey hook: HG_BUNDLE2=1 HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
+ remote: pushkey-abort: prepushkey hook exited with status 1
+ remote: transaction abort!
+ remote: rollback completed
+ abort: updating ba677d0156c1 to public failed
% serve errors
+ [255]
expect phase change success
- $ echo "prepushkey = python \"$TESTDIR/printenv.py\" prepushkey 0" >> .hg/hgrc
+ $ echo "prepushkey = printenv.py prepushkey 0" >> .hg/hgrc
$ req
pushing to http://localhost:$HGPORT/
searching for changes
- no changes found
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: prepushkey hook: HG_BUNDLE2=1 HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
% serve errors
- [1]
$ hg rollback
repository tip rolled back to revision 0 (undo serve)
--- a/tests/test-push-warn.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-push-warn.t Mon Jun 15 13:31:22 2015 -0500
@@ -1,3 +1,9 @@
+ $ cat << EOF >> $HGRCPATH
+ > [experimental]
+ > # drop me once bundle2 is the default,
+ > # added to get test change early.
+ > bundle2-exp = True
+ > EOF
$ hg init a
$ cd a
$ echo foo > t1
@@ -40,7 +46,6 @@
query 1; heads
searching for changes
taking quick initial sample
- searching: 2 queries
query 2; still undecided: 1, sample size is: 1
2 total queries
listing keys for "phases"
@@ -151,9 +156,9 @@
searching for changes
2 changesets found
uncompressed size of bundle content:
- 308 (changelog)
- 286 (manifests)
- 213 foo
+ 348 (changelog)
+ 326 (manifests)
+ 253 foo
adding changesets
adding manifests
adding file changes
@@ -463,7 +468,6 @@
$ hg -R j ci -m a1
$ hg -R k branch b
marked working directory as branch b
- (branches are permanent and global, did you want a bookmark?)
$ echo b > k/foo
$ hg -R k ci -m b
$ hg -R k up 0
@@ -533,7 +537,6 @@
adding a
$ hg branch B
marked working directory as branch B
- (branches are permanent and global, did you want a bookmark?)
$ echo b >b
$ hg ci -Amb
adding b
@@ -612,7 +615,6 @@
adding a
$ hg branch B
marked working directory as branch B
- (branches are permanent and global, did you want a bookmark?)
$ echo b >b
$ hg ci -Amb
adding b
@@ -704,7 +706,6 @@
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg branch B
marked working directory as branch B
- (branches are permanent and global, did you want a bookmark?)
$ echo b0 >b
$ hg ci -Amb0
adding b
@@ -719,7 +720,6 @@
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg branch -f B
marked working directory as branch B
- (branches are permanent and global, did you want a bookmark?)
$ echo a3 >a
$ hg ci -ma3
created new head
@@ -727,7 +727,6 @@
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg branch -f A
marked working directory as branch A
- (branches are permanent and global, did you want a bookmark?)
$ echo b3 >b
$ hg ci -mb3
created new head
--- a/tests/test-qrecord.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-qrecord.t Mon Jun 15 13:31:22 2015 -0500
@@ -58,8 +58,7 @@
-A --addremove mark new/missing files as added/removed before
committing
- --close-branch mark a branch as closed, hiding it from the branch
- list
+ --close-branch mark a branch head as closed
--amend amend the parent of the working directory
-s --secret use the secret phase for committing
-e --edit invoke editor on commit messages
--- a/tests/test-rebase-abort.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rebase-abort.t Mon Jun 15 13:31:22 2015 -0500
@@ -321,3 +321,4 @@
branch: default
commit: (clean)
update: 1 new changesets, 2 branch heads (merge)
+ phases: 4 draft
--- a/tests/test-rebase-cache.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rebase-cache.t Mon Jun 15 13:31:22 2015 -0500
@@ -31,7 +31,6 @@
$ hg branch branch2
marked working directory as branch branch2
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -m 'branch2'
$ echo c > C
@@ -42,7 +41,6 @@
$ hg branch -f branch2
marked working directory as branch branch2
- (branches are permanent and global, did you want a bookmark?)
$ echo d > d
$ hg ci -Am D
adding d
@@ -57,7 +55,6 @@
$ hg branch branch3
marked working directory as branch branch3
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -m 'branch3'
$ echo f > f
@@ -308,12 +305,10 @@
$ hg branch branch2
marked working directory as branch branch2
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -m 'branch2'
$ hg branch -f branch1
marked working directory as branch branch1
- (branches are permanent and global, did you want a bookmark?)
$ echo a > A
$ hg ci -Am A
--- a/tests/test-rebase-collapse.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rebase-collapse.t Mon Jun 15 13:31:22 2015 -0500
@@ -571,7 +571,6 @@
$ hg branch 'two'
marked working directory as branch two
- (branches are permanent and global, did you want a bookmark?)
$ echo 'c' > c
$ hg ci -Am 'C'
adding c
--- a/tests/test-rebase-conflicts.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rebase-conflicts.t Mon Jun 15 13:31:22 2015 -0500
@@ -223,7 +223,6 @@
ignoring null merge rebase of 6
ignoring null merge rebase of 8
rebasing 9:e31216eec445 "more changes to f1"
- rebasing: 9:e31216eec445 5/6 changesets (83.33%)
future parents are 2 and -1
rebase status stored
update to 2:4bc80088dc6b
@@ -232,10 +231,8 @@
ancestor: d79e2059b5c0+, local: d79e2059b5c0+, remote: 4bc80088dc6b
f2.txt: other deleted -> r
removing f2.txt
- updating: f2.txt 1/2 files (50.00%)
f1.txt: remote created -> g
getting f1.txt
- updating: f1.txt 2/2 files (100.00%)
merge against 9:e31216eec445
detach base 8:8e4e2c1a07ae
searching for copies back to rev 3
@@ -244,14 +241,12 @@
ancestor: 8e4e2c1a07ae, local: 4bc80088dc6b+, remote: e31216eec445
f1.txt: remote is newer -> g
getting f1.txt
- updating: f1.txt 1/1 files (100.00%)
committing files:
f1.txt
committing manifest
committing changelog
rebased as 19c888675e13
rebasing 10:2f2496ddf49d "merge" (tip)
- rebasing: 10:2f2496ddf49d 6/6 changesets (100.00%)
future parents are 11 and 7
rebase status stored
already in target
@@ -263,7 +258,6 @@
ancestor: e31216eec445, local: 19c888675e13+, remote: 2f2496ddf49d
f1.txt: remote is newer -> g
getting f1.txt
- updating: f1.txt 1/1 files (100.00%)
committing files:
f1.txt
committing manifest
@@ -276,50 +270,27 @@
ancestor: 2a7f09cac94c, local: 2a7f09cac94c+, remote: d79e2059b5c0
f1.txt: other deleted -> r
removing f1.txt
- updating: f1.txt 1/2 files (50.00%)
f2.txt: remote created -> g
getting f2.txt
- updating: f2.txt 2/2 files (100.00%)
3 changesets found
list of changesets:
4c9fbe56a16f30c0d5dcc40ec1a97bbe3325209c
e31216eec445e44352c5f01588856059466a24c9
2f2496ddf49d69b5ef23ad8cf9fb2e0e4faf0ac2
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: f1.txt 1/1 files (100.00%)
saved backup bundle to $TESTTMP/issue4041/.hg/strip-backup/e31216eec445-15f7a814-backup.hg (glob)
3 changesets found
list of changesets:
4c9fbe56a16f30c0d5dcc40ec1a97bbe3325209c
19c888675e133ab5dff84516926a65672eaf04d9
2a7f09cac94c7f4b73ebd5cd1a62d3b2e8e336bf
- bundling: 1/3 changesets (33.33%)
- bundling: 2/3 changesets (66.67%)
- bundling: 3/3 changesets (100.00%)
- bundling: 1/3 manifests (33.33%)
- bundling: 2/3 manifests (66.67%)
- bundling: 3/3 manifests (100.00%)
- bundling: f1.txt 1/1 files (100.00%)
adding branch
adding changesets
- changesets: 1 chunks
add changeset 4c9fbe56a16f
- changesets: 2 chunks
add changeset 19c888675e13
- changesets: 3 chunks
add changeset 2a7f09cac94c
adding manifests
- manifests: 1/2 chunks (50.00%)
- manifests: 2/2 chunks (100.00%)
- manifests: 3/2 chunks (150.00%)
adding file changes
adding f1.txt revisions
- files: 1/1 chunks (100.00%)
added 2 changesets with 2 changes to 1 files
invalid branchheads cache (served): tip differs
rebase completed
--- a/tests/test-rebase-interruptions.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rebase-interruptions.t Mon Jun 15 13:31:22 2015 -0500
@@ -258,7 +258,7 @@
Abort the rebasing:
$ hg rebase --abort
- warning: can't clean up immutable changesets 45396c49d53b
+ warning: can't clean up public changesets 45396c49d53b
rebase aborted
$ hg tglogp
--- a/tests/test-rebase-named-branches.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rebase-named-branches.t Mon Jun 15 13:31:22 2015 -0500
@@ -36,7 +36,6 @@
2 files updated, 0 files merged, 3 files removed, 0 files unresolved
$ hg branch dev-two
marked working directory as branch dev-two
- (branches are permanent and global, did you want a bookmark?)
$ echo x > x
@@ -128,7 +127,6 @@
3 files updated, 0 files merged, 3 files removed, 0 files unresolved
$ hg branch dev-one
marked working directory as branch dev-one
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -m 'dev-one named branch'
$ hg tglog
--- a/tests/test-rebase-parameters.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rebase-parameters.t Mon Jun 15 13:31:22 2015 -0500
@@ -476,6 +476,7 @@
branch: default
commit: 1 modified, 1 unresolved (merge)
update: (current)
+ phases: 3 draft
rebase: 0 rebased, 1 remaining (rebase --continue)
$ hg resolve -l
--- a/tests/test-rebase-scenario-global.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rebase-scenario-global.t Mon Jun 15 13:31:22 2015 -0500
@@ -308,7 +308,7 @@
nothing to rebase
[1]
$ hg rebase -d 5 -b 6
- abort: can't rebase immutable changeset e1c4361dd923
+ abort: can't rebase public changeset e1c4361dd923
(see "hg help phases" for details)
[255]
@@ -397,7 +397,7 @@
abort: can't remove original changesets with unrebased descendants
(use --keep to keep original changesets)
[255]
- $ hg rebase -r '2::8' -d 1 --keep
+ $ hg rebase -r '2::8' -d 1 -k
rebasing 2:c9e50f6cdc55 "C"
rebasing 3:ffd453c31098 "D"
rebasing 6:3d8a618087a7 "G"
--- a/tests/test-record.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-record.t Mon Jun 15 13:31:22 2015 -0500
@@ -45,8 +45,7 @@
-A --addremove mark new/missing files as added/removed before
committing
- --close-branch mark a branch as closed, hiding it from the branch
- list
+ --close-branch mark a branch head as closed
--amend amend the parent of the working directory
-s --secret use the secret phase for committing
-e --edit invoke editor on commit messages
--- a/tests/test-relink.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-relink.t Mon Jun 15 13:31:22 2015 -0500
@@ -70,7 +70,7 @@
relink
- $ hg relink --debug | fix_path
+ $ hg relink --debug --config progress.debug=true | fix_path
relinking $TESTTMP/repo/.hg/store to $TESTTMP/clone/.hg/store
tip has 2 files, estimated total number of files: 3
collecting: 00changelog.i 1/3 files (33.33%)
--- a/tests/test-rename-dir-merge.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rename-dir-merge.t Mon Jun 15 13:31:22 2015 -0500
@@ -43,14 +43,11 @@
removing a/a
a/b: other deleted -> r
removing a/b
- updating: a/b 2/5 files (40.00%)
b/a: remote created -> g
getting b/a
b/b: remote created -> g
getting b/b
- updating: b/b 4/5 files (80.00%)
b/c: remote directory rename - move from a/c -> dm
- updating: b/c 5/5 files (100.00%)
moving a/c to b/c (glob)
3 files updated, 0 files merged, 2 files removed, 0 files unresolved
(branch merge, don't forget to commit)
@@ -89,7 +86,6 @@
branchmerge: True, force: False, partial: False
ancestor: f9b20c0d4c51, local: 397f8b00a740+, remote: ce36d17b18fb
b/c: local directory rename - get from a/c -> dg
- updating: b/c 1/1 files (100.00%)
getting a/c to b/c
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
--- a/tests/test-rename-merge1.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rename-merge1.t Mon Jun 15 13:31:22 2015 -0500
@@ -40,9 +40,7 @@
removing a
b2: remote created -> g
getting b2
- updating: b2 1/2 files (50.00%)
b: remote moved from a -> m
- updating: b 2/2 files (100.00%)
picked tool 'internal:merge' for b (binary False symlink False)
merging a and b to b
my b@044f8520aeeb+ other b@85c198ef2f6c ancestor a@af1939970a1c
@@ -181,7 +179,6 @@
ancestor: 19d7f95df299, local: 0084274f6b67+, remote: 5d32493049f0
newfile: remote created -> g
getting newfile
- updating: newfile 1/1 files (100.00%)
note: possible conflict - file was deleted and renamed to:
newfile
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-rename-merge2.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rename-merge2.t Mon Jun 15 13:31:22 2015 -0500
@@ -90,13 +90,11 @@
preserving rev for resolve of rev
a: remote unchanged -> k
b: remote copied from a -> m
- updating: b 1/2 files (50.00%)
picked tool 'python ../merge' for b (binary False symlink False)
merging a and b to b
my b@e300d1c794ec+ other b@4ce40f5aca24 ancestor a@924404dff337
premerge successful
rev: versions differ -> m
- updating: rev 2/2 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@e300d1c794ec+ other rev@4ce40f5aca24 ancestor rev@924404dff337
@@ -128,15 +126,12 @@
preserving rev for resolve of rev
a: remote is newer -> g
getting a
- updating: a 1/3 files (33.33%)
b: local copied/moved from a -> m
- updating: b 2/3 files (66.67%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b and a to b
my b@86a2aa42fc76+ other a@f4db7e329e71 ancestor a@924404dff337
premerge successful
rev: versions differ -> m
- updating: rev 3/3 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@86a2aa42fc76+ other rev@f4db7e329e71 ancestor rev@924404dff337
@@ -168,13 +163,11 @@
preserving rev for resolve of rev
removing a
b: remote moved from a -> m
- updating: b 1/2 files (50.00%)
picked tool 'python ../merge' for b (binary False symlink False)
merging a and b to b
my b@e300d1c794ec+ other b@bdb19105162a ancestor a@924404dff337
premerge successful
rev: versions differ -> m
- updating: rev 2/2 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@e300d1c794ec+ other rev@bdb19105162a ancestor rev@924404dff337
@@ -204,13 +197,11 @@
preserving b for resolve of b
preserving rev for resolve of rev
b: local copied/moved from a -> m
- updating: b 1/2 files (50.00%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b and a to b
my b@02963e448370+ other a@f4db7e329e71 ancestor a@924404dff337
premerge successful
rev: versions differ -> m
- updating: rev 2/2 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@02963e448370+ other rev@f4db7e329e71 ancestor rev@924404dff337
@@ -240,9 +231,7 @@
preserving rev for resolve of rev
b: remote created -> g
getting b
- updating: b 1/2 files (50.00%)
rev: versions differ -> m
- updating: rev 2/2 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@94b33a1b7f2d+ other rev@4ce40f5aca24 ancestor rev@924404dff337
@@ -271,7 +260,6 @@
ancestor: 924404dff337, local: 86a2aa42fc76+, remote: 97c705ade336
preserving rev for resolve of rev
rev: versions differ -> m
- updating: rev 1/1 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@86a2aa42fc76+ other rev@97c705ade336 ancestor rev@924404dff337
@@ -301,12 +289,9 @@
preserving rev for resolve of rev
a: other deleted -> r
removing a
- updating: a 1/3 files (33.33%)
b: remote created -> g
getting b
- updating: b 2/3 files (66.67%)
rev: versions differ -> m
- updating: rev 3/3 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@94b33a1b7f2d+ other rev@bdb19105162a ancestor rev@924404dff337
@@ -334,7 +319,6 @@
ancestor: 924404dff337, local: 02963e448370+, remote: 97c705ade336
preserving rev for resolve of rev
rev: versions differ -> m
- updating: rev 1/1 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@02963e448370+ other rev@97c705ade336 ancestor rev@924404dff337
@@ -360,14 +344,12 @@
preserving b for resolve of b
preserving rev for resolve of rev
b: both renamed from a -> m
- updating: b 1/2 files (50.00%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b
my b@62e7bf090eba+ other b@49b6d8032493 ancestor a@924404dff337
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 2/2 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@62e7bf090eba+ other rev@49b6d8032493 ancestor rev@924404dff337
@@ -402,9 +384,7 @@
preserving rev for resolve of rev
c: remote created -> g
getting c
- updating: c 1/2 files (50.00%)
rev: versions differ -> m
- updating: rev 2/2 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@02963e448370+ other rev@fe905ef2c33e ancestor rev@924404dff337
@@ -434,14 +414,12 @@
preserving b for resolve of b
preserving rev for resolve of rev
b: both created -> m
- updating: b 1/2 files (50.00%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b
my b@86a2aa42fc76+ other b@af30c7647fc7 ancestor b@000000000000
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 2/2 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@86a2aa42fc76+ other rev@af30c7647fc7 ancestor rev@924404dff337
@@ -469,16 +447,13 @@
preserving rev for resolve of rev
a: other deleted -> r
removing a
- updating: a 1/3 files (33.33%)
b: both created -> m
- updating: b 2/3 files (66.67%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b
my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 3/3 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
@@ -505,16 +480,13 @@
preserving rev for resolve of rev
a: remote is newer -> g
getting a
- updating: a 1/3 files (33.33%)
b: both created -> m
- updating: b 2/3 files (66.67%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b
my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 3/3 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
@@ -542,16 +514,13 @@
preserving rev for resolve of rev
a: other deleted -> r
removing a
- updating: a 1/3 files (33.33%)
b: both created -> m
- updating: b 2/3 files (66.67%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b
my b@59318016310c+ other b@bdb19105162a ancestor b@000000000000
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 3/3 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@59318016310c+ other rev@bdb19105162a ancestor rev@924404dff337
@@ -578,16 +547,13 @@
preserving rev for resolve of rev
a: remote is newer -> g
getting a
- updating: a 1/3 files (33.33%)
b: both created -> m
- updating: b 2/3 files (66.67%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b
my b@86a2aa42fc76+ other b@8dbce441892a ancestor b@000000000000
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 3/3 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@86a2aa42fc76+ other rev@8dbce441892a ancestor rev@924404dff337
@@ -615,14 +581,12 @@
preserving rev for resolve of rev
a: remote unchanged -> k
b: both created -> m
- updating: b 1/2 files (50.00%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b
my b@0b76e65c8289+ other b@4ce40f5aca24 ancestor b@000000000000
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 2/2 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@0b76e65c8289+ other rev@4ce40f5aca24 ancestor rev@924404dff337
@@ -652,16 +616,13 @@
preserving rev for resolve of rev
a: prompt recreating -> g
getting a
- updating: a 1/3 files (33.33%)
b: both created -> m
- updating: b 2/3 files (66.67%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b
my b@02963e448370+ other b@8dbce441892a ancestor b@000000000000
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 3/3 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@02963e448370+ other rev@8dbce441892a ancestor rev@924404dff337
@@ -690,16 +651,13 @@
preserving b for resolve of b
preserving rev for resolve of rev
a: prompt keep -> a
- updating: a 1/3 files (33.33%)
b: both created -> m
- updating: b 2/3 files (66.67%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b
my b@0b76e65c8289+ other b@bdb19105162a ancestor b@000000000000
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 3/3 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@0b76e65c8289+ other rev@bdb19105162a ancestor rev@924404dff337
@@ -730,14 +688,12 @@
preserving rev for resolve of rev
removing a
b: remote moved from a -> m
- updating: b 1/2 files (50.00%)
picked tool 'python ../merge' for b (binary False symlink False)
merging a and b to b
my b@e300d1c794ec+ other b@49b6d8032493 ancestor a@924404dff337
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 2/2 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@e300d1c794ec+ other rev@49b6d8032493 ancestor rev@924404dff337
@@ -767,14 +723,12 @@
preserving b for resolve of b
preserving rev for resolve of rev
b: local copied/moved from a -> m
- updating: b 1/2 files (50.00%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b and a to b
my b@62e7bf090eba+ other a@f4db7e329e71 ancestor a@924404dff337
launching merge tool: python ../merge *$TESTTMP/t/t/b* * * (glob)
merge tool returned: 0
rev: versions differ -> m
- updating: rev 2/2 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@62e7bf090eba+ other rev@f4db7e329e71 ancestor rev@924404dff337
@@ -810,15 +764,12 @@
preserving rev for resolve of rev
c: remote created -> g
getting c
- updating: c 1/3 files (33.33%)
b: local copied/moved from a -> m
- updating: b 2/3 files (66.67%)
picked tool 'python ../merge' for b (binary False symlink False)
merging b and a to b
my b@02963e448370+ other a@2b958612230f ancestor a@924404dff337
premerge successful
rev: versions differ -> m
- updating: rev 3/3 files (100.00%)
picked tool 'python ../merge' for rev (binary False symlink False)
merging rev
my rev@02963e448370+ other rev@2b958612230f ancestor rev@924404dff337
@@ -875,7 +826,7 @@
$ mkdir 7 8
$ echo m > 7/f
$ echo m > 8/f
- $ hg merge -f --tool internal:dump -v --debug -r2 | sed '/^updating:/,$d' 2> /dev/null
+ $ hg merge -f --tool internal:dump -v --debug -r2 | sed '/^ 0\/f: both created -> m/,$d' 2> /dev/null
searching for copies back to rev 1
unmatched files in local:
5/g
--- a/tests/test-rename.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-rename.t Mon Jun 15 13:31:22 2015 -0500
@@ -20,6 +20,7 @@
branch: default
commit: 1 renamed
update: (current)
+ phases: 1 draft
$ hg status -C
A d2/c
d1/d11/a1
--- a/tests/test-revert-interactive.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-revert-interactive.t Mon Jun 15 13:31:22 2015 -0500
@@ -52,7 +52,7 @@
reverting folder1/g (glob)
removing folder1/i (glob)
reverting folder2/h (glob)
- diff -r 89ac3d72e4a4 f
+ diff --git a/f b/f
2 hunks, 2 lines changed
examine changes to 'f'? [Ynesfdaq?] y
@@ -74,7 +74,7 @@
-b
record change 2/6 to 'f'? [Ynesfdaq?] y
- diff -r 89ac3d72e4a4 folder1/g
+ diff --git a/folder1/g b/folder1/g
2 hunks, 2 lines changed
examine changes to 'folder1/g'? [Ynesfdaq?] y
@@ -96,7 +96,7 @@
-d
record change 4/6 to 'folder1/g'? [Ynesfdaq?] n
- diff -r 89ac3d72e4a4 folder2/h
+ diff --git a/folder2/h b/folder2/h
2 hunks, 2 lines changed
examine changes to 'folder2/h'? [Ynesfdaq?] n
@@ -127,7 +127,7 @@
$ echo q | hg revert -i -r 2
reverting folder1/g (glob)
reverting folder2/h (glob)
- diff -r 89ac3d72e4a4 folder1/g
+ diff --git a/folder1/g b/folder1/g
1 hunks, 1 lines changed
examine changes to 'folder1/g'? [Ynesfdaq?] q
@@ -151,7 +151,7 @@
reverting folder1/g (glob)
removing folder1/i (glob)
reverting folder2/h (glob)
- diff -r 89ac3d72e4a4 f
+ diff --git a/f b/f
2 hunks, 2 lines changed
examine changes to 'f'? [Ynesfdaq?] y
@@ -173,7 +173,7 @@
-b
record change 2/6 to 'f'? [Ynesfdaq?] y
- diff -r 89ac3d72e4a4 folder1/g
+ diff --git a/folder1/g b/folder1/g
2 hunks, 2 lines changed
examine changes to 'folder1/g'? [Ynesfdaq?] y
@@ -195,7 +195,7 @@
-d
record change 4/6 to 'folder1/g'? [Ynesfdaq?] n
- diff -r 89ac3d72e4a4 folder2/h
+ diff --git a/folder2/h b/folder2/h
2 hunks, 2 lines changed
examine changes to 'folder2/h'? [Ynesfdaq?] n
@@ -230,7 +230,7 @@
> n
> n
> EOF
- diff -r 59dd6e4ab63a f
+ diff --git a/f b/f
2 hunks, 2 lines changed
examine changes to 'f'? [Ynesfdaq?] y
@@ -270,3 +270,124 @@
3
4
5
+ $ rm f.orig
+ $ hg update -C .
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Check editing files newly added by a revert
+
+1) Create a dummy editor changing 1 to 42
+ $ cat > $TESTTMP/editor.sh << '__EOF__'
+ > cat "$1" | sed "s/1/42/g" > tt
+ > mv tt "$1"
+ > __EOF__
+
+2) Remove f
+ $ hg rm f
+ $ hg commit -m "remove f"
+
+3) Do another commit on top
+ $ touch k; hg add k
+ $ hg commit -m "add k"
+ $ hg st
+
+4) Use interactive revert to recover f and change it on the fly
+ $ HGEDITOR="\"sh\" \"${TESTTMP}/editor.sh\"" hg revert -i -r ".^^" <<EOF
+ > y
+ > e
+ > EOF
+ adding f
+ removing k
+ diff --git a/f b/f
+ new file mode 100644
+ examine changes to 'f'? [Ynesfdaq?] y
+
+ @@ -0,0 +1,7 @@
+ +a
+ +1
+ +2
+ +3
+ +4
+ +5
+ +b
+ record this change to 'f'? [Ynesfdaq?] e
+
+ $ cat f
+ a
+ 42
+ 2
+ 3
+ 4
+ 5
+ b
+
+Check the experimental config to invert the selection:
+ $ cat <<EOF >> $HGRCPATH
+ > [experimental]
+ > revertalternateinteractivemode=True
+ > EOF
+
+
+ $ hg up -C .
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ printf 'firstline\nc\n1\n2\n3\n 3\n5\nd\nlastline\n' > folder1/g
+ $ hg diff --nodates
+ diff -r 5a858e056dc0 folder1/g
+ --- a/folder1/g
+ +++ b/folder1/g
+ @@ -1,7 +1,9 @@
+ +firstline
+ c
+ 1
+ 2
+ 3
+ -4
+ + 3
+ 5
+ d
+ +lastline
+ $ hg revert -i <<EOF
+ > y
+ > y
+ > y
+ > n
+ > EOF
+ reverting folder1/g (glob)
+ diff --git a/folder1/g b/folder1/g
+ 3 hunks, 3 lines changed
+ examine changes to 'folder1/g'? [Ynesfdaq?] y
+
+ @@ -1,4 +1,5 @@
+ +firstline
+ c
+ 1
+ 2
+ 3
+ record change 1/3 to 'folder1/g'? [Ynesfdaq?] y
+
+ @@ -1,7 +2,7 @@
+ c
+ 1
+ 2
+ 3
+ -4
+ + 3
+ 5
+ d
+ record change 2/3 to 'folder1/g'? [Ynesfdaq?] y
+
+ @@ -6,2 +7,3 @@
+ 5
+ d
+ +lastline
+ record change 3/3 to 'folder1/g'? [Ynesfdaq?] n
+
+ $ hg diff --nodates
+ diff -r 5a858e056dc0 folder1/g
+ --- a/folder1/g
+ +++ b/folder1/g
+ @@ -5,3 +5,4 @@
+ 4
+ 5
+ d
+ +lastline
--- a/tests/test-revert.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-revert.t Mon Jun 15 13:31:22 2015 -0500
@@ -360,6 +360,7 @@
branch: default
commit: 2 modified, 1 removed (merge)
update: (current)
+ phases: 3 draft
clarifies who added what
--- a/tests/test-revset.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-revset.t Mon Jun 15 13:31:22 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 "$@"
@@ -21,13 +43,11 @@
$ echo b > b
$ hg branch b
marked working directory as branch b
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -Aqm1
$ rm a
$ hg branch a-b-c-
marked working directory as branch a-b-c-
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -Aqm2 -u Bob
$ hg log -r "extra('branch', 'a-b-c-')" --template '{rev}\n'
@@ -44,7 +64,6 @@
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg branch +a+b+c+
marked working directory as branch +a+b+c+
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -Aqm3
$ hg co 2 # interleave
@@ -52,14 +71,12 @@
$ echo bb > b
$ hg branch -- -a-b-c-
marked working directory as branch -a-b-c-
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -Aqm4 -d "May 12 2005"
$ hg co 3
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg branch !a/b/c/
marked working directory as branch !a/b/c/
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -Aqm"5 bug"
$ hg merge 4
@@ -67,23 +84,19 @@
(branch merge, don't forget to commit)
$ hg branch _a_b_c_
marked working directory as branch _a_b_c_
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -Aqm"6 issue619"
$ hg branch .a.b.c.
marked working directory as branch .a.b.c.
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -Aqm7
$ hg branch all
marked working directory as branch all
- (branches are permanent and global, did you want a bookmark?)
$ hg co 4
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg branch é
marked working directory as branch \xc3\xa9 (esc)
- (branches are permanent and global, did you want a bookmark?)
$ hg ci -Aqm9
$ hg tag -r6 1.0
@@ -115,16 +128,11 @@
6
$ try '0|1|2'
(or
- (or
- ('symbol', '0')
- ('symbol', '1'))
+ ('symbol', '0')
+ ('symbol', '1')
('symbol', '2'))
* set:
- <addset
- <addset
- <baseset [0]>,
- <baseset [1]>>,
- <baseset [2]>>
+ <baseset [0, 1, 2]>
0
1
2
@@ -260,9 +268,7 @@
* set:
<addset
<baseset [1]>,
- <addset
- <baseset [2]>,
- <baseset [3]>>>
+ <baseset [2, 3]>>
1
2
3
@@ -281,7 +287,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 +295,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 +346,9 @@
0
$ log 'ancestor(1,2,3,4,5)'
1
+
+test ancestors
+
$ log 'ancestors(5)'
0
1
@@ -318,6 +356,12 @@
5
$ log 'ancestor(ancestors(5))'
0
+ $ log '::r3232()'
+ 0
+ 1
+ 2
+ 3
+
$ log 'author(bob)'
2
$ log 'author("re:bob|test")'
@@ -555,6 +599,24 @@
<baseset+ [8, 9]>
8
9
+ $ try --optimize '(9)%(5)'
+ (only
+ (group
+ ('symbol', '9'))
+ (group
+ ('symbol', '5')))
+ * optimized:
+ (func
+ ('symbol', 'only')
+ (list
+ ('symbol', '9')
+ ('symbol', '5')))
+ * set:
+ <baseset+ [8, 9, 2, 4]>
+ 2
+ 4
+ 8
+ 9
Test the order of operations
@@ -630,9 +692,9 @@
Test working-directory revision
$ hg debugrevspec 'wdir()'
None
-BROKEN: should include 'None'
$ hg debugrevspec 'tip or wdir()'
9
+ None
$ hg debugrevspec '0:tip and wdir()'
$ log 'outgoing()'
@@ -796,6 +858,239 @@
4
5
+test that more than one `-r`s are combined in the right order and deduplicated:
+
+ $ hg log -T '{rev}\n' -r 3 -r 3 -r 4 -r 5:2 -r 'ancestors(4)'
+ 3
+ 4
+ 5
+ 2
+ 0
+ 1
+
+test that `or` operation skips duplicated revisions from right-hand side
+
+ $ try 'reverse(1::5) or ancestors(4)'
+ (or
+ (func
+ ('symbol', 'reverse')
+ (dagrange
+ ('symbol', '1')
+ ('symbol', '5')))
+ (func
+ ('symbol', 'ancestors')
+ ('symbol', '4')))
+ * set:
+ <addset
+ <baseset [5, 3, 1]>,
+ <generatorset+>>
+ 5
+ 3
+ 1
+ 0
+ 2
+ 4
+ $ try 'sort(ancestors(4) or reverse(1::5))'
+ (func
+ ('symbol', 'sort')
+ (or
+ (func
+ ('symbol', 'ancestors')
+ ('symbol', '4'))
+ (func
+ ('symbol', 'reverse')
+ (dagrange
+ ('symbol', '1')
+ ('symbol', '5')))))
+ * set:
+ <addset+
+ <generatorset+>,
+ <baseset [5, 3, 1]>>
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+
+test optimization of trivial `or` operation
+
+ $ try --optimize '0|(1)|"2"|-2|tip|null'
+ (or
+ ('symbol', '0')
+ (group
+ ('symbol', '1'))
+ ('string', '2')
+ (negate
+ ('symbol', '2'))
+ ('symbol', 'tip')
+ ('symbol', 'null'))
+ * optimized:
+ (func
+ ('symbol', '_list')
+ ('string', '0\x001\x002\x00-2\x00tip\x00null'))
+ * set:
+ <baseset [0, 1, 2, 8, 9, -1]>
+ 0
+ 1
+ 2
+ 8
+ 9
+ -1
+
+ $ try --optimize '0|1|2:3'
+ (or
+ ('symbol', '0')
+ ('symbol', '1')
+ (range
+ ('symbol', '2')
+ ('symbol', '3')))
+ * optimized:
+ (or
+ (func
+ ('symbol', '_list')
+ ('string', '0\x001'))
+ (range
+ ('symbol', '2')
+ ('symbol', '3')))
+ * set:
+ <addset
+ <baseset [0, 1]>,
+ <spanset+ 2:3>>
+ 0
+ 1
+ 2
+ 3
+
+ $ try --optimize '0:1|2|3:4|5|6'
+ (or
+ (range
+ ('symbol', '0')
+ ('symbol', '1'))
+ ('symbol', '2')
+ (range
+ ('symbol', '3')
+ ('symbol', '4'))
+ ('symbol', '5')
+ ('symbol', '6'))
+ * optimized:
+ (or
+ (range
+ ('symbol', '0')
+ ('symbol', '1'))
+ ('symbol', '2')
+ (range
+ ('symbol', '3')
+ ('symbol', '4'))
+ (func
+ ('symbol', '_list')
+ ('string', '5\x006')))
+ * set:
+ <addset
+ <addset
+ <spanset+ 0:1>,
+ <baseset [2]>>,
+ <addset
+ <spanset+ 3:4>,
+ <baseset [5, 6]>>>
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+
+test that `_list` should be narrowed by provided `subset`
+
+ $ log '0:2 and (null|1|2|3)'
+ 1
+ 2
+
+test that `_list` should remove duplicates
+
+ $ log '0|1|2|1|2|-1|tip'
+ 0
+ 1
+ 2
+ 9
+
+test unknown revision in `_list`
+
+ $ log '0|unknown'
+ abort: unknown revision 'unknown'!
+ [255]
+
+test integer range in `_list`
+
+ $ log '-1|-10'
+ 9
+ 0
+
+ $ log '-10|-11'
+ abort: unknown revision '-11'!
+ [255]
+
+ $ log '9|10'
+ abort: unknown revision '10'!
+ [255]
+
+test '0000' != '0' in `_list`
+
+ $ log '0|0000'
+ 0
+ -1
+
+test that chained `or` operations make balanced addsets
+
+ $ try '0:1|1:2|2:3|3:4|4:5'
+ (or
+ (range
+ ('symbol', '0')
+ ('symbol', '1'))
+ (range
+ ('symbol', '1')
+ ('symbol', '2'))
+ (range
+ ('symbol', '2')
+ ('symbol', '3'))
+ (range
+ ('symbol', '3')
+ ('symbol', '4'))
+ (range
+ ('symbol', '4')
+ ('symbol', '5')))
+ * set:
+ <addset
+ <addset
+ <spanset+ 0:1>,
+ <spanset+ 1:2>>,
+ <addset
+ <spanset+ 2:3>,
+ <addset
+ <spanset+ 3:4>,
+ <spanset+ 4:5>>>>
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+
+test that chained `or` operations never eat up stack (issue4624)
+(uses `0:1` instead of `0` to avoid future optimization of trivial revisions)
+
+ $ hg log -T '{rev}\n' -r "`python -c "print '|'.join(['0:1'] * 500)"`"
+ 0
+ 1
+
+test that repeated `-r` options never eat up stack (issue4565)
+(uses `-r 0::1` to avoid possible optimization at old-style parser)
+
+ $ hg log -T '{rev}\n' `python -c "for i in xrange(500): print '-r 0::1 ',"`
+ 0
+ 1
+
check that conversion to only works
$ try --optimize '::3 - ::1'
(minus
@@ -1211,9 +1506,7 @@
* set:
<addset
<baseset [3]>,
- <addset
- <baseset [1]>,
- <baseset [2]>>>
+ <baseset [1, 2]>>
3
1
2
@@ -1238,6 +1531,44 @@
<baseset [5]>
5
+test chained `or` operations are flattened at parsing phase
+
+ $ echo 'chainedorops($1, $2, $3) = $1|$2|$3' >> .hg/hgrc
+ $ try 'chainedorops(0:1, 1:2, 2:3)'
+ (func
+ ('symbol', 'chainedorops')
+ (list
+ (list
+ (range
+ ('symbol', '0')
+ ('symbol', '1'))
+ (range
+ ('symbol', '1')
+ ('symbol', '2')))
+ (range
+ ('symbol', '2')
+ ('symbol', '3'))))
+ (or
+ (range
+ ('symbol', '0')
+ ('symbol', '1'))
+ (range
+ ('symbol', '1')
+ ('symbol', '2'))
+ (range
+ ('symbol', '2')
+ ('symbol', '3')))
+ * set:
+ <addset
+ <spanset+ 0:1>,
+ <addset
+ <spanset+ 1:2>,
+ <spanset+ 2:3>>>
+ 0
+ 1
+ 2
+ 3
+
test variable isolation, variable placeholders are rewritten as string
then parsed and matched again as string. Check they do not leak too
far away.
@@ -1306,8 +1637,7 @@
<addset
<baseset [9]>,
<filteredset
- <filteredset
- <fullreposet+ 0:9>>>>
+ <fullreposet+ 0:9>>>
9
$ try 'd(2:5)'
--- a/tests/test-run-tests.py Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-run-tests.py Mon Jun 15 13:31:22 2015 -0500
@@ -3,6 +3,7 @@
run-test.t only checks positive matches and can not see warnings
(both by design)
"""
+from __future__ import print_function
import os, re
# this is hack to make sure no escape characters are inserted into the output
@@ -11,27 +12,37 @@
import doctest
run_tests = __import__('run-tests')
+def prn(ex):
+ m = ex.args[0]
+ if isinstance(m, str):
+ print(m)
+ else:
+ print(m.decode('utf-8'))
+
def lm(expected, output):
r"""check if output matches expected
does it generally work?
- >>> lm('H*e (glob)\n', 'Here\n')
+ >>> lm(b'H*e (glob)\n', b'Here\n')
True
fail on bad test data
- >>> try: lm('a\n','a')
- ... except AssertionError, ex: print ex
+ >>> try: lm(b'a\n',b'a')
+ ... except AssertionError as ex: print(ex)
missing newline
- >>> try: lm('single backslash\n', 'single \backslash\n')
- ... except AssertionError, ex: print ex
+ >>> try: lm(b'single backslash\n', b'single \backslash\n')
+ ... except AssertionError as ex: prn(ex)
single backslash or unknown char
"""
- assert expected.endswith('\n') and output.endswith('\n'), 'missing newline'
- assert not re.search(r'[^ \w\\/\r\n()*?]', expected + output), \
- 'single backslash or unknown char'
+ assert (expected.endswith(b'\n')
+ and output.endswith(b'\n')), 'missing newline'
+ assert not re.search(br'[^ \w\\/\r\n()*?]', expected + output), \
+ b'single backslash or unknown char'
match = run_tests.TTest.linematch(expected, output)
if isinstance(match, str):
return 'special: ' + match
+ elif isinstance(match, bytes):
+ return 'special: ' + match.decode('utf-8')
else:
return bool(match) # do not return match object
@@ -43,15 +54,15 @@
>>> os.altsep = True
valid match on windows
- >>> lm('g/a*/d (glob)\n', 'g\\abc/d\n')
+ >>> lm(b'g/a*/d (glob)\n', b'g\\abc/d\n')
True
direct matching, glob unnecessary
- >>> lm('g/b (glob)\n', 'g/b\n')
+ >>> lm(b'g/b (glob)\n', b'g/b\n')
'special: -glob'
missing glob
- >>> lm('/g/c/d/fg\n', '\\g\\c\\d/fg\n')
+ >>> lm(b'/g/c/d/fg\n', b'\\g\\c\\d/fg\n')
'special: +glob'
restore os.altsep
@@ -67,15 +78,15 @@
>>> os.altsep = False
backslash does not match slash
- >>> lm('h/a* (glob)\n', 'h\\ab\n')
+ >>> lm(b'h/a* (glob)\n', b'h\\ab\n')
False
direct matching glob can not be recognized
- >>> lm('h/b (glob)\n', 'h/b\n')
+ >>> lm(b'h/b (glob)\n', b'h/b\n')
True
missing glob can not not be recognized
- >>> lm('/h/c/df/g/\n', '\\h/c\\df/g\\\n')
+ >>> lm(b'/h/c/df/g/\n', b'\\h/c\\df/g\\\n')
False
restore os.altsep
--- a/tests/test-run-tests.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-run-tests.t Mon Jun 15 13:31:22 2015 -0500
@@ -10,7 +10,7 @@
Smoke test
============
- $ $TESTDIR/run-tests.py $HGTEST_RUN_TESTS_PURE
+ $ run-tests.py $HGTEST_RUN_TESTS_PURE
# Ran 0 tests, 0 skipped, 0 warned, 0 failed.
@@ -21,10 +21,12 @@
> $ echo babar
> babar
> $ echo xyzzy
+ > never happens (?)
> xyzzy
+ > nor this (?)
> EOF
- $ $TESTDIR/run-tests.py --with-hg=`which hg`
+ $ run-tests.py --with-hg=`which hg`
.
# Ran 1 tests, 0 skipped, 0 warned, 0 failed.
@@ -39,10 +41,10 @@
> EOF
>>> fh = open('test-failure-unicode.t', 'wb')
- >>> fh.write(u' $ echo babar\u03b1\n'.encode('utf-8'))
- >>> fh.write(u' l\u03b5\u03b5t\n'.encode('utf-8'))
+ >>> fh.write(u' $ echo babar\u03b1\n'.encode('utf-8')) and None
+ >>> fh.write(u' l\u03b5\u03b5t\n'.encode('utf-8')) and None
- $ $TESTDIR/run-tests.py --with-hg=`which hg`
+ $ run-tests.py --with-hg=`which hg`
--- $TESTTMP/test-failure.t
+++ $TESTTMP/test-failure.t.err
@@ -71,7 +73,7 @@
[1]
test --xunit support
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --xunit=xunit.xml
+ $ run-tests.py --with-hg=`which hg` --xunit=xunit.xml
--- $TESTTMP/test-failure.t
+++ $TESTTMP/test-failure.t.err
@@ -127,7 +129,7 @@
test for --retest
====================
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --retest
+ $ run-tests.py --with-hg=`which hg` --retest
--- $TESTTMP/test-failure.t
+++ $TESTTMP/test-failure.t.err
@@ -150,18 +152,18 @@
successful
- $ $TESTDIR/run-tests.py --with-hg=`which hg` test-success.t
+ $ run-tests.py --with-hg=`which hg` test-success.t
.
# Ran 1 tests, 0 skipped, 0 warned, 0 failed.
success w/ keyword
- $ $TESTDIR/run-tests.py --with-hg=`which hg` -k xyzzy
+ $ run-tests.py --with-hg=`which hg` -k xyzzy
.
# Ran 2 tests, 1 skipped, 0 warned, 0 failed.
failed
- $ $TESTDIR/run-tests.py --with-hg=`which hg` test-failure.t
+ $ run-tests.py --with-hg=`which hg` test-failure.t
--- $TESTTMP/test-failure.t
+++ $TESTTMP/test-failure.t.err
@@ -180,7 +182,7 @@
[1]
failure w/ keyword
- $ $TESTDIR/run-tests.py --with-hg=`which hg` -k rataxes
+ $ run-tests.py --with-hg=`which hg` -k rataxes
--- $TESTTMP/test-failure.t
+++ $TESTTMP/test-failure.t.err
@@ -206,7 +208,7 @@
$ cat > test-serve-fail.t <<EOF
> $ echo 'abort: child process failed to start blah'
> EOF
- $ $TESTDIR/run-tests.py --with-hg=`which hg` test-serve-fail.t
+ $ run-tests.py --with-hg=`which hg` test-serve-fail.t
ERROR: test-serve-fail.t output changed
!
@@ -222,7 +224,7 @@
Running In Debug Mode
======================
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --debug 2>&1 | grep -v pwd
+ $ run-tests.py --with-hg=`which hg` --debug 2>&1 | grep -v pwd
+ echo *SALT* 0 0 (glob)
*SALT* 0 0 (glob)
+ echo babar
@@ -237,8 +239,8 @@
*SALT* 2 0 (glob)
+ echo xyzzy
xyzzy
- + echo *SALT* 4 0 (glob)
- *SALT* 4 0 (glob)
+ + echo *SALT* 6 0 (glob)
+ *SALT* 6 0 (glob)
.
# Ran 2 tests, 0 skipped, 0 warned, 0 failed.
@@ -248,7 +250,7 @@
(duplicate the failing test to get predictable output)
$ cp test-failure.t test-failure-copy.t
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --jobs 2 test-failure*.t -n
+ $ run-tests.py --with-hg=`which hg` --jobs 2 test-failure*.t -n
!!
Failed test-failure*.t: output changed (glob)
Failed test-failure*.t: output changed (glob)
@@ -258,9 +260,9 @@
failures in parallel with --first should only print one failure
>>> f = open('test-nothing.t', 'w')
- >>> f.write('foo\n' * 1024)
- >>> f.write(' $ sleep 1')
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --jobs 2 --first
+ >>> f.write('foo\n' * 1024) and None
+ >>> f.write(' $ sleep 1') and None
+ $ run-tests.py --with-hg=`which hg` --jobs 2 --first
--- $TESTTMP/test-failure*.t (glob)
+++ $TESTTMP/test-failure*.t.err (glob)
@@ -290,7 +292,7 @@
Refuse the fix
- $ echo 'n' | $TESTDIR/run-tests.py --with-hg=`which hg` -i
+ $ echo 'n' | run-tests.py --with-hg=`which hg` -i
--- $TESTTMP/test-failure.t
+++ $TESTTMP/test-failure.t.err
@@ -316,7 +318,7 @@
Interactive with custom view
- $ echo 'n' | $TESTDIR/run-tests.py --with-hg=`which hg` -i --view echo
+ $ echo 'n' | run-tests.py --with-hg=`which hg` -i --view echo
$TESTTMP/test-failure.t $TESTTMP/test-failure.t.err (glob)
Accept this change? [n]* (glob)
ERROR: test-failure.t output changed
@@ -328,7 +330,7 @@
View the fix
- $ echo 'y' | $TESTDIR/run-tests.py --with-hg=`which hg` --view echo
+ $ echo 'y' | run-tests.py --with-hg=`which hg` --view echo
$TESTTMP/test-failure.t $TESTTMP/test-failure.t.err (glob)
ERROR: test-failure.t output changed
@@ -346,7 +348,7 @@
$ echo " saved backup bundle to \$TESTTMP/foo.hg (glob)" >> test-failure.t
$ echo " $ echo 'saved backup bundle to \$TESTTMP/foo.hg'" >> test-failure.t
$ echo " saved backup bundle to \$TESTTMP/*.hg (glob)" >> test-failure.t
- $ echo 'y' | $TESTDIR/run-tests.py --with-hg=`which hg` -i 2>&1 | \
+ $ echo 'y' | run-tests.py --with-hg=`which hg` -i 2>&1 | \
> sed -e 's,(glob)$,&<,g'
--- $TESTTMP/test-failure.t
@@ -384,7 +386,7 @@
No Diff
===============
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --nodiff
+ $ run-tests.py --with-hg=`which hg` --nodiff
!.
Failed test-failure.t: output changed
# Ran 2 tests, 0 skipped, 0 warned, 1 failed.
@@ -394,22 +396,22 @@
test for --time
==================
- $ $TESTDIR/run-tests.py --with-hg=`which hg` test-success.t --time
+ $ run-tests.py --with-hg=`which hg` test-success.t --time
.
# Ran 1 tests, 0 skipped, 0 warned, 0 failed.
# Producing time report
- cuser csys real Test
- \s*[\d\.]{5} \s*[\d\.]{5} \s*[\d\.]{5} test-success.t (re)
+ start end cuser csys real Test
+ \s*[\d\.]{5} \s*[\d\.]{5} \s*[\d\.]{5} \s*[\d\.]{5} \s*[\d\.]{5} test-success.t (re)
test for --time with --job enabled
====================================
- $ $TESTDIR/run-tests.py --with-hg=`which hg` test-success.t --time --jobs 2
+ $ run-tests.py --with-hg=`which hg` test-success.t --time --jobs 2
.
# Ran 1 tests, 0 skipped, 0 warned, 0 failed.
# Producing time report
- cuser csys real Test
- \s*[\d\.]{5} \s*[\d\.]{5} \s*[\d\.]{5} test-success.t (re)
+ start end cuser csys real Test
+ \s*[\d\.]{5} \s*[\d\.]{5} \s*[\d\.]{5} \s*[\d\.]{5} \s*[\d\.]{5} test-success.t (re)
Skips
================
@@ -417,7 +419,7 @@
> $ echo xyzzy
> #require false
> EOF
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --nodiff
+ $ run-tests.py --with-hg=`which hg` --nodiff
!.s
Skipped test-skip.t: skipped
Failed test-failure.t: output changed
@@ -425,13 +427,13 @@
python hash seed: * (glob)
[1]
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --keyword xyzzy
+ $ run-tests.py --with-hg=`which hg` --keyword xyzzy
.s
Skipped test-skip.t: skipped
# Ran 2 tests, 2 skipped, 0 warned, 0 failed.
Skips with xml
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --keyword xyzzy \
+ $ run-tests.py --with-hg=`which hg` --keyword xyzzy \
> --xunit=xunit.xml
.s
Skipped test-skip.t: skipped
@@ -444,7 +446,7 @@
Missing skips or blacklisted skips don't count as executed:
$ echo test-failure.t > blacklist
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --blacklist=blacklist \
+ $ run-tests.py --with-hg=`which hg` --blacklist=blacklist \
> test-failure.t test-bogus.t
ss
Skipped test-bogus.t: Doesn't exist
@@ -456,7 +458,7 @@
test for --json
==================
- $ $TESTDIR/run-tests.py --with-hg=`which hg` --json
+ $ run-tests.py --with-hg=`which hg` --json
--- $TESTTMP/test-failure.t
+++ $TESTTMP/test-failure.t.err
@@ -480,23 +482,75 @@
"test-failure.t": [\{] (re)
"csys": "\s*[\d\.]{4,5}", ? (re)
"cuser": "\s*[\d\.]{4,5}", ? (re)
+ "end": "\s*[\d\.]{4,5}", ? (re)
"result": "failure", ? (re)
+ "start": "\s*[\d\.]{4,5}", ? (re)
"time": "\s*[\d\.]{4,5}" (re)
}, ? (re)
"test-skip.t": {
"csys": "\s*[\d\.]{4,5}", ? (re)
"cuser": "\s*[\d\.]{4,5}", ? (re)
+ "end": "\s*[\d\.]{4,5}", ? (re)
"result": "skip", ? (re)
+ "start": "\s*[\d\.]{4,5}", ? (re)
"time": "\s*[\d\.]{4,5}" (re)
}, ? (re)
"test-success.t": [\{] (re)
"csys": "\s*[\d\.]{4,5}", ? (re)
"cuser": "\s*[\d\.]{4,5}", ? (re)
+ "end": "\s*[\d\.]{4,5}", ? (re)
"result": "success", ? (re)
+ "start": "\s*[\d\.]{4,5}", ? (re)
"time": "\s*[\d\.]{4,5}" (re)
}
} (no-eol)
+Test that failed test accepted through interactive are properly reported:
+
+ $ cp test-failure.t backup
+ $ echo y | 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)
+ "end": "\s*[\d\.]{4,5}", ? (re)
+ "result": "success", ? (re)
+ "start": "\s*[\d\.]{4,5}", ? (re)
+ "time": "\s*[\d\.]{4,5}" (re)
+ }, ? (re)
+ "test-skip.t": {
+ "csys": "\s*[\d\.]{4,5}", ? (re)
+ "cuser": "\s*[\d\.]{4,5}", ? (re)
+ "end": "\s*[\d\.]{4,5}", ? (re)
+ "result": "skip", ? (re)
+ "start": "\s*[\d\.]{4,5}", ? (re)
+ "time": "\s*[\d\.]{4,5}" (re)
+ }, ? (re)
+ "test-success.t": [\{] (re)
+ "csys": "\s*[\d\.]{4,5}", ? (re)
+ "cuser": "\s*[\d\.]{4,5}", ? (re)
+ "end": "\s*[\d\.]{4,5}", ? (re)
+ "result": "success", ? (re)
+ "start": "\s*[\d\.]{4,5}", ? (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
@@ -506,7 +560,7 @@
> foo * \ (glob)
> EOF
- $ $TESTDIR/run-tests.py --with-hg=`which hg` test-glob-backslash.t
+ $ run-tests.py --with-hg=`which hg` test-glob-backslash.t
.
# Ran 1 tests, 0 skipped, 0 warned, 0 failed.
--- a/tests/test-serve.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-serve.t Mon Jun 15 13:31:22 2015 -0500
@@ -9,7 +9,7 @@
> cat hg.pid >> "$DAEMON_PIDS"
> echo % errors
> cat errors.log
- > "$TESTDIR/killdaemons.py" hg.pid
+ > killdaemons.py hg.pid
> }
$ hg init test
--- a/tests/test-setdiscovery.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-setdiscovery.t Mon Jun 15 13:31:22 2015 -0500
@@ -14,13 +14,13 @@
> hg -R a debugdiscovery b --verbose --old
> echo
> echo "% -- a -> b set"
- > hg -R a debugdiscovery b --verbose --debug
+ > hg -R a debugdiscovery b --verbose --debug --config progress.debug=true
> echo
> echo "% -- b -> a tree"
- > hg -R b debugdiscovery a --verbose --old
+ > hg -R b debugdiscovery a --verbose --old --config
> echo
> echo "% -- b -> a set"
- > hg -R b debugdiscovery a --verbose --debug
+ > hg -R b debugdiscovery a --verbose --debug --config progress.debug=true
> cd ..
> }
@@ -305,7 +305,7 @@
updating to branch b
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
- $ hg -R a debugdiscovery b --debug --verbose
+ $ hg -R a debugdiscovery b --debug --verbose --config progress.debug=true
comparing with b
query 1; heads
searching for changes
@@ -346,7 +346,7 @@
searching for changes
e64a39e7da8b
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
$ cut -d' ' -f6- access.log | grep -v cmd=known # cmd=known uses random sampling
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D513314ca8b3ae4dac8eec56966265b00fcf866db
--- a/tests/test-share.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-share.t Mon Jun 15 13:31:22 2015 -0500
@@ -99,7 +99,7 @@
$ hg serve -n test -p $HGPORT -d --pid-file=hg.pid
$ cat hg.pid >> $DAEMON_PIDS
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-file/'
+ $ get-with-headers.py localhost:$HGPORT 'raw-file/'
200 Script output follows
@@ -299,5 +299,5 @@
Explicitly kill daemons to let the test exit on Windows
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
--- a/tests/test-shelve.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-shelve.t Mon Jun 15 13:31:22 2015 -0500
@@ -60,6 +60,7 @@
-m --message TEXT use text as shelve message
-n --name NAME use the given name for the shelved commit
-p --patch show patch
+ -i --interactive interactive mode, only works while creating a shelve
--stat output diffstat-style summary of changes
-I --include PATTERN [+] include names matching the given patterns
-X --exclude PATTERN [+] exclude names matching the given patterns
@@ -782,6 +783,7 @@
bookmarks: *test
commit: 2 unknown (clean)
update: (current)
+ phases: 5 draft
$ hg shelve --delete --stat
abort: options '--delete' and '--stat' may not be used together
@@ -862,4 +864,45 @@
c
x
x
- $ cd ..
+
+shelve --patch and shelve --stat should work with a single valid shelfname
+
+ $ hg up --clean .
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg shelve --list
+ $ echo 'patch a' > shelf-patch-a
+ $ hg add shelf-patch-a
+ $ hg shelve
+ shelved as default
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo 'patch b' > shelf-patch-b
+ $ hg add shelf-patch-b
+ $ hg shelve
+ shelved as default-01
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ hg shelve --patch default default-01
+ abort: --patch expects a single shelf
+ [255]
+ $ hg shelve --stat default default-01
+ abort: --stat expects a single shelf
+ [255]
+ $ hg shelve --patch default
+ default (* ago) changes to 'create conflict' (glob)
+
+ diff --git a/shelf-patch-a b/shelf-patch-a
+ new file mode 100644
+ --- /dev/null
+ +++ b/shelf-patch-a
+ @@ -0,0 +1,1 @@
+ +patch a
+ $ hg shelve --stat default
+ default (* ago) changes to 'create conflict' (glob)
+ shelf-patch-a | 1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+ $ hg shelve --patch nonexistentshelf
+ abort: cannot find shelf nonexistentshelf
+ [255]
+ $ hg shelve --stat nonexistentshelf
+ abort: cannot find shelf nonexistentshelf
+ [255]
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-ssh-bundle1.t Mon Jun 15 13:31:22 2015 -0500
@@ -0,0 +1,512 @@
+This test is a duplicate of 'test-http.t' feel free to factor out
+parts that are not bundle1/bundle2 specific.
+
+ $ cat << EOF >> $HGRCPATH
+ > [experimental]
+ > # This test is dedicated to interaction through old bundle
+ > bundle2-exp = False
+ > EOF
+
+
+This test tries to exercise the ssh functionality with a dummy script
+
+creating 'remote' repo
+
+ $ hg init remote
+ $ cd remote
+ $ echo this > foo
+ $ echo this > fooO
+ $ hg ci -A -m "init" foo fooO
+
+insert a closed branch (issue4428)
+
+ $ hg up null
+ 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
+ $ hg branch closed
+ marked working directory as branch closed
+ (branches are permanent and global, did you want a bookmark?)
+ $ hg ci -mc0
+ $ hg ci --close-branch -mc1
+ $ hg up -q default
+
+configure for serving
+
+ $ cat <<EOF > .hg/hgrc
+ > [server]
+ > uncompressed = True
+ >
+ > [hooks]
+ > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
+ > EOF
+ $ cd ..
+
+repo not found error
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
+ remote: abort: there is no Mercurial repository here (.hg not found)!
+ abort: no suitable response from remote hg!
+ [255]
+
+non-existent absolute path
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
+ remote: abort: there is no Mercurial repository here (.hg not found)!
+ abort: no suitable response from remote hg!
+ [255]
+
+clone remote via stream
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
+ streaming all changes
+ 4 files to transfer, 615 bytes of data
+ transferred 615 bytes in * seconds (*) (glob)
+ searching for changes
+ no changes found
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd local-stream
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 3 changesets, 2 total revisions
+ $ hg branches
+ default 0:1160648e36ce
+ $ cd ..
+
+clone bookmarks via stream
+
+ $ hg -R local-stream book mybook
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/local-stream stream2
+ streaming all changes
+ 4 files to transfer, 615 bytes of data
+ transferred 615 bytes in * seconds (*) (glob)
+ searching for changes
+ no changes found
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd stream2
+ $ hg book
+ mybook 0:1160648e36ce
+ $ cd ..
+ $ rm -rf local-stream stream2
+
+clone remote via pull
+
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 3 changesets with 2 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+verify
+
+ $ cd local
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 3 changesets, 2 total revisions
+ $ echo '[hooks]' >> .hg/hgrc
+ $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
+
+empty default pull
+
+ $ hg paths
+ default = ssh://user@dummy/remote
+ $ hg pull -e "python \"$TESTDIR/dummyssh\""
+ pulling from ssh://user@dummy/remote
+ searching for changes
+ no changes found
+
+pull from wrong ssh URL
+
+ $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
+ pulling from ssh://user@dummy/doesnotexist
+ remote: abort: there is no Mercurial repository here (.hg not found)!
+ abort: no suitable response from remote hg!
+ [255]
+
+local change
+
+ $ echo bleah > foo
+ $ hg ci -m "add"
+
+updating rc
+
+ $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
+ $ echo "[ui]" >> .hg/hgrc
+ $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
+
+find outgoing
+
+ $ hg out ssh://user@dummy/remote
+ comparing with ssh://user@dummy/remote
+ searching for changes
+ changeset: 3:a28a9d1a809c
+ tag: tip
+ parent: 0:1160648e36ce
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add
+
+
+find incoming on the remote side
+
+ $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
+ comparing with ssh://user@dummy/local
+ searching for changes
+ changeset: 3:a28a9d1a809c
+ tag: tip
+ parent: 0:1160648e36ce
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add
+
+
+find incoming on the remote side (using absolute path)
+
+ $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
+ comparing with ssh://user@dummy/$TESTTMP/local
+ searching for changes
+ changeset: 3:a28a9d1a809c
+ tag: tip
+ parent: 0:1160648e36ce
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add
+
+
+push
+
+ $ hg push
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ $ cd ../remote
+
+check remote tip
+
+ $ hg tip
+ changeset: 3:a28a9d1a809c
+ tag: tip
+ parent: 0:1160648e36ce
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: add
+
+ $ hg verify
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 2 files, 4 changesets, 3 total revisions
+ $ hg cat -r tip foo
+ bleah
+ $ echo z > z
+ $ hg ci -A -m z z
+ created new head
+
+test pushkeys and bookmarks
+
+ $ cd ../local
+ $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
+ bookmarks
+ namespaces
+ phases
+ $ hg book foo -r 0
+ $ hg out -B
+ comparing with ssh://user@dummy/remote
+ searching for changed bookmarks
+ foo 1160648e36ce
+ $ hg push -B foo
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ no changes found
+ exporting bookmark foo
+ [1]
+ $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
+ foo 1160648e36cec0054048a7edc4110c6f84fde594
+ $ hg book -f foo
+ $ hg push --traceback
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ no changes found
+ updating bookmark foo
+ [1]
+ $ hg book -d foo
+ $ hg in -B
+ comparing with ssh://user@dummy/remote
+ searching for changed bookmarks
+ foo a28a9d1a809c
+ $ hg book -f -r 0 foo
+ $ hg pull -B foo
+ pulling from ssh://user@dummy/remote
+ no changes found
+ updating bookmark foo
+ $ hg book -d foo
+ $ hg push -B foo
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ no changes found
+ deleting remote bookmark foo
+ [1]
+
+a bad, evil hook that prints to stdout
+
+ $ cat <<EOF > $TESTTMP/badhook
+ > import sys
+ > sys.stdout.write("KABOOM\n")
+ > EOF
+
+ $ echo '[hooks]' >> ../remote/.hg/hgrc
+ $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
+ $ echo r > r
+ $ hg ci -A -m z r
+
+push should succeed even though it has an unexpected response
+
+ $ hg push
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ remote has heads on branch 'default' that are not known locally: 6c0482d977a3
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: KABOOM
+ $ hg -R ../remote heads
+ changeset: 5:1383141674ec
+ tag: tip
+ parent: 3:a28a9d1a809c
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: z
+
+ changeset: 4:6c0482d977a3
+ parent: 0:1160648e36ce
+ user: test
+ date: Thu Jan 01 00:00:00 1970 +0000
+ summary: z
+
+
+clone bookmarks
+
+ $ hg -R ../remote bookmark test
+ $ hg -R ../remote bookmarks
+ * test 4:6c0482d977a3
+ $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 5 changes to 4 files (+1 heads)
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg -R local-bookmarks bookmarks
+ test 4:6c0482d977a3
+
+passwords in ssh urls are not supported
+(we use a glob here because different Python versions give different
+results here)
+
+ $ hg push ssh://user:erroneouspwd@dummy/remote
+ pushing to ssh://user:*@dummy/remote (glob)
+ abort: password in URL not supported!
+ [255]
+
+ $ cd ..
+
+hide outer repo
+ $ hg init
+
+Test remote paths with spaces (issue2983):
+
+ $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
+ $ touch "$TESTTMP/a repo/test"
+ $ hg -R 'a repo' commit -A -m "test"
+ adding test
+ $ hg -R 'a repo' tag tag
+ $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
+ 73649e48688a
+
+ $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
+ abort: unknown revision 'noNoNO'!
+ [255]
+
+Test (non-)escaping of remote paths with spaces when cloning (issue3145):
+
+ $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
+ destination directory: a repo
+ abort: destination 'a repo' is not empty
+ [255]
+
+Test hg-ssh using a helper script that will restore PYTHONPATH (which might
+have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
+parameters:
+
+ $ cat > ssh.sh << EOF
+ > userhost="\$1"
+ > SSH_ORIGINAL_COMMAND="\$2"
+ > export SSH_ORIGINAL_COMMAND
+ > PYTHONPATH="$PYTHONPATH"
+ > export PYTHONPATH
+ > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
+ > EOF
+
+ $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
+ 73649e48688a
+
+ $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
+ remote: Illegal repository "$TESTTMP/a'repo" (glob)
+ abort: no suitable response from remote hg!
+ [255]
+
+ $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
+ remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
+ abort: no suitable response from remote hg!
+ [255]
+
+ $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
+ Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
+ [255]
+
+Test hg-ssh in read-only mode:
+
+ $ cat > ssh.sh << EOF
+ > userhost="\$1"
+ > SSH_ORIGINAL_COMMAND="\$2"
+ > export SSH_ORIGINAL_COMMAND
+ > PYTHONPATH="$PYTHONPATH"
+ > export PYTHONPATH
+ > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
+ > EOF
+
+ $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 6 changesets with 5 changes to 4 files (+1 heads)
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+ $ cd read-only-local
+ $ echo "baz" > bar
+ $ hg ci -A -m "unpushable commit" bar
+ $ hg push --ssh "sh ../ssh.sh"
+ pushing to ssh://user@dummy/*/remote (glob)
+ searching for changes
+ remote: Permission denied
+ remote: abort: pretxnopen.hg-ssh hook failed
+ remote: Permission denied
+ remote: pushkey-abort: prepushkey.hg-ssh hook failed
+ updating 6c0482d977a3 to public failed!
+ [1]
+
+ $ cd ..
+
+stderr from remote commands should be printed before stdout from local code (issue4336)
+
+ $ hg clone remote stderr-ordering
+ updating to branch default
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd stderr-ordering
+ $ cat >> localwrite.py << EOF
+ > from mercurial import exchange, extensions
+ >
+ > def wrappedpush(orig, repo, *args, **kwargs):
+ > res = orig(repo, *args, **kwargs)
+ > repo.ui.write('local stdout\n')
+ > return res
+ >
+ > def extsetup(ui):
+ > extensions.wrapfunction(exchange, 'push', wrappedpush)
+ > EOF
+
+ $ cat >> .hg/hgrc << EOF
+ > [paths]
+ > default-push = ssh://user@dummy/remote
+ > [ui]
+ > ssh = python "$TESTDIR/dummyssh"
+ > [extensions]
+ > localwrite = localwrite.py
+ > EOF
+
+ $ echo localwrite > foo
+ $ hg commit -m 'testing localwrite'
+ $ hg push
+ pushing to ssh://user@dummy/remote
+ searching for changes
+ remote: adding changesets
+ remote: adding manifests
+ remote: adding file changes
+ remote: added 1 changesets with 1 changes to 1 files
+ remote: KABOOM
+ local stdout
+
+debug output
+
+ $ hg pull --debug ssh://user@dummy/remote
+ pulling from ssh://user@dummy/remote
+ running python ".*/dummyssh" user@dummy ('|")hg -R remote serve --stdio('|") (re)
+ sending hello command
+ sending between command
+ remote: 345
+ remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
+ remote: 1
+ preparing listkeys for "bookmarks"
+ sending listkeys command
+ received listkey for "bookmarks": 45 bytes
+ query 1; heads
+ sending batch command
+ searching for changes
+ all remote heads known locally
+ no changes found
+ preparing listkeys for "phases"
+ sending listkeys command
+ received listkey for "phases": 15 bytes
+ checking for updated bookmarks
+
+ $ cd ..
+
+ $ cat dummylog
+ Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
+ Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R local serve --stdio
+ Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ Got arguments 1:user@dummy 2:hg init 'a repo'
+ Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
+ Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
+ Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
+ Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
+ changegroup-in-remote hook: HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
--- a/tests/test-ssh.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-ssh.t Mon Jun 15 13:31:22 2015 -0500
@@ -1,4 +1,3 @@
-
This test tries to exercise the ssh functionality with a dummy script
@@ -28,7 +27,7 @@
> uncompressed = True
>
> [hooks]
- > changegroup = python "$TESTDIR/printenv.py" changegroup-in-remote 0 ../dummylog
+ > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
> EOF
$ cd ..
@@ -105,7 +104,7 @@
checking files
2 files, 3 changesets, 2 total revisions
$ echo '[hooks]' >> .hg/hgrc
- $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup-in-local 0 ../dummylog" >> .hg/hgrc
+ $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
empty default pull
@@ -398,11 +397,8 @@
pushing to ssh://user@dummy/*/remote (glob)
searching for changes
remote: Permission denied
- remote: abort: prechangegroup.hg-ssh hook failed
- remote: Permission denied
- remote: pushkey-abort: prepushkey.hg-ssh hook failed
- updating 6c0482d977a3 to public failed!
- [1]
+ abort: pretxnopen.hg-ssh hook failed
+ [255]
$ cd ..
@@ -445,6 +441,32 @@
remote: KABOOM
local stdout
+debug output
+
+ $ hg pull --debug ssh://user@dummy/remote
+ pulling from ssh://user@dummy/remote
+ running python ".*/dummyssh" user@dummy ('|")hg -R remote serve --stdio('|") (re)
+ sending hello command
+ sending between command
+ remote: 345
+ remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
+ remote: 1
+ query 1; heads
+ sending batch command
+ searching for changes
+ all remote heads known locally
+ no changes found
+ sending getbundle command
+ bundle2-input-bundle: with-transaction
+ bundle2-input-part: "listkeys" (params: 1 mandatory) supported
+ bundle2-input-part: "listkeys" (params: 1 mandatory) supported
+ bundle2-input-part: total payload size 45
+ bundle2-input-bundle: 1 parts total
+ checking for updated bookmarks
+ preparing listkeys for "phases"
+ sending listkeys command
+ received listkey for "phases": 15 bytes
+
$ cd ..
$ cat dummylog
@@ -459,7 +481,7 @@
Got arguments 1:user@dummy 2:hg -R local serve --stdio
Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
- changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
+ changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
@@ -469,7 +491,7 @@
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
- changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
+ changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
Got arguments 1:user@dummy 2:hg init 'a repo'
Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
@@ -477,4 +499,5 @@
Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
Got arguments 1:user@dummy 2:hg -R remote serve --stdio
- changegroup-in-remote hook: HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
+ changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
+ Got arguments 1:user@dummy 2:hg -R remote serve --stdio
--- a/tests/test-static-http.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-static-http.t Mon Jun 15 13:31:22 2015 -0500
@@ -60,7 +60,7 @@
$ rm .hg/cache/*
$ cd ../local
$ echo '[hooks]' >> .hg/hgrc
- $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
+ $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
$ hg pull
pulling from static-http://localhost:$HGPORT/remote
searching for changes
@@ -159,4 +159,4 @@
$ hg clone static-http://localhost:$HGPORT/notarepo local3
abort: 'http://localhost:$HGPORT/notarepo' does not appear to be an hg repository!
[255]
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
--- a/tests/test-status.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-status.t Mon Jun 15 13:31:22 2015 -0500
@@ -212,6 +212,33 @@
$ mkdir ignoreddir
$ touch ignoreddir/file
+Test templater support:
+
+ $ hg status -AT "[{status}]\t{if(copy, '{copy} -> ')}{path}\n"
+ [M] .hgignore
+ [A] added
+ [A] modified -> copied
+ [R] removed
+ [!] deleted
+ [?] ignored
+ [?] unknown
+ [I] ignoreddir/file
+ [C] modified
+ $ hg status -AT default
+ M .hgignore
+ A added
+ A copied
+ modified
+ R removed
+ ! deleted
+ ? ignored
+ ? unknown
+ I ignoreddir/file
+ C modified
+ $ hg status -T compact
+ abort: "status" not in template map
+ [255]
+
hg status ignoreddir/file:
$ hg status ignoreddir/file
--- a/tests/test-strip.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-strip.t Mon Jun 15 13:31:22 2015 -0500
@@ -526,6 +526,7 @@
branch: default
commit: 1 modified, 1 unknown, 1 unresolved
update: (current)
+ phases: 2 draft
mq: 3 unapplied
$ echo c > b
@@ -553,6 +554,7 @@
branch: default
commit: 1 modified, 1 unknown
update: (current)
+ phases: 1 draft
mq: 3 unapplied
Strip adds, removes, modifies with --keep
--- a/tests/test-subrepo-deep-nested-change.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-subrepo-deep-nested-change.t Mon Jun 15 13:31:22 2015 -0500
@@ -209,6 +209,41 @@
sub1/sub2/folder/bar (glob)
sub1/sub2/x.txt (glob)
+ $ hg files -S "set:eol('dos') or eol('unix') or size('<= 0')"
+ .hgsub
+ .hgsubstate
+ foo/bar/abc (glob)
+ main
+ sub1/.hgsub (glob)
+ sub1/.hgsubstate (glob)
+ sub1/foo (glob)
+ sub1/sub1 (glob)
+ sub1/sub2/folder/bar (glob)
+ sub1/sub2/x.txt (glob)
+
+ $ hg files -r '.^' -S "set:eol('dos') or eol('unix')"
+ .hgsub
+ .hgsubstate
+ main
+ sub1/.hgsub (glob)
+ sub1/.hgsubstate (glob)
+ sub1/sub1 (glob)
+ sub1/sub2/folder/test.txt (glob)
+ sub1/sub2/sub2 (glob)
+ sub1/sub2/test.txt (glob)
+
+ $ hg files sub1
+ sub1/.hgsub (glob)
+ sub1/.hgsubstate (glob)
+ sub1/foo (glob)
+ sub1/sub1 (glob)
+ sub1/sub2/folder/bar (glob)
+ sub1/sub2/x.txt (glob)
+
+ $ hg files sub1/sub2
+ sub1/sub2/folder/bar (glob)
+ sub1/sub2/x.txt (glob)
+
$ hg files -S -r '.^' sub1/sub2/folder
sub1/sub2/folder/test.txt (glob)
@@ -216,7 +251,7 @@
sub1/sub2/missing: no such file in rev 78026e779ea6 (glob)
[1]
- $ hg files -S -r '.^' sub1/
+ $ hg files -r '.^' sub1/
sub1/.hgsub (glob)
sub1/.hgsubstate (glob)
sub1/sub1 (glob)
@@ -224,7 +259,7 @@
sub1/sub2/sub2 (glob)
sub1/sub2/test.txt (glob)
- $ hg files -S -r '.^' sub1/sub2
+ $ hg files -r '.^' sub1/sub2
sub1/sub2/folder/test.txt (glob)
sub1/sub2/sub2 (glob)
sub1/sub2/test.txt (glob)
@@ -329,17 +364,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 Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-subrepo-git.t Mon Jun 15 13:31:22 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 Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-subrepo-recursion.t Mon Jun 15 13:31:22 2015 -0500
@@ -258,6 +258,7 @@
> [extensions]
> progress =
> [progress]
+ > disable=False
> assume-tty = 1
> delay = 0
> # set changedelay really large so we don't see nested topics
@@ -273,28 +274,18 @@
$ hg archive --subrepos ../archive
\r (no-eol) (esc)
archiving [ ] 0/3\r (no-eol) (esc)
- archiving [ ] 0/3\r (no-eol) (esc)
- archiving [=============> ] 1/3\r (no-eol) (esc)
archiving [=============> ] 1/3\r (no-eol) (esc)
archiving [===========================> ] 2/3\r (no-eol) (esc)
- archiving [===========================> ] 2/3\r (no-eol) (esc)
- archiving [==========================================>] 3/3\r (no-eol) (esc)
archiving [==========================================>] 3/3\r (no-eol) (esc)
\r (no-eol) (esc)
\r (no-eol) (esc)
archiving (foo) [ ] 0/3\r (no-eol) (esc)
- archiving (foo) [ ] 0/3\r (no-eol) (esc)
- archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
- archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
- archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
\r (no-eol) (esc)
\r (no-eol) (esc)
archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
- archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
- archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
\r (no-eol) (esc)
$ find ../archive | sort
@@ -312,34 +303,41 @@
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)
archiving [=============> ] 1/3\r (no-eol) (esc)
- archiving [=============> ] 1/3\r (no-eol) (esc)
archiving [===========================> ] 2/3\r (no-eol) (esc)
- archiving [===========================> ] 2/3\r (no-eol) (esc)
- archiving [==========================================>] 3/3\r (no-eol) (esc)
archiving [==========================================>] 3/3\r (no-eol) (esc)
\r (no-eol) (esc)
\r (no-eol) (esc)
archiving (foo) [ ] 0/3\r (no-eol) (esc)
- archiving (foo) [ ] 0/3\r (no-eol) (esc)
- archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
- archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
- archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
\r (no-eol) (esc)
\r (no-eol) (esc)
archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
- archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
- archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
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,15 +361,11 @@
$ 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)
archiving [=============> ] 1/3\r (no-eol) (esc)
- archiving [=============> ] 1/3\r (no-eol) (esc)
archiving [===========================> ] 2/3\r (no-eol) (esc)
- archiving [===========================> ] 2/3\r (no-eol) (esc)
- archiving [==========================================>] 3/3\r (no-eol) (esc)
archiving [==========================================>] 3/3\r (no-eol) (esc)
\r (no-eol) (esc)
\r (no-eol) (esc)
@@ -386,12 +380,8 @@
\r (no-eol) (esc)
\r (no-eol) (esc)
archiving (foo) [ ] 0/3\r (no-eol) (esc)
- archiving (foo) [ ] 0/3\r (no-eol) (esc)
- archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
archiving (foo) [===========> ] 1/3\r (no-eol) (esc)
archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
- archiving (foo) [=======================> ] 2/3\r (no-eol) (esc)
- archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
archiving (foo) [====================================>] 3/3\r (no-eol) (esc)
\r (no-eol) (esc)
\r (no-eol) (esc)
@@ -404,8 +394,6 @@
\r (no-eol) (esc)
\r (no-eol) (esc)
archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
- archiving (foo/bar) [ ] 0/1\r (no-eol) (glob) (esc)
- archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
archiving (foo/bar) [================================>] 1/1\r (no-eol) (glob) (esc)
\r (no-eol) (esc)
cloning subrepo foo from $TESTTMP/repo/foo
@@ -413,23 +401,17 @@
#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)
archiving [=============> ] 1/3\r (no-eol) (esc)
- archiving [=============> ] 1/3\r (no-eol) (esc)
archiving [===========================> ] 2/3\r (no-eol) (esc)
- archiving [===========================> ] 2/3\r (no-eol) (esc)
- archiving [==========================================>] 3/3\r (no-eol) (esc)
archiving [==========================================>] 3/3\r (no-eol) (esc)
\r (no-eol) (esc)
\r (no-eol) (esc)
linking [ <=> ] 1\r (no-eol) (esc)
\r (no-eol) (esc)
\r (no-eol) (esc)
- \r (no-eol) (esc)
- \r (no-eol) (esc)
linking [ <=> ] 1cloning subrepo foo from $TESTTMP/repo/foo
cloning subrepo foo/bar from $TESTTMP/repo/foo/bar (glob)
#endif
@@ -437,14 +419,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:
--- a/tests/test-subrepo-relative-path.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-subrepo-relative-path.t Mon Jun 15 13:31:22 2015 -0500
@@ -70,7 +70,7 @@
source ../sub
revision 863c1745b441bd97a8c4a096e87793073f4fb215
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
subrepo paths with ssh urls
--- a/tests/test-subrepo-svn.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-subrepo-svn.t Mon Jun 15 13:31:22 2015 -0500
@@ -72,6 +72,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 2 draft
$ hg ci -moops
nothing changed
[1]
@@ -96,6 +97,7 @@
branch: default
commit: 1 modified, 1 subrepos
update: (current)
+ phases: 2 draft
$ hg commit --subrepos -m 'Message!' | grep -v Updating
committing subrepository s
Sending*s/alpha (glob)
@@ -136,6 +138,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 3 draft
$ echo a > s/a
@@ -548,7 +551,7 @@
Test archive
- $ hg archive -S ../archive-all --debug
+ $ hg archive -S ../archive-all --debug --config progress.debug=true
archiving: 0/2 files (0.00%)
archiving: .hgsub 1/2 files (50.00%)
archiving: .hgsubstate 2/2 files (100.00%)
@@ -560,7 +563,7 @@
archiving (s): 1/2 files (50.00%)
archiving (s): 2/2 files (100.00%)
- $ hg archive -S ../archive-exclude --debug -X **old
+ $ hg archive -S ../archive-exclude --debug --config progress.debug=true -X **old
archiving: 0/2 files (0.00%)
archiving: .hgsub 1/2 files (50.00%)
archiving: .hgsubstate 2/2 files (100.00%)
--- a/tests/test-subrepo.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-subrepo.t Mon Jun 15 13:31:22 2015 -0500
@@ -38,6 +38,7 @@
branch: default
commit: 1 added, 1 subrepos
update: (current)
+ phases: 1 draft
$ hg ci -m1
test handling .hgsubstate "added" explicitly.
@@ -83,6 +84,7 @@
branch: default
commit: 1 subrepos
update: (current)
+ phases: 2 draft
$ hg co -C 1
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg sum
@@ -91,6 +93,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 2 draft
commands that require a clean repo should respect subrepos
@@ -113,6 +116,7 @@
branch: default
commit: 1 subrepos
update: (current)
+ phases: 2 draft
$ hg ci -m2
committing subrepository s
committing subrepository s/ss (glob)
@@ -122,6 +126,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 3 draft
test handling .hgsubstate "modified" explicitly.
@@ -255,7 +260,6 @@
branchmerge: True, force: False, partial: False
ancestor: 1f14a2e2d3ec, local: f0d2028bf86d+, remote: 1831e14459c4
.hgsubstate: versions differ -> m
- updating: .hgsubstate 1/1 files (100.00%)
subrepo merge f0d2028bf86d+ 1831e14459c4 1f14a2e2d3ec
subrepo t: other changed, get t:6747d179aa9a688023c4b0cad32e4c92bb7f34ad:hg
getting subrepo t
@@ -264,7 +268,6 @@
ancestor: 60ca1237c194, local: 60ca1237c194+, remote: 6747d179aa9a
t: remote is newer -> g
getting t
- updating: t 1/1 files (100.00%)
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg debugsub
@@ -283,7 +286,6 @@
branchmerge: True, force: False, partial: False
ancestor: 1831e14459c4, local: e45c8b14af55+, remote: f94576341bcf
.hgsubstate: versions differ -> m
- updating: .hgsubstate 1/1 files (100.00%)
subrepo merge e45c8b14af55+ f94576341bcf 1831e14459c4
subrepo t: both sides changed
subrepository t diverged (local revision: 20a0db6fbf6c, remote revision: 7af322bc1198)
@@ -295,7 +297,6 @@
ancestor: 6747d179aa9a, local: 20a0db6fbf6c+, remote: 7af322bc1198
preserving t for resolve of t
t: versions differ -> m
- updating: t 1/1 files (100.00%)
picked tool 'internal:merge' for t (binary False symlink False)
merging t
my t@20a0db6fbf6c+ other t@7af322bc1198 ancestor t@6747d179aa9a
@@ -1489,7 +1490,17 @@
> [paths]
> default=../issue3781-dest/
> EOF
- $ hg push
+ $ hg push --config experimental.bundle2-exp=False
+ pushing to $TESTTMP/issue3781-dest (glob)
+ pushing subrepo s to $TESTTMP/issue3781-dest/s
+ searching for changes
+ no changes found
+ searching for changes
+ no changes found
+ [1]
+# clean the push cache
+ $ rm s/.hg/cache/storehash/*
+ $ hg push --config experimental.bundle2-exp=True
pushing to $TESTTMP/issue3781-dest (glob)
pushing subrepo s to $TESTTMP/issue3781-dest/s
searching for changes
@@ -1692,4 +1703,37 @@
[paths]
default = $TESTTMP/t/t
default-push = /foo/bar/t
+
+ $ cd $TESTTMP/t
+ $ hg up -qC 0
+ $ echo 'bar' > bar.txt
+ $ hg ci -Am 'branch before subrepo add'
+ adding bar.txt
+ created new head
+ $ hg merge -r "first(subrepo('s'))"
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg status -S -X '.hgsub*'
+ A s/a
+ ? s/b
+ ? s/c
+ ? s/f1
+ $ hg status -S --rev 'p2()'
+ A bar.txt
+ ? s/b
+ ? s/c
+ ? s/f1
+ $ hg diff -S -X '.hgsub*' --nodates
+ diff -r 000000000000 s/a
+ --- /dev/null
+ +++ b/s/a
+ @@ -0,0 +1,1 @@
+ +a
+ $ hg diff -S --rev 'p2()' --nodates
+ diff -r 7cf8cfea66e4 bar.txt
+ --- /dev/null
+ +++ b/bar.txt
+ @@ -0,0 +1,1 @@
+ +bar
+
$ cd ..
--- a/tests/test-symlinks.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-symlinks.t Mon Jun 15 13:31:22 2015 -0500
@@ -214,13 +214,13 @@
$ hg manifest --debug
2564acbe54bbbedfbf608479340b359f04597f80 644 @ dangling
- $ "$TESTDIR/readlink.py" dangling
+ $ readlink.py dangling
dangling -> nothing
$ rm dangling
$ ln -s void dangling
$ hg commit -m 'change symlink'
- $ "$TESTDIR/readlink.py" dangling
+ $ readlink.py dangling
dangling -> void
@@ -228,7 +228,7 @@
$ rm dangling
$ ln -s empty dangling
- $ "$TESTDIR/readlink.py" dangling
+ $ readlink.py dangling
dangling -> empty
@@ -236,13 +236,13 @@
$ hg revert -r 0 -a
reverting dangling
- $ "$TESTDIR/readlink.py" dangling
+ $ readlink.py dangling
dangling -> nothing
backups:
- $ "$TESTDIR/readlink.py" *.orig
+ $ readlink.py *.orig
dangling.orig -> empty
$ rm *.orig
$ hg up -C
@@ -255,7 +255,7 @@
$ hg st -Cmard
A dangling2
dangling
- $ "$TESTDIR/readlink.py" dangling dangling2
+ $ readlink.py dangling dangling2
dangling -> void
dangling2 -> void
--- a/tests/test-tags.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-tags.t Mon Jun 15 13:31:22 2015 -0500
@@ -625,3 +625,77 @@
globaltag 0:bbd179dfa0a7
$ cd ..
+
+Create a repository with tags data to test .hgtags fnodes transfer
+
+ $ hg init tagsserver
+ $ cd tagsserver
+ $ cat > .hg/hgrc << EOF
+ > [experimental]
+ > bundle2-exp=True
+ > EOF
+ $ touch foo
+ $ hg -q commit -A -m initial
+ $ hg tag -m 'tag 0.1' 0.1
+ $ echo second > foo
+ $ hg commit -m second
+ $ hg tag -m 'tag 0.2' 0.2
+ $ hg tags
+ tip 3:40f0358cb314
+ 0.2 2:f63cc8fe54e4
+ 0.1 0:96ee1d7354c4
+ $ cd ..
+
+Cloning should pull down hgtags fnodes mappings and write the cache file
+
+ $ hg --config experimental.bundle2-exp=True clone --pull tagsserver tagsclient
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 4 changes to 2 files
+ updating to branch default
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Missing tags2* files means the cache wasn't written through the normal mechanism.
+
+ $ ls tagsclient/.hg/cache
+ branch2-served
+ hgtagsfnodes1
+ rbc-names-v1
+ rbc-revs-v1
+
+Cache should contain the head only, even though other nodes have tags data
+
+ $ f --size --hexdump tagsclient/.hg/cache/hgtagsfnodes1
+ tagsclient/.hg/cache/hgtagsfnodes1: size=96
+ 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+ 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+ 0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+ 0030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+ 0040: ff ff ff ff ff ff ff ff 40 f0 35 8c 19 e0 a7 d3 |........@.5.....|
+ 0050: 8a 5c 6a 82 4d cf fb a5 87 d0 2f a3 1e 4f 2f 8a |.\j.M...../..O/.|
+
+Running hg tags should produce tags2* file and not change cache
+
+ $ hg -R tagsclient tags
+ tip 3:40f0358cb314
+ 0.2 2:f63cc8fe54e4
+ 0.1 0:96ee1d7354c4
+
+ $ ls tagsclient/.hg/cache
+ branch2-served
+ hgtagsfnodes1
+ rbc-names-v1
+ rbc-revs-v1
+ tags2-visible
+
+ $ f --size --hexdump tagsclient/.hg/cache/hgtagsfnodes1
+ tagsclient/.hg/cache/hgtagsfnodes1: size=96
+ 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+ 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+ 0020: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+ 0030: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
+ 0040: ff ff ff ff ff ff ff ff 40 f0 35 8c 19 e0 a7 d3 |........@.5.....|
+ 0050: 8a 5c 6a 82 4d cf fb a5 87 d0 2f a3 1e 4f 2f 8a |.\j.M...../..O/.|
+
--- a/tests/test-transplant.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-transplant.t Mon Jun 15 13:31:22 2015 -0500
@@ -788,5 +788,5 @@
Explicitly kill daemons to let the test exit on Windows
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
--- a/tests/test-treediscovery-legacy.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-treediscovery-legacy.t Mon Jun 15 13:31:22 2015 -0500
@@ -8,7 +8,7 @@
> EOF
$ cp $HGRCPATH $HGRCPATH-withcap
- $ CAP="getbundle known changegroupsubset"
+ $ CAP="getbundle known changegroupsubset bundle2"
$ . "$TESTDIR/notcapable"
$ cp $HGRCPATH $HGRCPATH-nocap
$ cp $HGRCPATH-withcap $HGRCPATH
@@ -33,7 +33,7 @@
> cat hg.pid >> $DAEMON_PIDS
> }
$ tstop() {
- > "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ > killdaemons.py
> cp $HGRCPATH-withcap $HGRCPATH
> }
--- a/tests/test-treediscovery.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-treediscovery.t Mon Jun 15 13:31:22 2015 -0500
@@ -2,7 +2,7 @@
Tests discovery against servers without getbundle support:
- $ CAP=getbundle
+ $ CAP="getbundle bundle2"
$ . "$TESTDIR/notcapable"
$ cat >> $HGRCPATH <<EOF
> [ui]
@@ -21,7 +21,7 @@
> cat hg.pid >> $DAEMON_PIDS
> }
$ tstop() {
- > "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ > killdaemons.py
> [ "$1" ] && cut -d' ' -f6- access.log && cat errors.log
> rm access.log errors.log
> }
@@ -516,7 +516,6 @@
"GET /?cmd=between HTTP/1.1" 200 - x-hgarg-1:pairs=d8f638ac69e9ae8dea4f09f11d696546a912d961-d57206cc072a18317c1e381fb60aa31bd3401785
"GET /?cmd=capabilities HTTP/1.1" 200 -
"GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
- "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
"GET /?cmd=heads HTTP/1.1" 200 -
"GET /?cmd=branches HTTP/1.1" 200 - x-hgarg-1:nodes=d8f638ac69e9ae8dea4f09f11d696546a912d961
"GET /?cmd=between HTTP/1.1" 200 - x-hgarg-1:pairs=d8f638ac69e9ae8dea4f09f11d696546a912d961-d57206cc072a18317c1e381fb60aa31bd3401785
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-treemanifest.t Mon Jun 15 13:31:22 2015 -0500
@@ -0,0 +1,386 @@
+
+Set up repo
+
+ $ hg --config experimental.treemanifest=True init repo
+ $ cd repo
+
+Requirements get set on init
+
+ $ grep treemanifest .hg/requires
+ treemanifest
+
+Without directories, looks like any other repo
+
+ $ echo 0 > a
+ $ echo 0 > b
+ $ hg ci -Aqm initial
+ $ hg debugdata -m 0
+ a\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
+ b\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
+
+Submanifest is stored in separate revlog
+
+ $ mkdir dir1
+ $ echo 1 > dir1/a
+ $ echo 1 > dir1/b
+ $ echo 1 > e
+ $ hg ci -Aqm 'add dir1'
+ $ hg debugdata -m 1
+ a\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
+ b\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (esc)
+ dir1\x008b3ffd73f901e83304c83d33132c8e774ceac44ed (esc)
+ e\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
+ $ hg debugdata --dir dir1 0
+ a\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
+ b\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
+
+Can add nested directories
+
+ $ mkdir dir1/dir1
+ $ echo 2 > dir1/dir1/a
+ $ echo 2 > dir1/dir1/b
+ $ mkdir dir1/dir2
+ $ echo 2 > dir1/dir2/a
+ $ echo 2 > dir1/dir2/b
+ $ hg ci -Aqm 'add dir1/dir1'
+ $ hg files -r .
+ a
+ b
+ dir1/a (glob)
+ dir1/b (glob)
+ dir1/dir1/a (glob)
+ dir1/dir1/b (glob)
+ dir1/dir2/a (glob)
+ dir1/dir2/b (glob)
+ e
+
+Revision is not created for unchanged directory
+
+ $ mkdir dir2
+ $ echo 3 > dir2/a
+ $ hg add dir2
+ adding dir2/a (glob)
+ $ hg debugindex --dir dir1 > before
+ $ hg ci -qm 'add dir2'
+ $ hg debugindex --dir dir1 > after
+ $ diff before after
+ $ rm before after
+
+Removing directory does not create an revlog entry
+
+ $ hg rm dir1/dir1
+ removing dir1/dir1/a (glob)
+ removing dir1/dir1/b (glob)
+ $ hg debugindex --dir dir1/dir1 > before
+ $ hg ci -qm 'remove dir1/dir1'
+ $ hg debugindex --dir dir1/dir1 > after
+ $ diff before after
+ $ rm before after
+
+Check that hg files (calls treemanifest.walk()) works
+without loading all directory revlogs
+
+ $ hg co 'desc("add dir2")'
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ mv .hg/store/meta/dir2 .hg/store/meta/dir2-backup
+ $ hg files -r . dir1
+ dir1/a (glob)
+ dir1/b (glob)
+ dir1/dir1/a (glob)
+ dir1/dir1/b (glob)
+ dir1/dir2/a (glob)
+ dir1/dir2/b (glob)
+
+Check that status between revisions works (calls treemanifest.matches())
+without loading all directory revlogs
+
+ $ hg status --rev 'desc("add dir1")' --rev . dir1
+ A dir1/dir1/a
+ A dir1/dir1/b
+ A dir1/dir2/a
+ A dir1/dir2/b
+ $ mv .hg/store/meta/dir2-backup .hg/store/meta/dir2
+
+Merge creates 2-parent revision of directory revlog
+
+ $ echo 5 > dir1/a
+ $ hg ci -Aqm 'modify dir1/a'
+ $ hg co '.^'
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 6 > dir1/b
+ $ hg ci -Aqm 'modify dir1/b'
+ $ hg merge 'desc("modify dir1/a")'
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m 'conflict-free merge involving dir1/'
+ $ cat dir1/a
+ 5
+ $ cat dir1/b
+ 6
+ $ hg debugindex --dir dir1
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 54 0 1 8b3ffd73f901 000000000000 000000000000
+ 1 54 68 0 2 b66d046c644f 8b3ffd73f901 000000000000
+ 2 122 12 0 4 b87265673c8a b66d046c644f 000000000000
+ 3 134 95 0 5 aa5d3adcec72 b66d046c644f 000000000000
+ 4 229 81 0 6 e29b066b91ad b66d046c644f 000000000000
+ 5 310 107 5 7 a120ce2b83f5 e29b066b91ad aa5d3adcec72
+
+Merge keeping directory from parent 1 does not create revlog entry. (Note that
+dir1's manifest does change, but only because dir1/a's filelog changes.)
+
+ $ hg co 'desc("add dir2")'
+ 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 8 > dir2/a
+ $ hg ci -m 'modify dir2/a'
+ created new head
+
+ $ hg debugindex --dir dir2 > before
+ $ hg merge 'desc("modify dir1/a")'
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg revert -r 'desc("modify dir2/a")' .
+ reverting dir1/a (glob)
+ $ hg ci -m 'merge, keeping parent 1'
+ $ hg debugindex --dir dir2 > after
+ $ diff before after
+ $ rm before after
+
+Merge keeping directory from parent 2 does not create revlog entry. (Note that
+dir2's manifest does change, but only because dir2/a's filelog changes.)
+
+ $ hg co 'desc("modify dir2/a")'
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg debugindex --dir dir1 > before
+ $ hg merge 'desc("modify dir1/a")'
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg revert -r 'desc("modify dir1/a")' .
+ reverting dir2/a (glob)
+ $ hg ci -m 'merge, keeping parent 2'
+ created new head
+ $ hg debugindex --dir dir1 > after
+ $ diff before after
+ $ rm before after
+
+Create flat source repo for tests with mixed flat/tree manifests
+
+ $ cd ..
+ $ hg init repo-flat
+ $ cd repo-flat
+
+Create a few commits with flat manifest
+
+ $ echo 0 > a
+ $ echo 0 > b
+ $ echo 0 > e
+ $ for d in dir1 dir1/dir1 dir1/dir2 dir2
+ > do
+ > mkdir $d
+ > echo 0 > $d/a
+ > echo 0 > $d/b
+ > done
+ $ hg ci -Aqm initial
+
+ $ echo 1 > a
+ $ echo 1 > dir1/a
+ $ echo 1 > dir1/dir1/a
+ $ hg ci -Aqm 'modify on branch 1'
+
+ $ hg co 0
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 2 > b
+ $ echo 2 > dir1/b
+ $ echo 2 > dir1/dir1/b
+ $ hg ci -Aqm 'modify on branch 2'
+
+ $ hg merge 1
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m 'merge of flat manifests to new flat manifest'
+
+Create clone with tree manifests enabled
+
+ $ cd ..
+ $ hg clone --pull --config experimental.treemanifest=1 repo-flat repo-mixed
+ requesting all changes
+ adding changesets
+ adding manifests
+ adding file changes
+ added 4 changesets with 17 changes to 11 files
+ updating to branch default
+ 11 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ cd repo-mixed
+ $ test -f .hg/store/meta
+ [1]
+ $ grep treemanifest .hg/requires
+ treemanifest
+
+Commit should store revlog per directory
+
+ $ hg co 1
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ echo 3 > a
+ $ echo 3 > dir1/a
+ $ echo 3 > dir1/dir1/a
+ $ hg ci -m 'first tree'
+ created new head
+ $ find .hg/store/meta | sort
+ .hg/store/meta
+ .hg/store/meta/dir1
+ .hg/store/meta/dir1/00manifest.i
+ .hg/store/meta/dir1/dir1
+ .hg/store/meta/dir1/dir1/00manifest.i
+ .hg/store/meta/dir1/dir2
+ .hg/store/meta/dir1/dir2/00manifest.i
+ .hg/store/meta/dir2
+ .hg/store/meta/dir2/00manifest.i
+
+Merge of two trees
+
+ $ hg co 2
+ 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ $ hg merge 1
+ 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ (branch merge, don't forget to commit)
+ $ hg ci -m 'merge of flat manifests to new tree manifest'
+ created new head
+ $ hg diff -r 3
+
+Parent of tree root manifest should be flat manifest, and two for merge
+
+ $ hg debugindex -m
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 80 0 0 40536115ed9e 000000000000 000000000000
+ 1 80 83 0 1 f3376063c255 40536115ed9e 000000000000
+ 2 163 103 0 2 5d9b9da231a2 40536115ed9e 000000000000
+ 3 266 83 0 3 d17d663cbd8a 5d9b9da231a2 f3376063c255
+ 4 349 132 4 4 c05a51345f86 f3376063c255 000000000000
+ 5 481 110 4 5 82594b1f557d 5d9b9da231a2 f3376063c255
+
+
+Status across flat/tree boundary should work
+
+ $ hg status --rev '.^' --rev .
+ M a
+ M dir1/a
+ M dir1/dir1/a
+
+
+Turning off treemanifest config has no effect
+
+ $ hg debugindex .hg/store/meta/dir1/00manifest.i
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 125 0 4 63c9c0557d24 000000000000 000000000000
+ 1 125 109 0 5 23d12a1f6e0e 000000000000 000000000000
+ $ echo 2 > dir1/a
+ $ hg --config experimental.treemanifest=False ci -qm 'modify dir1/a'
+ $ hg debugindex .hg/store/meta/dir1/00manifest.i
+ rev offset length base linkrev nodeid p1 p2
+ 0 0 125 0 4 63c9c0557d24 000000000000 000000000000
+ 1 125 109 0 5 23d12a1f6e0e 000000000000 000000000000
+ 2 234 55 0 6 3cb2d87b4250 23d12a1f6e0e 000000000000
+
+Create deeper repo with tree manifests.
+
+ $ cd ..
+ $ hg --config experimental.treemanifest=True init deeprepo
+ $ cd deeprepo
+
+ $ mkdir a
+ $ mkdir b
+ $ mkdir b/bar
+ $ mkdir b/bar/orange
+ $ mkdir b/bar/orange/fly
+ $ mkdir b/foo
+ $ mkdir b/foo/apple
+ $ mkdir b/foo/apple/bees
+
+ $ touch a/one.txt
+ $ touch a/two.txt
+ $ touch b/bar/fruits.txt
+ $ touch b/bar/orange/fly/gnat.py
+ $ touch b/bar/orange/fly/housefly.txt
+ $ touch b/foo/apple/bees/flower.py
+ $ touch c.txt
+ $ touch d.py
+
+ $ hg ci -Aqm 'initial'
+
+We'll see that visitdir works by removing some treemanifest revlogs and running
+the files command with various parameters.
+
+Test files from the root.
+
+ $ hg files -r .
+ a/one.txt (glob)
+ a/two.txt (glob)
+ b/bar/fruits.txt (glob)
+ b/bar/orange/fly/gnat.py (glob)
+ b/bar/orange/fly/housefly.txt (glob)
+ b/foo/apple/bees/flower.py (glob)
+ c.txt
+ d.py
+
+Excludes with a glob should not exclude everything from the glob's root
+
+ $ hg files -r . -X 'b/fo?' b
+ b/bar/fruits.txt (glob)
+ b/bar/orange/fly/gnat.py (glob)
+ b/bar/orange/fly/housefly.txt (glob)
+
+Test files for a subdirectory.
+
+ $ mv .hg/store/meta/a oldmf
+ $ hg files -r . b
+ b/bar/fruits.txt (glob)
+ b/bar/orange/fly/gnat.py (glob)
+ b/bar/orange/fly/housefly.txt (glob)
+ b/foo/apple/bees/flower.py (glob)
+ $ mv oldmf .hg/store/meta/a
+
+Test files with just includes and excludes.
+
+ $ mv .hg/store/meta/a oldmf
+ $ mv .hg/store/meta/b/bar/orange/fly oldmf2
+ $ mv .hg/store/meta/b/foo/apple/bees oldmf3
+ $ hg files -r . -I path:b/bar -X path:b/bar/orange/fly -I path:b/foo -X path:b/foo/apple/bees
+ b/bar/fruits.txt (glob)
+ $ mv oldmf .hg/store/meta/a
+ $ mv oldmf2 .hg/store/meta/b/bar/orange/fly
+ $ mv oldmf3 .hg/store/meta/b/foo/apple/bees
+
+Test files for a subdirectory, excluding a directory within it.
+
+ $ mv .hg/store/meta/a oldmf
+ $ mv .hg/store/meta/b/foo oldmf2
+ $ hg files -r . -X path:b/foo b
+ b/bar/fruits.txt (glob)
+ b/bar/orange/fly/gnat.py (glob)
+ b/bar/orange/fly/housefly.txt (glob)
+ $ mv oldmf .hg/store/meta/a
+ $ mv oldmf2 .hg/store/meta/b/foo
+
+Test files for a sub directory, including only a directory within it, and
+including an unrelated directory.
+
+ $ mv .hg/store/meta/a oldmf
+ $ mv .hg/store/meta/b/foo oldmf2
+ $ hg files -r . -I path:b/bar/orange -I path:a b
+ b/bar/orange/fly/gnat.py (glob)
+ b/bar/orange/fly/housefly.txt (glob)
+ $ mv oldmf .hg/store/meta/a
+ $ mv oldmf2 .hg/store/meta/b/foo
+
+Test files for a pattern, including a directory, and excluding a directory
+within that.
+
+ $ mv .hg/store/meta/a oldmf
+ $ mv .hg/store/meta/b/foo oldmf2
+ $ mv .hg/store/meta/b/bar/orange oldmf3
+ $ hg files -r . glob:**.txt -I path:b/bar -X path:b/bar/orange
+ b/bar/fruits.txt (glob)
+ $ mv oldmf .hg/store/meta/a
+ $ mv oldmf2 .hg/store/meta/b/foo
+ $ mv oldmf3 .hg/store/meta/b/bar/orange
+
--- a/tests/test-unbundlehash.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-unbundlehash.t Mon Jun 15 13:31:22 2015 -0500
@@ -2,6 +2,14 @@
Test wire protocol unbundle with hashed heads (capability: unbundlehash)
+ $ cat << EOF >> $HGRCPATH
+ > [experimental]
+ > # This tests is intended for bundle1 only.
+ > # bundle2 carries the head information inside the bundle itself and
+ > # always uses 'force' as the heads value.
+ > bundle2-exp = False
+ > EOF
+
Create a remote repository.
$ hg init remote
@@ -33,5 +41,5 @@
Explicitly kill daemons to let the test exit on Windows
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py
--- a/tests/test-unified-test.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-unified-test.t Mon Jun 15 13:31:22 2015 -0500
@@ -88,14 +88,14 @@
testing hghave
- $ "$TESTDIR/hghave" true
- $ "$TESTDIR/hghave" false
+ $ hghave true
+ $ hghave false
skipped: missing feature: nail clipper
[1]
- $ "$TESTDIR/hghave" no-true
+ $ hghave no-true
skipped: system supports yak shaving
[1]
- $ "$TESTDIR/hghave" no-false
+ $ hghave no-false
Conditional sections based on hghave:
--- a/tests/test-up-local-change.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-up-local-change.t Mon Jun 15 13:31:22 2015 -0500
@@ -49,9 +49,7 @@
preserving a for resolve of a
b: remote created -> g
getting b
- updating: b 1/2 files (50.00%)
a: versions differ -> m
- updating: a 2/2 files (100.00%)
picked tool 'true' for a (binary False symlink False)
merging a
my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
@@ -72,9 +70,7 @@
preserving a for resolve of a
b: other deleted -> r
removing b
- updating: b 1/2 files (50.00%)
a: versions differ -> m
- updating: a 2/2 files (100.00%)
picked tool 'true' for a (binary False symlink False)
merging a
my a@1e71731e6fbb+ other a@c19d34741b0a ancestor a@1e71731e6fbb
@@ -103,9 +99,7 @@
preserving a for resolve of a
b: remote created -> g
getting b
- updating: b 1/2 files (50.00%)
a: versions differ -> m
- updating: a 2/2 files (100.00%)
picked tool 'true' for a (binary False symlink False)
merging a
my a@c19d34741b0a+ other a@1e71731e6fbb ancestor a@c19d34741b0a
--- a/tests/test-update-reverse.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-update-reverse.t Mon Jun 15 13:31:22 2015 -0500
@@ -72,10 +72,8 @@
removing side1
side2: other deleted -> r
removing side2
- updating: side2 2/3 files (66.67%)
main: remote created -> g
getting main
- updating: main 3/3 files (100.00%)
1 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ ls
--- a/tests/test-url-rev.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-url-rev.t Mon Jun 15 13:31:22 2015 -0500
@@ -101,6 +101,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 4 draft
remote: 2 outgoing
$ hg -q outgoing '../clone#foo'
2:faba9097cad4
@@ -110,6 +111,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 4 draft
remote: 1 outgoing
$ hg -q --cwd ../clone incoming '../repo#foo'
@@ -282,6 +284,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 1 draft
remote: 1 outgoing
$ hg summary --remote --config paths.default='../clone#foo' --config paths.default-push='../clone'
@@ -290,6 +293,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 1 draft
remote: 2 outgoing
$ hg summary --remote --config paths.default='../clone' --config paths.default-push='../clone#foo'
@@ -298,6 +302,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 1 draft
remote: 1 outgoing
$ hg clone -q -r 0 . ../another
@@ -311,6 +316,7 @@
branch: default
commit: (clean)
update: (current)
+ phases: 1 draft
remote: 1 outgoing
$ cd ..
--- a/tests/test-verify.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-verify.t Mon Jun 15 13:31:22 2015 -0500
@@ -103,7 +103,7 @@
test revlog format 0
- $ "$TESTDIR/revlog-formatv0.py"
+ $ revlog-formatv0.py
$ cd formatv0
$ hg verify
repository uses revlog format 0
--- a/tests/test-walk.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-walk.t Mon Jun 15 13:31:22 2015 -0500
@@ -170,6 +170,32 @@
f beans/black beans/black
f fenugreek fenugreek
f mammals/skunk mammals/skunk
+ $ hg debugwalk -Ibeans mammals
+ $ hg debugwalk -Inon-existent
+ $ hg debugwalk -Inon-existent -Ibeans/black
+ f beans/black beans/black
+ $ hg debugwalk -Ibeans beans/black
+ f beans/black beans/black exact
+ $ hg debugwalk -Ibeans/black beans
+ f beans/black beans/black
+ $ hg debugwalk -Xbeans/black beans
+ f beans/borlotti beans/borlotti
+ f beans/kidney beans/kidney
+ f beans/navy beans/navy
+ f beans/pinto beans/pinto
+ f beans/turtle beans/turtle
+ $ hg debugwalk -Xbeans/black -Ibeans
+ f beans/borlotti beans/borlotti
+ f beans/kidney beans/kidney
+ f beans/navy beans/navy
+ f beans/pinto beans/pinto
+ f beans/turtle beans/turtle
+ $ hg debugwalk -Xbeans/black beans/black
+ f beans/black beans/black exact
+ $ hg debugwalk -Xbeans/black -Ibeans/black
+ $ hg debugwalk -Xbeans beans/black
+ f beans/black beans/black exact
+ $ hg debugwalk -Xbeans -Ibeans/black
$ hg debugwalk 'glob:mammals/../beans/b*'
f beans/black beans/black
f beans/borlotti beans/borlotti
--- a/tests/test-websub.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-websub.t Mon Jun 15 13:31:22 2015 -0500
@@ -27,7 +27,7 @@
log
- $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT "rev/tip" | grep bts
+ $ get-with-headers.py localhost:$HGPORT "rev/tip" | grep bts
<div class="description"><a href="http://bts.example.org/issue123">Issue123</a>: fixed the <i class="x">bug</i>!</div>
errors
--- a/tests/test-wireproto.t Sat Jun 13 20:14:22 2015 +0900
+++ b/tests/test-wireproto.t Mon Jun 15 13:31:22 2015 -0500
@@ -90,29 +90,16 @@
SSH (try to exercise the ssh functionality with a dummy script):
- $ cat <<EOF > dummyssh
- > import sys
- > import os
- > os.chdir(os.path.dirname(sys.argv[0]))
- > if sys.argv[1] != "user@dummy":
- > sys.exit(-1)
- > if not os.path.exists("dummyssh"):
- > sys.exit(-1)
- > os.environ["SSH_CLIENT"] = "127.0.0.1 1 2"
- > r = os.system(sys.argv[2])
- > sys.exit(bool(r))
- > EOF
-
- $ hg debugwireargs --ssh "python ./dummyssh" ssh://user@dummy/repo uno due tre quattro
+ $ hg debugwireargs --ssh "python $TESTDIR/dummyssh" ssh://user@dummy/repo uno due tre quattro
uno due tre quattro None
- $ hg debugwireargs --ssh "python ./dummyssh" ssh://user@dummy/repo eins zwei --four vier
+ $ hg debugwireargs --ssh "python $TESTDIR/dummyssh" ssh://user@dummy/repo eins zwei --four vier
eins zwei None vier None
- $ hg debugwireargs --ssh "python ./dummyssh" ssh://user@dummy/repo eins zwei
+ $ hg debugwireargs --ssh "python $TESTDIR/dummyssh" ssh://user@dummy/repo eins zwei
eins zwei None None None
- $ hg debugwireargs --ssh "python ./dummyssh" ssh://user@dummy/repo eins zwei --five fuenf
+ $ hg debugwireargs --ssh "python $TESTDIR/dummyssh" ssh://user@dummy/repo eins zwei --five fuenf
eins zwei None None None
Explicitly kill daemons to let the test exit on Windows
- $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
+ $ killdaemons.py