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