Mercurial > hg
changeset 22560:4109cc16279e
merge with stable
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Sat, 27 Sep 2014 14:47:52 -0500 |
parents | 4e0b696a1cb3 (diff) 6e1fbcb18a75 (current diff) |
children | 1120b1e2f975 |
files | mercurial/hgweb/hgweb_mod.py tests/test-hgweb.t |
diffstat | 303 files changed, 8296 insertions(+), 2974 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Mon Sep 22 23:46:38 2014 +0900 +++ b/Makefile Sat Sep 27 14:47:52 2014 -0500 @@ -56,7 +56,8 @@ find contrib doc hgext i18n mercurial tests \ \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';' rm -f $(addprefix mercurial/,$(notdir $(wildcard mercurial/pure/[a-z]*.py))) - rm -f MANIFEST MANIFEST.in mercurial/__version__.py hgext/__index__.py tests/*.err + rm -f MANIFEST MANIFEST.in hgext/__index__.py tests/*.err + if test -d .hg; then rm -f mercurial/__version__.py; fi rm -rf build mercurial/locale $(MAKE) -C doc clean @@ -135,23 +136,34 @@ # Packaging targets osx: - @which -s bdist_mpkg || \ + @which bdist_mpkg >/dev/null || \ (echo "Missing bdist_mpkg (easy_install bdist_mpkg)"; false) + rm -rf dist/mercurial-*.mpkg bdist_mpkg setup.py mkdir -p packages/osx + 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 - mv dist/mercurial*macosx*.zip packages/osx -fedora: - mkdir -p packages/fedora +fedora20: + mkdir -p packages/fedora20 contrib/buildrpm - cp rpmbuild/RPMS/*/* packages/fedora - cp rpmbuild/SRPMS/* packages/fedora + cp rpmbuild/RPMS/*/* packages/fedora20 + cp rpmbuild/SRPMS/* packages/fedora20 rm -rf rpmbuild -docker-fedora: - mkdir -p packages/fedora - contrib/dockerrpm fedora +docker-fedora20: + mkdir -p packages/fedora20 + contrib/dockerrpm fedora20 + +centos5: + mkdir -p packages/centos5 + contrib/buildrpm --withpython + cp rpmbuild/RPMS/*/* packages/centos5 + cp rpmbuild/SRPMS/* packages/centos5 + +docker-centos5: + mkdir -p packages/centos5 + contrib/dockerrpm centos5 --withpython centos6: mkdir -p packages/centos6 @@ -165,4 +177,4 @@ .PHONY: help all local build doc clean install install-bin install-doc \ install-home install-home-bin install-home-doc dist dist-notests tests \ - update-pot fedora docker-fedora + update-pot fedora20 docker-fedora20
--- a/contrib/buildrpm Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/buildrpm Sat Sep 27 14:47:52 2014 -0500 @@ -7,9 +7,33 @@ # - CentOS 5 # - centOS 6 +BUILD=1 +RPMBUILDDIR="$PWD/rpmbuild" +while [ "$1" ]; do + case "$1" in + --prepare ) + shift + BUILD= + ;; + --withpython | --with-python) + shift + PYTHONVER=2.7.8 + ;; + --rpmbuilddir ) + shift + RPMBUILDDIR="$1" + shift + ;; + * ) + echo "Invalid parameter $1!" 1>&2 + exit 1 + ;; + esac +done + cd "`dirname $0`/.." -specfile=contrib/mercurial.spec +specfile=$PWD/contrib/mercurial.spec if [ ! -f $specfile ]; then echo "Cannot find $specfile!" 1>&2 exit 1 @@ -26,10 +50,7 @@ PYTHONPATH="$PWD/mercurial/pure" export PYTHONPATH -rpmdir="$PWD/rpmbuild" - -rm -rf $rpmdir -mkdir -p $rpmdir/SOURCES $rpmdir/SPECS $rpmdir/RPMS $rpmdir/SRPMS $rpmdir/BUILD +mkdir -p $RPMBUILDDIR/SOURCES $RPMBUILDDIR/SPECS $RPMBUILDDIR/RPMS $RPMBUILDDIR/SRPMS $RPMBUILDDIR/BUILD hgversion=`$HG version | sed -ne 's/.*(version \(.*\))$/\1/p'` @@ -42,9 +63,29 @@ version=`echo $hgversion | sed -e 's/+.*//'` release='0' fi +if [ "$PYTHONVER" ]; then + release=$release+$PYTHONVER + RPMPYTHONVER=$PYTHONVER +else + RPMPYTHONVER=%{nil} +fi -$HG archive -t tgz $rpmdir/SOURCES/mercurial-$version-$release.tar.gz -rpmspec=$rpmdir/SPECS/mercurial.spec +$HG archive -t tgz $RPMBUILDDIR/SOURCES/mercurial-$version-$release.tar.gz +if [ "$PYTHONVER" ]; then +( + cd build + PYTHON_SRCFILE=Python-$PYTHONVER.tgz + [ -f $PYTHON_SRCFILE ] || curl -Lo $PYTHON_SRCFILE http://www.python.org/ftp/python/$PYTHONVER/$PYTHON_SRCFILE + ln -f $PYTHON_SRCFILE $RPMBUILDDIR/SOURCES/$PYTHON_SRCFILE + + DOCUTILSVER=`sed -ne "s/^%global docutilsname docutils-//p" $specfile` + DOCUTILS_SRCFILE=docutils-$DOCUTILSVER.tar.gz + [ -f $DOCUTILS_SRCFILE ] || curl -Lo $DOCUTILS_SRCFILE http://downloads.sourceforge.net/project/docutils/docutils/$DOCUTILSVER/$DOCUTILS_SRCFILE + ln -f $DOCUTILS_SRCFILE $RPMBUILDDIR/SOURCES/$DOCUTILS_SRCFILE +) +fi + +rpmspec=$RPMBUILDDIR/SPECS/mercurial.spec sed -e "s,^Version:.*,Version: $version," \ -e "s,^Release:.*,Release: $release," \ @@ -95,9 +136,18 @@ fi -rpmbuild --define "_topdir $rpmdir" -ba $rpmspec --clean -if [ $? = 0 ]; then - echo - echo "Packages are in $rpmdir:" - ls -l $rpmdir/*RPMS/* +sed -i \ + -e "s/^%define withpython.*$/%define withpython $RPMPYTHONVER/" \ + $rpmspec + +if [ "$BUILD" ]; then + rpmbuild --define "_topdir $RPMBUILDDIR" -ba $rpmspec --clean + if [ $? = 0 ]; then + echo + echo "Built packages for $version-$release:" + find $RPMBUILDDIR/*RPMS/ -type f -newer $rpmspec + fi +else + echo "Prepared sources for $version-$release $rpmspec are in $RPMBUILDDIR/SOURCES/ - use like:" + echo "rpmbuild --define '_topdir $RPMBUILDDIR' -ba $rpmspec --clean" fi
--- a/contrib/check-code.py Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/check-code.py Sat Sep 27 14:47:52 2014 -0500 @@ -94,7 +94,7 @@ (r'sed.*-i', "don't use 'sed -i', use a temporary file"), (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"), (r'echo -n', "don't use 'echo -n', use printf"), - (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"), + (r'(^| )\bwc\b[^|]*$\n(?!.*\(re\))', "filter wc output"), (r'head -c', "don't use 'head -c', use 'dd'"), (r'tail -n', "don't use the '-n' option to tail, just use '-<num>'"), (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"), @@ -179,12 +179,14 @@ ] for i in [0, 1]: - for p, m in testpats[i]: + for tp in testpats[i]: + p = tp[0] + m = tp[1] if p.startswith(r'^'): p = r"^ [$>] (%s)" % p[1:] else: p = r"^ [$>] .*(%s)" % p - utestpats[i].append((p, m)) + utestpats[i].append((p, m) + tp[2:]) utestfilters = [ (r"<<(\S+)((.|\n)*?\n > \1)", rephere), @@ -214,8 +216,9 @@ (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'(\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.*?' @@ -296,6 +299,7 @@ (r'ui\.(status|progress|write|note|warn)\([\'\"]x', "missing _() in ui message (use () to hide false-positives)"), (r'release\(.*wlock, .*lock\)', "wrong lock release order"), + (r'\b__bool__\b', "__bool__ should be __nonzero__ in Python 2"), ], # warnings [
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/check-commit Sat Sep 27 14:47:52 2014 -0500 @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# +# Copyright 2014 Matt Mackall <mpm@selenic.com> +# +# A tool/hook to run basic sanity checks on commits/patches for +# submission to Mercurial. Install by adding the following to your +# .hg/hgrc: +# +# [hooks] +# pretxncommit = contrib/check-commit +# +# The hook can be temporarily bypassed with: +# +# $ BYPASS= hg commit +# +# See also: http://mercurial.selenic.com/wiki/ContributingChanges + +import re, sys, os + +errors = [ + (r"[(]bc[)]", "(BC) needs to be uppercase"), + (r"[(]issue \d\d\d", "no space allowed between issue and number"), + (r"[(]bug", "use (issueDDDD) instead of bug"), + (r"^# User [^@\n]+$", "username is not an email address"), + (r"^# .*\n(?!merge with )[^#]\S+[^:] ", + "summary line doesn't start with 'topic: '"), + (r"^# .*\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 \n", "adds double empty line"), + (r"\+\s+def [a-z]+_[a-z]", "adds a function with foo_bar naming"), +] + +node = os.environ.get("HG_NODE") + +if node: + commit = os.popen("hg export %s" % node).read() +else: + commit = sys.stdin.read() + +exitcode = 0 +for exp, msg in errors: + m = re.search(exp, commit, re.MULTILINE) + if m: + pos = 0 + for n, l in enumerate(commit.splitlines(True)): + pos += len(l) + if pos >= m.end(): + print "%d: %s" % (n, msg) + print " %s" % l[:-1] + if "BYPASS" not in os.environ: + exitcode = 1 + break + +sys.exit(exitcode)
--- a/contrib/convert-repo Mon Sep 22 23:46:38 2014 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# -# Wrapper script around the convert.py hgext extension -# for foreign SCM conversion to mercurial format. -# - -import sys -from mercurial import ui, fancyopts -from hgext import convert - -# Options extracted from the cmdtable -func, options, help = convert.cmdtable['convert'] - -# An ui instance -u = ui.ui() - -opts = {} -args = [] -try: - args = list(fancyopts.fancyopts(sys.argv[1:], options, opts)) - args += [None]*(3 - len(args)) - src, dest, revmapfile = args -except (fancyopts.getopt.GetoptError, ValueError), inst: - u.warn('Usage:\n%s\n' % help) - sys.exit(-1) - -convert.convert(u, src, dest, revmapfile, **opts)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/docker/centos5 Sat Sep 27 14:47:52 2014 -0500 @@ -0,0 +1,6 @@ +FROM saltstack/centos-5-minimal +RUN yum install -y gcc make rpm-build gettext tar +RUN yum install -y python-devel python-docutils +# For creating repo meta data +RUN yum install -y createrepo +RUN yum install -y readline-devel openssl-devel ncurses-devel zlib-devel bzip2-devel
--- a/contrib/docker/centos6 Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/docker/centos6 Sat Sep 27 14:47:52 2014 -0500 @@ -1,7 +1,9 @@ -FROM centos +FROM centos:centos6 RUN yum install -y gcc RUN yum install -y python-devel python-docutils RUN yum install -y make RUN yum install -y rpm-build RUN yum install -y gettext RUN yum install -y tar +# For creating repo meta data +RUN yum install -y createrepo
--- a/contrib/docker/fedora Mon Sep 22 23:46:38 2014 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -FROM fedora -RUN yum install -y gcc -RUN yum install -y python-devel python-docutils -RUN yum install -y make -RUN yum install -y rpm-build -RUN yum install -y gettext
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/docker/fedora20 Sat Sep 27 14:47:52 2014 -0500 @@ -0,0 +1,8 @@ +FROM fedora:20 +RUN yum install -y gcc +RUN yum install -y python-devel python-docutils +RUN yum install -y make +RUN yum install -y rpm-build +RUN yum install -y gettext +# For creating repo meta data +RUN yum install -y createrepo
--- a/contrib/dockerrpm Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/dockerrpm Sat Sep 27 14:47:52 2014 -0500 @@ -1,14 +1,57 @@ -#!/bin/bash +#!/bin/bash -e BUILDDIR=$(dirname $0) ROOTDIR=$(cd $BUILDDIR/..; pwd) -if which docker.io >> /dev/null ; then +if which docker.io >> /dev/null 2>&1 ; then DOCKER=docker.io -elif which docker >> /dev/null ; then +elif which docker >> /dev/null 2>&1 ; then DOCKER=docker +else + echo "Error: docker must be installed" + exit 1 fi -$DOCKER build --tag "hg-dockerrpm-$1" - < $BUILDDIR/docker/$1 -$DOCKER run --rm -v $ROOTDIR:/hg "hg-dockerrpm-$1" bash -c \ - "cp -a hg hg-build; cd hg-build; make clean local $1; cp packages/$1/* /hg/packages/$1/" +$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; } + +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 - + +RPMBUILDDIR=$ROOTDIR/packages/$PLATFORM +contrib/buildrpm --rpmbuilddir $RPMBUILDDIR --prepare $* + +DSHARED=/mnt/shared +$DOCKER run -u $DBUILDUSER --rm -v $RPMBUILDDIR:$DSHARED $CONTAINER \ + rpmbuild --define "_topdir $DSHARED" -ba $DSHARED/SPECS/mercurial.spec --clean + +$DOCKER run -u $DBUILDUSER --rm -v $RPMBUILDDIR:$DSHARED $CONTAINER \ + createrepo $DSHARED + +cat << EOF > $RPMBUILDDIR/mercurial.repo +# Place this file in /etc/yum.repos.d/mercurial.repo +[mercurial] +name=Mercurial packages for $NAME +# baseurl=file://$RPMBUILDDIR/ +baseurl=http://hg.example.com/build/$NAME/ +skip_if_unavailable=True +gpgcheck=0 +enabled=1 +EOF + +echo +echo "Build complete - results can be found in $RPMBUILDDIR"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/hg-test-mode.el Sat Sep 27 14:47:52 2014 -0500 @@ -0,0 +1,56 @@ +;; hg-test-mode.el - Major mode for editing Mercurial tests +;; +;; Copyright 2014 Matt Mackall <mpm@selenic.com> +;; "I have no idea what I'm doing" +;; +;; This software may be used and distributed according to the terms of the +;; GNU General Public License version 2 or any later version. +;; +;; To enable, add something like the following to your .emacs: +;; +;; (if (file-exists-p "~/hg/contrib/hg-test-mode.el") +;; (load "~/hg/contrib/hg-test-mode.el")) + +(defvar hg-test-mode-hook nil) + +(defvar hg-test-mode-map + (let ((map (make-keymap))) + (define-key map "\C-j" 'newline-and-indent) + map) + "Keymap for hg test major mode") + +(add-to-list 'auto-mode-alist '("\\.t\\'" . hg-test-mode)) + +(defconst hg-test-font-lock-keywords-1 + (list + '("^ \\(\\$\\|>>>\\) " 1 font-lock-builtin-face) + '("^ \\(>\\|\\.\\.\\.\\) " 1 font-lock-constant-face) + '("^ \\([[][0-9]+[]]\\)$" 1 font-lock-warning-face) + '("^ \\(.*?\\)\\(\\( [(][-a-z]+[)]\\)*\\)$" 1 font-lock-string-face) + '("\\$?\\(HG\\|TEST\\)\\w+=?" . font-lock-variable-name-face) + '("^ \\(.*?\\)\\(\\( [(][-a-z]+[)]\\)+\\)$" 2 font-lock-type-face) + '("^#.*" . font-lock-preprocessor-face) + '("^\\([^ ].*\\)$" 1 font-lock-comment-face) + ) + "Minimal highlighting expressions for hg-test mode") + +(defvar hg-test-font-lock-keywords hg-test-font-lock-keywords-1 + "Default highlighting expressions for hg-test mode") + +(defvar hg-test-mode-syntax-table + (let ((st (make-syntax-table))) + (modify-syntax-entry ?\" "w" st) ;; disable standard quoting + st) +"Syntax table for hg-test mode") + +(defun hg-test-mode () + (interactive) + (kill-all-local-variables) + (use-local-map hg-test-mode-map) + (set-syntax-table hg-test-mode-syntax-table) + (set (make-local-variable 'font-lock-defaults) '(hg-test-font-lock-keywords)) + (setq major-mode 'hg-test-mode) + (setq mode-name "hg-test") + (run-hooks 'hg-test-mode-hook)) + +(provide 'hg-test-mode)
--- a/contrib/mercurial.spec Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/mercurial.spec Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,23 @@ %global emacs_lispdir %{_datadir}/emacs/site-lisp + +%define withpython %{nil} + +%if "%{?withpython}" + +%global pythonver %{withpython} +%global pythonname Python-%{withpython} +%global docutilsname docutils-0.11 +%global pythonhg python-hg +%global hgpyprefix /usr/%{pythonhg} +# byte compilation will fail on some some Python /test/ files +%global _python_bytecompile_errors_terminate_build 0 + +%else + %global pythonver %(python -c 'import sys;print ".".join(map(str, sys.version_info[:2]))') +%endif + Summary: A fast, lightweight Source Control Management system Name: mercurial Version: snapshot @@ -9,11 +26,19 @@ Group: Development/Tools URL: http://mercurial.selenic.com/ Source0: %{name}-%{version}-%{release}.tar.gz +%if "%{?withpython}" +Source1: %{pythonname}.tgz +Source2: %{docutilsname}.tar.gz +%endif BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root -BuildRequires: python >= 2.4, python-devel, make, gcc, python-docutils >= 0.5, gettext -Provides: hg = %{version}-%{release} +BuildRequires: make, gcc, gettext +%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 +%endif # The hgk extension uses the wish tcl interpreter, but we don't enforce it #Requires: tk @@ -22,15 +47,69 @@ for efficient handling of very large distributed projects. %prep + +%if "%{?withpython}" +%setup -q -n mercurial-%{version}-%{release} -a1 -a2 +# despite the comments in cgi.py, we do this to prevent rpmdeps from picking /usr/local/bin/python up +sed -i '1c#! /usr/bin/env python' %{pythonname}/Lib/cgi.py +%else %setup -q -n mercurial-%{version}-%{release} +%endif %build + +%if "%{?withpython}" + +PYPATH=$PWD/%{pythonname} +cd $PYPATH +./configure --prefix=%{hgpyprefix} +make all %{?_smp_mflags} +cd - + +cd %{docutilsname} +LD_LIBRARY_PATH=$PYPATH $PYPATH/python setup.py build +cd - + +# verify Python environment +LD_LIBRARY_PATH=$PYPATH PYTHONPATH=$PWD/%{docutilsname} $PYPATH/python -c 'import sys, zlib, bz2, ssl, curses, readline' + +# set environment for make +export PATH=$PYPATH:$PATH +export LD_LIBRARY_PATH=$PYPATH +export CFLAGS="-L $PYPATH" +export PYTHONPATH=$PWD/%{docutilsname} + +%endif + make all %install rm -rf $RPM_BUILD_ROOT + +%if "%{?withpython}" + +PYPATH=$PWD/%{pythonname} +cd $PYPATH +make install DESTDIR=$RPM_BUILD_ROOT +# these .a are not necessary and they are readonly and strip fails - kill them! +rm -f %{buildroot}%{hgpyprefix}/lib/{,python2.*/config}/libpython2.*.a +cd - + +cd %{docutilsname} +LD_LIBRARY_PATH=$PYPATH $PYPATH/python setup.py install --root="$RPM_BUILD_ROOT" +cd - + +PATH=$PYPATH:$PATH LD_LIBRARY_PATH=$PYPATH make install DESTDIR=$RPM_BUILD_ROOT PREFIX=%{hgpyprefix} MANDIR=%{_mandir} +mkdir -p $RPM_BUILD_ROOT%{_bindir} +( cd $RPM_BUILD_ROOT%{_bindir}/ && ln -s ../..%{hgpyprefix}/bin/hg . ) +( cd $RPM_BUILD_ROOT%{_bindir}/ && ln -s ../..%{hgpyprefix}/bin/python2.? %{pythonhg} ) + +%else + make install DESTDIR=$RPM_BUILD_ROOT PREFIX=%{_prefix} MANDIR=%{_mandir} +%endif + install -m 755 contrib/hgk $RPM_BUILD_ROOT%{_bindir}/ install -m 755 contrib/hg-ssh $RPM_BUILD_ROOT%{_bindir}/ @@ -56,7 +135,7 @@ %defattr(-,root,root,-) %doc CONTRIBUTORS COPYING doc/README doc/hg*.txt doc/hg*.html *.cgi contrib/*.fcgi %doc %attr(644,root,root) %{_mandir}/man?/hg* -%doc %attr(644,root,root) contrib/*.svg contrib/sample.hgrc +%doc %attr(644,root,root) contrib/*.svg %dir %{_datadir}/zsh/ %dir %{_datadir}/zsh/site-functions/ %{_datadir}/zsh/site-functions/_mercurial @@ -71,8 +150,13 @@ %dir %{_sysconfdir}/mercurial %dir %{_sysconfdir}/mercurial/hgrc.d %config(noreplace) %{_sysconfdir}/mercurial/hgrc.d/mergetools.rc +%if "%{?withpython}" +%{_bindir}/%{pythonhg} +%{hgpyprefix} +%else %if "%{?pythonver}" != "2.4" %{_libdir}/python%{pythonver}/site-packages/%{name}-*-py%{pythonver}.egg-info %endif %{_libdir}/python%{pythonver}/site-packages/%{name} %{_libdir}/python%{pythonver}/site-packages/hgext +%endif
--- a/contrib/mergetools.hgrc Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/mergetools.hgrc Sat Sep 27 14:47:52 2014 -0500 @@ -58,6 +58,12 @@ p4merge.priority=-8 p4merge.diffargs=$parent $child +p4mergeosx.executable = /Applications/p4merge.app/Contents/MacOS/p4merge +p4mergeosx.args = $base $local $other $output +p4mergeosx.gui = True +p4mergeosx.priority=-8 +p4mergeosx.diffargs=$parent $child + tortoisemerge.args=/base:$base /mine:$local /theirs:$other /merged:$output tortoisemerge.regkey=Software\TortoiseSVN tortoisemerge.regkeyalt=Software\Wow6432Node\TortoiseSVN
--- a/contrib/revsetbenchmarks.py Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/revsetbenchmarks.py Sat Sep 27 14:47:52 2014 -0500 @@ -19,8 +19,6 @@ # cannot use argparse, python 2.7 only from optparse import OptionParser - - def check_output(*args, **kwargs): kwargs.setdefault('stderr', PIPE) kwargs.setdefault('stdout', PIPE) @@ -76,7 +74,8 @@ parser = OptionParser(usage="usage: %prog [options] <revs>") parser.add_option("-f", "--file", - help="read revset from FILE", metavar="FILE") + help="read revset from FILE (stdin if omited)", + metavar="FILE") parser.add_option("-R", "--repo", help="run benchmark on REPO", metavar="REPO") @@ -95,7 +94,7 @@ if options.file: revsetsfile = open(options.file) -revsets = [l.strip() for l in revsetsfile] +revsets = [l.strip() for l in revsetsfile if not l.startswith('#')] print "Revsets to benchmark" print "----------------------------"
--- a/contrib/revsetbenchmarks.txt Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/revsetbenchmarks.txt Sat Sep 27 14:47:52 2014 -0500 @@ -14,7 +14,9 @@ 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)) ::p1(p1(tip)):: public() :10000 and public() @@ -22,3 +24,9 @@ :10000 and draft() max(::(tip~20) - obsolete()) roots((0:tip)::) +(not public() - obsolete()) +(_intlist('20000\x0020001')) and merge() +parents(20000) +(20000::) - (20000) +# The one below is used by rebase +(children(ancestor(tip~5, tip)) and ::(tip~5))::
--- a/contrib/sample.hgrc Mon Sep 22 23:46:38 2014 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -### --- User interface - -[ui] - -### show changed files and be a bit more verbose if True - -# verbose = True - -### username data to appear in comits -### it usually takes the form: Joe User <joe.user@host.com> - -# username = Joe User <j.user@example.com> - -### --- Extensions - -[extensions] - -### each extension has its own 'extension_name=path' line -### the default python library path is used when path is left blank -### the hgext dir is used when 'hgext.extension_name=' is written - -### acl - Access control lists -### hg help acl - -# hgext.acl = - -### bisect - binary search changesets to detect bugs -### hg help bisect - -# hgext.hbisect = - -### bugzilla - update bugzilla bugs when changesets mention them -### hg help bugzilla - -# hgext.bugzilla = - -### extdiff - Use external diff application instead of builtin one - -# hgext.extdiff = - -### gpg - GPG checks and signing -### hg help gpg - -# hgext.gpg = - -### hgk - GUI repository browser -### hg help view - -# hgext.hgk = - -### strip - Remove changesets and their descendents from history -### hg help strip - -# hgext.strip = - -### notify - Template driven e-mail notifications -### hg help notify - -# hgext.notify = - -### patchbomb - send changesets as a series of patch emails -### hg help email - -# hgext.patchbomb = - -### churn - create a graph showing who changed the most lines -### hg help churn - -# hgext.churn = /home/user/hg/hg/contrib/churn.py - -### eol - automatic management of line endings - -# hgext.eol = - -### --- hgk additional configuration - -[hgk] - -### set executable path - -# path = /home/user/hg/hg/contrib/hgk - -### --- Hook to Mercurial actions - See hgrc man page for avaliable hooks - -[hooks] - -### Example notify hooks (load hgext.notify extension before use) - -# incoming.notify = python:hgext.notify.hook -# changegroup.notify = python:hgext.notify.hook - -### Email configuration for the notify and patchbomb extensions - -[email] - -### Your email address - -# from = user@example.com - -### Method to send email - smtp or /usr/sbin/sendmail or other program name - -# method = smtp - -### smtp server to send email to - -[smtp] - -# host = mail -# port = 25 -# tls = false -# username = user -# password = blivet -# local_hostname = myhost - -### --- Email notification hook for server - -[notify] -### multiple sources can be specified as a whitespace or comma separated list - -# sources = serve push pull bundle - -### set this to False when you're ready for mail to start sending - -# test = True - -### path to config file with names of subscribers - -# config = /path/to/subscription/file
--- a/contrib/simplemerge Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/simplemerge Sat Sep 27 14:47:52 2014 -0500 @@ -11,8 +11,7 @@ ('a', 'text', None, _('treat all files as text')), ('p', 'print', None, _('print results instead of overwriting LOCAL')), - ('', 'no-minimal', None, - _('do not try to minimize conflict regions')), + ('', 'no-minimal', None, _('no effect (DEPRECATED)')), ('h', 'help', None, _('display help and exit')), ('q', 'quiet', None, _('suppress output'))]
--- a/contrib/synthrepo.py Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/synthrepo.py Sat Sep 27 14:47:52 2014 -0500 @@ -151,8 +151,7 @@ lastctx = repo[rev - 1] if lastctx.rev() != nullrev: interarrival[roundto(ctx.date()[0] - lastctx.date()[0], 300)] += 1 - diff = sum((d.splitlines() - for d in ctx.diff(pctx, opts={'git': True})), []) + diff = sum((d.splitlines() for d in ctx.diff(pctx, git=True)), []) fileadds, diradds, fileremoves, filechanges = 0, 0, 0, 0 for filename, mar, lineadd, lineremove, binary in parsegitdiff(diff): if binary: @@ -307,7 +306,8 @@ # the number of heads will grow without bound if we use a pure # model, so artificially constrain their proliferation - if pick(parents) == 2 or len(heads) > random.randint(1, 20): + toomanyheads = len(heads) > random.randint(1, 20) + if p2distance[0] and (pick(parents) == 2 or toomanyheads): r2, p2 = pickhead(heads.difference([r1]), p2distance) else: r2, p2 = nullrev, nullid @@ -356,10 +356,7 @@ for __ in xrange(pick(linesinfilesadded))) + '\n' changes[path] = context.memfilectx(repo, path, data) def filectxfn(repo, memctx, path): - data = changes[path] - if data is None: - raise IOError - return data + return changes[path] if not changes: continue if revs:
--- a/contrib/win32/hgwebdir_wsgi.py Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/win32/hgwebdir_wsgi.py Sat Sep 27 14:47:52 2014 -0500 @@ -52,6 +52,7 @@ # Enable tracing. Run 'python -m win32traceutil' to debug if getattr(sys, 'isapidllhandle', None) is not None: import win32traceutil + win32traceutil.SetupForPrint # silence unused import warning # To serve pages in local charset instead of UTF-8, remove the two lines below import os @@ -90,6 +91,6 @@ return isapi_wsgi.ISAPISimpleHandler(handler) if __name__=='__main__': - from isapi.install import * + from isapi.install import ISAPIParameters, HandleCommandLine params = ISAPIParameters() HandleCommandLine(params)
--- a/contrib/wix/contrib.wxs Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/wix/contrib.wxs Sat Sep 27 14:47:52 2014 -0500 @@ -21,7 +21,6 @@ <File Name="hgweb.wsgi" /> <File Name="logo-droplets.svg" /> <File Name="mercurial.el" /> - <File Name="sample.hgrc" /> <File Name="tcsh_completion" /> <File Name="tcsh_completion_build.sh" /> <File Name="xml.rnc" />
--- a/contrib/wix/guids.wxi Mon Sep 22 23:46:38 2014 +0900 +++ b/contrib/wix/guids.wxi Sat Sep 27 14:47:52 2014 -0500 @@ -5,7 +5,7 @@ your project. Component GUIDs have global namespace! --> <!-- contrib.wxs --> - <?define contrib.guid = {F17D27B7-4A6B-4cd2-AE72-FED3CFAA585E} ?> + <?define contrib.guid = {4E11FFC2-E2F7-482A-8460-9394B5489F02} ?> <?define contrib.vim.guid = {BB04903A-652D-4C4F-9590-2BD07A2304F2} ?> <!-- dist.wxs -->
--- a/hgext/color.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/color.py Sat Sep 27 14:47:52 2014 -0500 @@ -19,7 +19,23 @@ available, then effects are rendered with the ECMA-48 SGR control function (aka ANSI escape codes). -Default effects may be overridden from your configuration file:: +Text receives color effects depending on the labels that it has. Many +default Mercurial commands emit labelled text. You can also define +your own labels in templates using the label function, see :hg:`help +templates`. A single portion of text may have more than one label. In +that case, effects given to the last label will override any other +effects. This includes the special "none" effect, which nullifies +other effects. + +Labels are normally invisible. In order to see these labels and their +position in the text, use the global --color=debug option. In case of +multiple labels for the same text, the labels will be enclosed by +square brackets, e.g. + + [log.changeset changeset.secret](changeset: 22611:6f0a53c8f587) + +The following are the default effects for some default labels. Default +effects may be overridden from your configuration file:: [color] status.modified = blue bold underline red_background @@ -47,6 +63,11 @@ diff.changed = white diff.trailingwhitespace = bold red_background + # Blank so it inherits the style of the surrounding label + changeset.public = + changeset.draft = + changeset.secret = + resolve.unresolved = red bold resolve.resolved = green bold @@ -168,6 +189,9 @@ def _modesetup(ui, coloropt): global _terminfo_params + if coloropt == 'debug': + return 'debug' + auto = (coloropt == 'auto') always = not auto and util.parsebool(coloropt) if not always and not auto: @@ -256,6 +280,9 @@ 'diff.hunk': 'magenta', 'diff.inserted': 'green', 'diff.trailingwhitespace': 'bold red_background', + 'changeset.public' : '', + 'changeset.draft' : '', + 'changeset.secret' : '', 'diffstat.deleted': 'red', 'diffstat.inserted': 'green', 'histedit.remaining': 'red bold', @@ -378,10 +405,22 @@ return super(colorui, self).write_err( *[self.label(str(a), label) for a in args], **opts) + def showlabel(self, msg, label): + if label: + if msg and msg[-1] == '\n': + return "[%s|%s]\n" % (label, msg[:-1]) + else: + return "[%s|%s]" % (label, msg) + else: + return msg + def label(self, msg, label): if self._colormode is None: return super(colorui, self).label(msg, label) + if self._colormode == 'debug': + return self.showlabel(msg, label) + effects = [] for l in label.split(): s = _styles.get(l, '') @@ -427,7 +466,7 @@ def colorcmd(orig, ui_, opts, cmd, cmdfunc): mode = _modesetup(ui_, opts['color']) colorui._colormode = mode - if mode: + if mode and mode != 'debug': extstyles() configstyles(ui_) return orig(ui_, opts, cmd, cmdfunc) @@ -437,9 +476,9 @@ def extsetup(ui): commands.globalopts.append( ('', 'color', 'auto', - # i18n: 'always', 'auto', and 'never' are keywords and should - # not be translated - _("when to colorize (boolean, always, auto, or never)"), + # i18n: 'always', 'auto', 'never', and 'debug' are keywords + # and should not be translated + _("when to colorize (boolean, always, auto, never, or debug)"), _('TYPE'))) @command('debugcolor', [], 'hg debugcolor')
--- a/hgext/convert/__init__.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/__init__.py Sat Sep 27 14:47:52 2014 -0500 @@ -29,6 +29,8 @@ ('A', 'authormap', '', _('remap usernames using this file'), _('FILE')), ('', 'filemap', '', _('remap file names using contents of file'), _('FILE')), + ('', 'full', None, + _('apply filemap changes by converting all files again')), ('', 'splicemap', '', _('splice synthesized history into place'), _('FILE')), ('', 'branchmap', '', _('change branch names while converting'), @@ -131,6 +133,14 @@ it is converted. To rename from a subdirectory into the root of the repository, use ``.`` as the path to rename to. + ``--full`` will make sure the converted changesets contain exactly + the right files with the right content. It will make a full + conversion of all files, not just the ones that have + changed. Files that already are correct will not be changed. This + can be used to apply filemap changes when converting + incrementally. This is currently only supported for Mercurial and + Subversion. + The splicemap is a file that allows insertion of synthetic history, letting you specify the parents of a revision. This is useful if you want to e.g. give a Subversion merge two parents, or @@ -272,6 +282,29 @@ :convert.svn.startrev: specify start Subversion revision number. The default is 0. + Git Source + ########## + + The Git importer converts commits from all reachable branches (refs + in refs/heads) and remotes (refs in refs/remotes) to Mercurial. + Branches are converted to bookmarks with the same name, with the + leading 'refs/heads' stripped. Git submodules are converted to Git + subrepos in Mercurial. + + The following options can be set with ``--config``: + + :convert.git.similarity: specify how similar files modified in a + commit must be to be imported as renames or copies, as a + percentage between ``0`` (disabled) and ``100`` (files must be + identical). For example, ``90`` means that a delete/add pair will + be imported as a rename if more than 90% of the file hasn't + changed. The default is ``50``. + + :convert.git.findcopiesharder: while detecting copies, look at all + files in the working copy instead of just changed ones. This + is very expensive for large projects, and is only effective when + ``convert.git.similarity`` is greater than 0. The default is False. + Perforce Source ###############
--- a/hgext/convert/bzr.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/bzr.py Sat Sep 27 14:47:52 2014 -0500 @@ -122,8 +122,7 @@ kind = revtree.kind(fileid) if kind not in supportedkinds: # the file is not available anymore - was deleted - raise IOError(_('%s is not available in %s anymore') % - (name, rev)) + return None, None mode = self._modecache[(name, rev)] if kind == 'symlink': target = revtree.get_symlink_target(fileid) @@ -135,8 +134,9 @@ sio = revtree.get_file(fileid) return sio.read(), mode - def getchanges(self, version): - # set up caches: modecache and revtree + def getchanges(self, version, full): + if full: + raise util.Abort(_("convert from cvs do not support --full")) self._modecache = {} self._revtree = self.sourcerepo.revision_tree(version) # get the parentids from the cache
--- a/hgext/convert/common.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/common.py Sat Sep 27 14:47:52 2014 -0500 @@ -88,17 +88,18 @@ def getfile(self, name, rev): """Return a pair (data, mode) where data is the file content as a string and mode one of '', 'x' or 'l'. rev is the - identifier returned by a previous call to getchanges(). Raise - IOError to indicate that name was deleted in rev. + identifier returned by a previous call to getchanges(). + Data is None if file is missing/deleted in rev. """ raise NotImplementedError - def getchanges(self, version): + def getchanges(self, version, full): """Returns a tuple of (files, copies). files is a sorted list of (filename, id) tuples for all files changed between version and its first parent returned by - getcommit(). id is the source revision id of the file. + getcommit(). If full, all files in that revision is returned. + id is the source revision id of the file. copies is a dictionary of dest: source """ @@ -108,6 +109,13 @@ """Return the commit object for version""" raise NotImplementedError + def numcommits(self): + """Return the number of commits in this source. + + If unknown, return None. + """ + return None + def gettags(self): """Return the tags as a dictionary of name: revision @@ -204,7 +212,7 @@ mapping equivalent authors identifiers for each system.""" return None - def putcommit(self, files, copies, parents, commit, source, revmap): + def putcommit(self, files, copies, parents, commit, source, revmap, full): """Create a revision with all changed files listed in 'files' and having listed parents. 'commit' is a commit object containing at a minimum the author, date, and message for this @@ -212,7 +220,8 @@ 'copies' is a dictionary mapping destinations to sources, 'source' is the source repository, and 'revmap' is a mapfile of source revisions to converted revisions. Only getfile() and - lookuprev() should be called on 'source'. + lookuprev() should be called on 'source'. 'full' means that 'files' + is complete and all other files should be removed. Note that the sink repository is not told to update itself to a particular revision (or even what that revision would be)
--- a/hgext/convert/convcmd.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/convcmd.py Sat Sep 27 14:47:52 2014 -0500 @@ -171,6 +171,7 @@ visit = heads known = set() parents = {} + numcommits = self.source.numcommits() while visit: n = visit.pop(0) if n in known: @@ -180,7 +181,8 @@ if m == SKIPREV or self.dest.hascommitfrommap(m): continue known.add(n) - self.ui.progress(_('scanning'), len(known), unit=_('revisions')) + self.ui.progress(_('scanning'), len(known), unit=_('revisions'), + total=numcommits) commit = self.cachecommit(n) parents[n] = [] for p in commit.parents: @@ -386,8 +388,8 @@ def copy(self, rev): commit = self.commitcache[rev] - - changes = self.source.getchanges(rev) + full = self.opts.get('full') + changes = self.source.getchanges(rev, full) if isinstance(changes, basestring): if changes == SKIPREV: dest = SKIPREV @@ -413,7 +415,7 @@ parents = [b[0] for b in pbranches] source = progresssource(self.ui, self.source, len(files)) newnode = self.dest.putcommit(files, copies, parents, commit, - source, self.map) + source, self.map, full) source.close() self.source.converted(rev, newnode) self.map[rev] = newnode
--- a/hgext/convert/cvs.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/cvs.py Sat Sep 27 14:47:52 2014 -0500 @@ -220,7 +220,7 @@ self._parse() if rev.endswith("(DEAD)"): - raise IOError + return None, None args = ("-N -P -kk -r %s --" % rev).split() args.append(self.cvsrepo + '/' + name) @@ -258,7 +258,9 @@ else: raise util.Abort(_("unknown CVS response: %s") % line) - def getchanges(self, rev): + def getchanges(self, rev, full): + if full: + raise util.Abort(_("convert from cvs do not support --full")) self._parse() return sorted(self.files[rev].iteritems()), {}
--- a/hgext/convert/cvsps.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/cvsps.py Sat Sep 27 14:47:52 2014 -0500 @@ -8,7 +8,6 @@ import os import re import cPickle as pickle -from mercurial import util from mercurial.i18n import _ from mercurial import hook from mercurial import util @@ -632,7 +631,19 @@ odd.add((l, r)) d = -1 break + # By this point, the changesets are sufficiently compared that + # we don't really care about ordering. However, this leaves + # some race conditions in the tests, so we compare on the + # number of files modified and the number of branchpoints in + # each changeset to ensure test output remains stable. + # recommended replacement for cmp from + # https://docs.python.org/3.0/whatsnew/3.0.html + c = lambda x, y: (x > y) - (x < y) + if not d: + d = c(len(l.entries), len(r.entries)) + if not d: + d = c(len(l.branchpoints), len(r.branchpoints)) return d changesets.sort(cscmp)
--- a/hgext/convert/darcs.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/darcs.py Sat Sep 27 14:47:52 2014 -0500 @@ -8,7 +8,7 @@ from common import NoRepo, checktool, commandline, commit, converter_source from mercurial.i18n import _ from mercurial import util -import os, shutil, tempfile, re +import os, shutil, tempfile, re, errno # The naming drift of ElementTree is fun! @@ -156,7 +156,9 @@ output, status = self.run('revert', all=True, repodir=self.tmppath) self.checkexit(status, output) - def getchanges(self, rev): + def getchanges(self, rev, full): + if full: + raise util.Abort(_("convert from darcs do not support --full")) copies = {} changes = [] man = None @@ -192,8 +194,13 @@ if rev != self.lastrev: raise util.Abort(_('internal calling inconsistency')) path = os.path.join(self.tmppath, name) - data = util.readfile(path) - mode = os.lstat(path).st_mode + try: + data = util.readfile(path) + mode = os.lstat(path).st_mode + except IOError, inst: + if inst.errno == errno.ENOENT: + return None, None + raise mode = (mode & 0111) and 'x' or '' return data, mode
--- a/hgext/convert/filemap.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/filemap.py Sat Sep 27 14:47:52 2014 -0500 @@ -304,7 +304,7 @@ wrev.add(rev) self.wantedancestors[rev] = wrev - def getchanges(self, rev): + def getchanges(self, rev, full): parents = self.commits[rev].parents if len(parents) > 1: self.rebuild() @@ -384,7 +384,7 @@ # Get the real changes and do the filtering/mapping. To be # able to get the files later on in getfile, we hide the # original filename in the rev part of the return value. - changes, copies = self.base.getchanges(rev) + changes, copies = self.base.getchanges(rev, full) files = {} for f, r in changes: newf = self.filemapper(f)
--- a/hgext/convert/git.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/git.py Sat Sep 27 14:47:52 2014 -0500 @@ -94,6 +94,19 @@ if not os.path.exists(path + "/objects"): raise NoRepo(_("%s does not look like a Git repository") % path) + # The default value (50) is based on the default for 'git diff'. + similarity = ui.configint('convert', 'git.similarity', default=50) + if similarity < 0 or similarity > 100: + raise util.Abort(_('similarity must be between 0 and 100')) + if similarity > 0: + self.simopt = '--find-copies=%d%%' % similarity + findcopiesharder = ui.configbool('convert', 'git.findcopiesharder', + False) + if findcopiesharder: + self.simopt += ' --find-copies-harder' + else: + self.simopt = '' + checktool('git', 'git') self.path = path @@ -135,7 +148,7 @@ def getfile(self, name, rev): if rev == hex(nullid): - raise IOError + return None, None if name == '.hgsub': data = '\n'.join([m.hgsub() for m in self.submoditer()]) mode = '' @@ -180,51 +193,78 @@ continue m.node = node.strip() - def getchanges(self, version): + def getchanges(self, version, full): + if full: + raise util.Abort(_("convert from git do not support --full")) self.modecache = {} - fh = self.gitopen("git diff-tree -z --root -m -r %s" % version) + fh = self.gitopen("git diff-tree -z --root -m -r %s %s" % ( + self.simopt, version)) changes = [] + copies = {} seen = set() entry = None - subexists = False - subdeleted = False - for l in fh.read().split('\x00'): + subexists = [False] + subdeleted = [False] + difftree = fh.read().split('\x00') + lcount = len(difftree) + i = 0 + + def add(entry, f, isdest): + seen.add(f) + h = entry[3] + p = (entry[1] == "100755") + s = (entry[1] == "120000") + renamesource = (not isdest and entry[4][0] == 'R') + + if f == '.gitmodules': + subexists[0] = True + if entry[4] == 'D' or renamesource: + subdeleted[0] = True + changes.append(('.hgsub', hex(nullid))) + else: + changes.append(('.hgsub', '')) + elif entry[1] == '160000' or entry[0] == ':160000': + subexists[0] = True + else: + if renamesource: + h = hex(nullid) + self.modecache[(f, h)] = (p and "x") or (s and "l") or "" + changes.append((f, h)) + + while i < lcount: + l = difftree[i] + i += 1 if not entry: if not l.startswith(':'): continue - entry = l + entry = l.split() continue f = l if f not in seen: - seen.add(f) - entry = entry.split() - h = entry[3] - p = (entry[1] == "100755") - s = (entry[1] == "120000") - - if f == '.gitmodules': - subexists = True - if entry[4] == 'D': - subdeleted = True - changes.append(('.hgsub', hex(nullid))) - else: - changes.append(('.hgsub', '')) - elif entry[1] == '160000' or entry[0] == ':160000': - subexists = True - else: - self.modecache[(f, h)] = (p and "x") or (s and "l") or "" - changes.append((f, h)) + add(entry, f, False) + # A file can be copied multiple times, or modified and copied + # simultaneously. So f can be repeated even if fdest isn't. + if entry[4][0] in 'RC': + # rename or copy: next line is the destination + fdest = difftree[i] + i += 1 + if fdest not in seen: + add(entry, fdest, True) + # .gitmodules isn't imported at all, so it being copied to + # and fro doesn't really make sense + if f != '.gitmodules' and fdest != '.gitmodules': + copies[fdest] = f entry = None if fh.close(): raise util.Abort(_('cannot read changes in %s') % version) - if subexists: - if subdeleted: + if subexists[0]: + if subdeleted[0]: changes.append(('.hgsubstate', hex(nullid))) else: self.retrievegitmodules(version) changes.append(('.hgsubstate', '')) - return (changes, {}) + return (changes, copies) def getcommit(self, version): c = self.catfile(version, "commit") # read the commit hash @@ -261,6 +301,9 @@ rev=version) return c + def numcommits(self): + return len([None for _ in self.gitopen('git rev-list --all')]) + def gettags(self): tags = {} alltags = {} @@ -340,4 +383,3 @@ def checkrevformat(self, revstr, mapname='splicemap'): """ git revision string is a 40 byte hex """ self.checkhexformat(revstr, mapname) -
--- a/hgext/convert/gnuarch.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/gnuarch.py Sat Sep 27 14:47:52 2014 -0500 @@ -137,13 +137,14 @@ if rev != self.lastrev: raise util.Abort(_('internal calling inconsistency')) - # Raise IOError if necessary (i.e. deleted files). if not os.path.lexists(os.path.join(self.tmppath, name)): - raise IOError + return None, None return self._getfile(name, rev) - def getchanges(self, rev): + def getchanges(self, rev, full): + if full: + raise util.Abort(_("convert from arch do not support --full")) self._update(rev) changes = [] copies = {}
--- a/hgext/convert/hg.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/hg.py Sat Sep 27 14:47:52 2014 -0500 @@ -128,12 +128,16 @@ fp.write('%s %s\n' % (revid, s[1])) return fp.getvalue() - def putcommit(self, files, copies, parents, commit, source, revmap): - + def putcommit(self, files, copies, parents, commit, source, revmap, full): files = dict(files) def getfilectx(repo, memctx, f): - v = files[f] + try: + v = files[f] + except KeyError: + return None data, mode = source.getfile(f, v) + if data is None: + return None if f == '.hgtags': data = self._rewritetags(source, revmap, data) return context.memfilectx(self.repo, f, data, 'l' in mode, @@ -191,7 +195,11 @@ while parents: p1 = p2 p2 = parents.pop(0) - ctx = context.memctx(self.repo, (p1, p2), text, files.keys(), + fileset = set(files) + if full: + fileset.update(self.repo[p1]) + fileset.update(self.repo[p2]) + ctx = context.memctx(self.repo, (p1, p2), text, fileset, getfilectx, commit.author, commit.date, extra) self.repo.commitctx(ctx) text = "(octopus merge fixup)\n" @@ -299,7 +307,7 @@ raise NoRepo(_("%s is not a local Mercurial repository") % path) self.lastrev = None self.lastctx = None - self._changescache = None + self._changescache = None, None self.convertfp = None # Restrict converted revisions to startrev descendants startnode = ui.config('convert', 'hg.startrev') @@ -351,29 +359,28 @@ try: fctx = self.changectx(rev)[name] return fctx.data(), fctx.flags() - except error.LookupError, err: - raise IOError(err) + except error.LookupError: + return None, None - def getchanges(self, rev): + def getchanges(self, rev, full): ctx = self.changectx(rev) parents = self.parents(ctx) - if not parents: - files = sorted(ctx.manifest()) - # getcopies() is not needed for roots, but it is a simple way to - # detect missing revlogs and abort on errors or populate - # self.ignored - self.getcopies(ctx, parents, files) - return [(f, rev) for f in files if f not in self.ignored], {} - if self._changescache and self._changescache[0] == rev: - m, a, r = self._changescache[1] - else: - m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3] - # getcopies() detects missing revlogs early, run it before - # filtering the changes. - copies = self.getcopies(ctx, parents, m + a) - changes = [(name, rev) for name in m + a + r - if name not in self.ignored] - return sorted(changes), copies + if full or not parents: + files = copyfiles = ctx.manifest() + if parents: + if self._changescache[0] == rev: + m, a, r = self._changescache[1] + else: + m, a, r = self.repo.status(parents[0].node(), ctx.node())[:3] + if not full: + files = m + a + r + copyfiles = m + a + # getcopies() is also run for roots and before filtering so missing + # revlogs are detected early + copies = self.getcopies(ctx, parents, copyfiles) + changes = [(f, rev) for f in files if f not in self.ignored] + changes.sort() + return changes, copies def getcopies(self, ctx, parents, files): copies = {}
--- a/hgext/convert/monotone.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/monotone.py Sat Sep 27 14:47:52 2014 -0500 @@ -224,7 +224,9 @@ else: return [self.rev] - def getchanges(self, rev): + def getchanges(self, rev, full): + if full: + raise util.Abort(_("convert from monotone do not support --full")) revision = self.mtnrun("get_revision", rev).split("\n\n") files = {} ignoremove = {} @@ -282,11 +284,11 @@ def getfile(self, name, rev): if not self.mtnisfile(name, rev): - raise IOError # file was deleted or renamed + return None, None try: data = self.mtnrun("get_file_of", name, r=rev) except Exception: - raise IOError # file was deleted or renamed + return None, None self.mtnloadmanifest(rev) node, attr = self.files.get(name, (None, "")) return data, attr
--- a/hgext/convert/p4.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/p4.py Sat Sep 27 14:47:52 2014 -0500 @@ -164,6 +164,8 @@ raise IOError(d["generic"], data) elif code == "stat": + if d.get("action") == "purge": + return None, None p4type = self.re_type.match(d["type"]) if p4type: mode = "" @@ -181,7 +183,7 @@ contents += data if mode is None: - raise IOError(0, "bad stat") + return None, None if keywords: contents = keywords.sub("$\\1$", contents) @@ -190,7 +192,9 @@ return contents, mode - def getchanges(self, rev): + def getchanges(self, rev, full): + if full: + raise util.Abort(_("convert from p4 do not support --full")) return self.files[rev], {} def getcommit(self, rev):
--- a/hgext/convert/subversion.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/convert/subversion.py Sat Sep 27 14:47:52 2014 -0500 @@ -347,7 +347,7 @@ % self.module) self.last_changed = self.revnum(self.head) - self._changescache = None + self._changescache = (None, None) if os.path.exists(os.path.join(url, '.svn/entries')): self.wc = url @@ -444,34 +444,39 @@ return self.heads - def getchanges(self, rev): - if self._changescache and self._changescache[0] == rev: - return self._changescache[1] - self._changescache = None + def _getchanges(self, rev, full): (paths, parents) = self.paths[rev] + copies = {} if parents: files, self.removed, copies = self.expandpaths(rev, paths, parents) - else: + if full or not parents: # Perform a full checkout on roots uuid, module, revnum = revsplit(rev) entries = svn.client.ls(self.baseurl + quote(module), optrev(revnum), True, self.ctx) files = [n for n, e in entries.iteritems() if e.kind == svn.core.svn_node_file] - copies = {} self.removed = set() files.sort() files = zip(files, [rev] * len(files)) + return (files, copies) - # caller caches the result, so free it here to release memory - del self.paths[rev] + def getchanges(self, rev, full): + # reuse cache from getchangedfiles + if self._changescache[0] == rev and not full: + (files, copies) = self._changescache[1] + else: + (files, copies) = self._getchanges(rev, full) + # caller caches the result, so free it here to release memory + del self.paths[rev] return (files, copies) def getchangedfiles(self, rev, i): - changes = self.getchanges(rev) - self._changescache = (rev, changes) - return [f[0] for f in changes[0]] + # called from filemap - cache computed values for reuse in getchanges + (files, copies) = self._getchanges(rev, False) + self._changescache = (rev, (files, copies)) + return [f[0] for f in files] def getcommit(self, rev): if rev not in self.commits: @@ -490,10 +495,10 @@ self._fetch_revisions(revnum, stop) if rev not in self.commits: raise util.Abort(_('svn: revision %s not found') % revnum) - commit = self.commits[rev] + revcommit = self.commits[rev] # caller caches the result, so free it here to release memory del self.commits[rev] - return commit + return revcommit def checkrevformat(self, revstr, mapname='splicemap'): """ fails if revision format does not match the correct format""" @@ -503,6 +508,9 @@ raise util.Abort(_('%s entry %s is not a valid revision' ' identifier') % (mapname, revstr)) + def numcommits(self): + return int(self.head.rsplit('@', 1)[1]) - self.startrev + def gettags(self): tags = {} if self.tags is None: @@ -933,7 +941,7 @@ def getfile(self, file, rev): # TODO: ra.get_file transmits the whole file instead of diffs. if file in self.removed: - raise IOError + return None, None mode = '' try: new_module, revnum = revsplit(rev)[1:] @@ -954,7 +962,7 @@ notfound = (svn.core.SVN_ERR_FS_NOT_FOUND, svn.core.SVN_ERR_RA_DAV_PATH_NOT_FOUND) if e.apr_err in notfound: # File not found - raise IOError + return None, None raise if mode == 'l': link_prefix = "link " @@ -1211,23 +1219,13 @@ self.xargs(files, 'add', quiet=True) return files - def tidy_dirs(self, names): - deleted = [] - for d in sorted(self.dirs_of(names), reverse=True): - wd = self.wjoin(d) - if os.listdir(wd) == '.svn': - self.run0('delete', d) - self.manifest.remove(d) - deleted.append(d) - return deleted - def addchild(self, parent, child): self.childmap[parent] = child def revid(self, rev): return u"svn:%s@%s" % (self.uuid, rev) - def putcommit(self, files, copies, parents, commit, source, revmap): + def putcommit(self, files, copies, parents, commit, source, revmap, full): for parent in parents: try: return self.revid(self.childmap[parent]) @@ -1236,14 +1234,15 @@ # Apply changes to working copy for f, v in files: - try: - data, mode = source.getfile(f, v) - except IOError: + data, mode = source.getfile(f, v) + if data is None: self.delete.append(f) else: self.putfile(f, mode, data) if f in copies: self.copies.append([copies[f], f]) + if full: + self.delete.extend(sorted(self.manifest.difference(files))) files = [f[0] for f in files] entries = set(self.delete) @@ -1259,7 +1258,6 @@ self.manifest.remove(f) self.delete = [] entries.update(self.add_files(files.difference(entries))) - entries.update(self.tidy_dirs(entries)) if self.delexec: self.xargs(self.delexec, 'propdel', 'svn:executable') self.delexec = []
--- a/hgext/extdiff.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/extdiff.py Sat Sep 27 14:47:52 2014 -0500 @@ -63,7 +63,7 @@ from mercurial.i18n import _ from mercurial.node import short, nullid -from mercurial import cmdutil, scmutil, scmutil, util, commands, encoding +from mercurial import cmdutil, scmutil, util, commands, encoding import os, shlex, shutil, tempfile, re cmdtable = {}
--- a/hgext/fetch.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/fetch.py Sat Sep 27 14:47:52 2014 -0500 @@ -143,8 +143,8 @@ ('Automated merge with %s' % util.removeauth(other.url()))) editopt = opts.get('edit') or opts.get('force_editor') - n = repo.commit(message, opts['user'], opts['date'], - editor=cmdutil.getcommiteditor(edit=editopt)) + editor = cmdutil.getcommiteditor(edit=editopt, editform='fetch') + n = repo.commit(message, opts['user'], opts['date'], editor=editor) ui.status(_('new changeset %d:%s merges remote changes ' 'with local\n') % (repo.changelog.rev(n), short(n)))
--- a/hgext/gpg.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/gpg.py Sat Sep 27 14:47:52 2014 -0500 @@ -277,8 +277,9 @@ % hgnode.short(n) for n in nodes]) try: + editor = cmdutil.getcommiteditor(editform='gpg.sign', **opts) repo.commit(message, opts['user'], opts['date'], match=msigs, - editor=cmdutil.getcommiteditor(**opts)) + editor=editor) except ValueError, inst: raise util.Abort(str(inst))
--- a/hgext/histedit.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/histedit.py Sat Sep 27 14:47:52 2014 -0500 @@ -36,6 +36,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content # @@ -57,6 +58,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content # @@ -180,6 +182,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above +# r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content # @@ -209,8 +212,6 @@ repo.ui.restoreconfig(phasebackup) return commitfunc - - def applychanges(ui, repo, ctx, opts): """Merge changeset from ctx (only) in the current working directory""" wcpar = repo.dirstate.parents()[0] @@ -220,6 +221,7 @@ cmdutil.revert(ui, repo, ctx, (wcpar, node.nullid), all=True) stats = None else: + repo.dirstate.beginparentchange() try: # ui.forcemerge is an internal variable, do not document repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), @@ -229,6 +231,7 @@ finally: repo.ui.setconfig('ui', 'forcemerge', '', 'histedit') repo.setparents(wcpar, node.nullid) + repo.dirstate.endparentchange() repo.dirstate.write() # fix up dirstate for copies and renames cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev()) @@ -283,7 +286,7 @@ isexec='x' in flags, copied=copied.get(path)) return mctx - raise IOError() + return None if commitopts.get('message'): message = commitopts['message'] @@ -294,6 +297,9 @@ extra = commitopts.get('extra') parents = (first.p1().node(), first.p2().node()) + editor = None + if not commitopts.get('rollup'): + editor = cmdutil.getcommiteditor(edit=True, editform='histedit.fold') new = context.memctx(repo, parents=parents, text=message, @@ -302,7 +308,7 @@ user=user, date=date, extra=extra, - editor=cmdutil.getcommiteditor(edit=True)) + editor=editor) return repo.commitctx(new) def pick(ui, repo, ctx, ha, opts): @@ -335,6 +341,11 @@ _('Make changes as needed, you may commit or record as needed now.\n' 'When you are finished, run hg histedit --continue to resume.')) +def rollup(ui, repo, ctx, ha, opts): + rollupopts = opts.copy() + rollupopts['rollup'] = True + return fold(ui, repo, ctx, ha, rollupopts) + def fold(ui, repo, ctx, ha, opts): oldctx = repo[ha] hg.update(repo, ctx.node()) @@ -357,10 +368,13 @@ commitopts = opts.copy() commitopts['user'] = ctx.user() # commit message - newmessage = '\n***\n'.join( - [ctx.description()] + - [repo[r].description() for r in internalchanges] + - [oldctx.description()]) + '\n' + if opts.get('rollup'): + newmessage = ctx.description() + else: + newmessage = '\n***\n'.join( + [ctx.description()] + + [repo[r].description() for r in internalchanges] + + [oldctx.description()]) + '\n' commitopts['message'] = newmessage # date commitopts['date'] = max(ctx.date(), oldctx.date()) @@ -401,9 +415,10 @@ _('Fix up the change and run hg histedit --continue')) message = oldctx.description() commit = commitfuncfor(repo, oldctx) + editor = cmdutil.getcommiteditor(edit=True, editform='histedit.mess') new = commit(text=message, user=oldctx.user(), date=oldctx.date(), extra=oldctx.extra(), - editor=cmdutil.getcommiteditor(edit=True)) + editor=editor) newctx = repo[new] if oldctx.node() != newctx.node(): return newctx, [(oldctx.node(), (new,))] @@ -440,6 +455,8 @@ 'edit': edit, 'f': fold, 'fold': fold, + 'r': rollup, + 'roll': rollup, 'd': drop, 'drop': drop, 'm': message, @@ -596,11 +613,10 @@ rules = f.read() f.close() rules = [l for l in (r.strip() for r in rules.splitlines()) - if l and not l[0] == '#'] + if l and not l.startswith('#')] rules = verifyrules(rules, repo, ctxs) parentctx = repo[root].parents()[0] - keep = opts.get('keep', False) replacements = [] @@ -675,12 +691,14 @@ m, a, r, d = repo.status()[:4] if m or a or r or d: # prepare the message for the commit to comes - if action in ('f', 'fold'): + if action in ('f', 'fold', 'r', 'roll'): message = 'fold-temp-revision %s' % currentnode else: message = ctx.description() editopt = action in ('e', 'edit', 'm', 'mess') - editor = cmdutil.getcommiteditor(edit=editopt) + canonaction = {'e': 'edit', 'm': 'mess', 'p': 'pick'} + editform = 'histedit.%s' % canonaction.get(action, action) + editor = cmdutil.getcommiteditor(edit=editopt, editform=editform) commit = commitfuncfor(repo, ctx) new = commit(text=message, user=ctx.user(), date=ctx.date(), extra=ctx.extra(), @@ -696,15 +714,19 @@ # to parent. replacements.append((ctx.node(), tuple(newchildren))) - if action in ('f', 'fold'): + if action in ('f', 'fold', 'r', 'roll'): if newchildren: # finalize fold operation if applicable if new is None: new = newchildren[-1] else: newchildren.pop() # remove new from internal changes - parentctx, repl = finishfold(ui, repo, parentctx, ctx, new, opts, - newchildren) + foldopts = opts + if action in ('r', 'roll'): + foldopts = foldopts.copy() + foldopts['rollup'] = True + parentctx, repl = finishfold(ui, repo, parentctx, ctx, new, + foldopts, newchildren) replacements.extend(repl) else: # newchildren is empty if the fold did not result in any commit @@ -729,7 +751,7 @@ if repo.revs('(%ld) and merge()', ctxs): raise util.Abort(_('cannot edit history that contains merges')) root = ctxs[0] # list is already sorted by repo.set - if not root.phase(): + if not root.mutable(): raise util.Abort(_('cannot edit immutable changeset: %s') % root) return [c.node() for c in ctxs]
--- a/hgext/keyword.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/keyword.py Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,6 @@ # keyword.py - $Keyword$ expansion for Mercurial # -# Copyright 2007-2012 Christian Ebert <blacktrash@gmx.net> +# Copyright 2007-2014 Christian Ebert <blacktrash@gmx.net> # # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. @@ -87,7 +87,7 @@ from mercurial import scmutil, pathutil from mercurial.hgweb import webcommands from mercurial.i18n import _ -import os, re, shutil, tempfile +import os, re, tempfile cmdtable = {} command = cmdutil.command(cmdtable) @@ -450,7 +450,12 @@ repo.commit(text=msg) ui.status(_('\n\tkeywords expanded\n')) ui.write(repo.wread(fn)) - shutil.rmtree(tmpdir, ignore_errors=True) + for root, dirs, files in os.walk(tmpdir, topdown=False): + for f in files: + util.unlink(os.path.join(root, f)) + for d in dirs: + os.rmdir(os.path.join(root, d)) + os.rmdir(tmpdir) @command('kwexpand', commands.walkopts,
--- a/hgext/largefiles/lfcommands.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/largefiles/lfcommands.py Sat Sep 27 14:47:52 2014 -0500 @@ -146,7 +146,7 @@ try: fctx = ctx.filectx(lfutil.standin(f)) except error.LookupError: - raise IOError + return None renamed = fctx.renamed() if renamed: renamed = lfutil.splitstandin(renamed[0]) @@ -248,7 +248,7 @@ try: fctx = ctx.filectx(srcfname) except error.LookupError: - raise IOError + return None renamed = fctx.renamed() if renamed: # standin is always a largefile because largefile-ness @@ -298,7 +298,7 @@ try: fctx = ctx.filectx(f) except error.LookupError: - raise IOError + return None renamed = fctx.renamed() if renamed: renamed = renamed[0] @@ -443,6 +443,7 @@ lfiles = set(lfutil.listlfiles(repo)) | set(lfdirstate) if filelist is not None: + filelist = set(filelist) lfiles = [f for f in lfiles if f in filelist] update = {} @@ -510,26 +511,20 @@ updated += update1 - standin = lfutil.standin(lfile) - if standin in repo.dirstate: - stat = repo.dirstate._map[standin] - state, mtime = stat[0], stat[3] - else: - state, mtime = '?', -1 - if state == 'n': - if normallookup or mtime < 0: - # state 'n' doesn't ensure 'clean' in this case - lfdirstate.normallookup(lfile) - else: - lfdirstate.normal(lfile) - elif state == 'm': - lfdirstate.normallookup(lfile) - elif state == 'r': - lfdirstate.remove(lfile) - elif state == 'a': - lfdirstate.add(lfile) - elif state == '?': - lfdirstate.drop(lfile) + lfutil.synclfdirstate(repo, lfdirstate, lfile, normallookup) + + if filelist is not None: + # If "local largefile" is chosen at file merging, it is + # not listed in "filelist" (= dirstate syncing is + # omitted), because the standin file is not changed before and + # after merging. + # But the status of such files may have to be changed by + # merging. For example, locally modified ("M") largefile + # has to become re-added("A"), if it is "normal" file in + # the target revision of linear-merging. + for lfile in lfdirstate: + if lfile not in filelist: + lfutil.synclfdirstate(repo, lfdirstate, lfile, True) lfdirstate.write() if printmessage and lfiles:
--- a/hgext/largefiles/lfutil.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/largefiles/lfutil.py Sat Sep 27 14:47:52 2014 -0500 @@ -363,6 +363,28 @@ standins.append((lfile, hash)) return standins +def synclfdirstate(repo, lfdirstate, lfile, normallookup): + lfstandin = standin(lfile) + if lfstandin in repo.dirstate: + stat = repo.dirstate._map[lfstandin] + state, mtime = stat[0], stat[3] + else: + state, mtime = '?', -1 + if state == 'n': + if normallookup or mtime < 0: + # state 'n' doesn't ensure 'clean' in this case + lfdirstate.normallookup(lfile) + else: + lfdirstate.normal(lfile) + elif state == 'm': + lfdirstate.normallookup(lfile) + elif state == 'r': + lfdirstate.remove(lfile) + elif state == 'a': + lfdirstate.add(lfile) + elif state == '?': + lfdirstate.drop(lfile) + def getlfilestoupdate(oldstandins, newstandins): changedstandins = set(oldstandins).symmetric_difference(set(newstandins)) filelist = []
--- a/hgext/largefiles/overrides.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/largefiles/overrides.py Sat Sep 27 14:47:52 2014 -0500 @@ -12,7 +12,7 @@ import copy from mercurial import hg, commands, util, cmdutil, scmutil, match as match_, \ - archival, merge, pathutil, revset + archival, pathutil, revset from mercurial.i18n import _ from mercurial.node import hex from hgext import rebase @@ -369,10 +369,6 @@ lfdirstate.write() if mod: raise util.Abort(_('uncommitted changes')) - # XXX handle removed differently - if not opts['clean']: - for lfile in unsure + modified + added: - lfutil.updatestandin(repo, lfutil.standin(lfile)) return orig(ui, repo, *pats, **opts) finally: wlock.release() @@ -430,6 +426,7 @@ removes = set(a[0] for a in actions['r']) newglist = [] + lfmr = [] # LargeFiles: Mark as Removed for action in actions['g']: f, args, msg = action splitstandin = f and lfutil.splitstandin(f) @@ -456,7 +453,16 @@ 'keep (l)argefile or use (n)ormal file?' '$$ &Largefile $$ &Normal file') % lfile if repo.ui.promptchoice(msg, 0) == 0: - actions['r'].append((lfile, None, msg)) + if branchmerge: + # largefile can be restored from standin safely + actions['r'].append((lfile, None, msg)) + else: + # "lfile" should be marked as "removed" without + # removal of itself + lfmr.append((lfile, None, msg)) + + # linear-merge should treat this largefile as 're-added' + actions['a'].append((standin, None, msg)) else: actions['r'].append((standin, None, msg)) newglist.append((lfile, (p2.flags(lfile),), msg)) @@ -465,9 +471,22 @@ newglist.sort() actions['g'] = newglist + if lfmr: + lfmr.sort() + actions['lfmr'] = lfmr return actions +def mergerecordupdates(orig, repo, actions, branchmerge): + if 'lfmr' in actions: + # this should be executed before 'orig', to execute 'remove' + # before all other actions + for lfile, args, msg in actions['lfmr']: + repo.dirstate.remove(lfile) + + return orig(repo, actions, branchmerge) + + # Override filemerge to prompt the user about how they wish to merge # largefiles. This will handle identical edits without prompting the user. def overridefilemerge(origfn, repo, mynode, orig, fcd, fco, fca, labels=None): @@ -695,25 +714,6 @@ finally: wlock.release() -def hgupdaterepo(orig, repo, node, overwrite): - if not overwrite: - # Only call updatelfiles on the standins that have changed to save time - oldstandins = lfutil.getstandinsstate(repo) - - result = orig(repo, node, overwrite) - - filelist = None - if not overwrite: - newstandins = lfutil.getstandinsstate(repo) - filelist = lfutil.getlfilestoupdate(oldstandins, newstandins) - lfcommands.updatelfiles(repo.ui, repo, filelist=filelist) - return result - -def hgmerge(orig, repo, node, force=None, remind=True): - result = orig(repo, node, force, remind) - lfcommands.updatelfiles(repo.ui, repo) - return result - # When we rebase a repository with remotely changed largefiles, we need to # take some extra care so that the largefiles are correctly updated in the # working copy @@ -1157,19 +1157,40 @@ repo.status = oldstatus def overriderollback(orig, ui, repo, **opts): - result = orig(ui, repo, **opts) - merge.update(repo, node=None, branchmerge=False, force=True, - partial=lfutil.isstandin) wlock = repo.wlock() try: + before = repo.dirstate.parents() + orphans = set(f for f in repo.dirstate + if lfutil.isstandin(f) and repo.dirstate[f] != 'r') + result = orig(ui, repo, **opts) + after = repo.dirstate.parents() + if before == after: + return result # no need to restore standins + + pctx = repo['.'] + for f in repo.dirstate: + if lfutil.isstandin(f): + orphans.discard(f) + if repo.dirstate[f] == 'r': + repo.wvfs.unlinkpath(f, ignoremissing=True) + elif f in pctx: + fctx = pctx[f] + repo.wwrite(f, fctx.data(), fctx.flags()) + else: + # content of standin is not so important in 'a', + # 'm' or 'n' (coming from the 2nd parent) cases + lfutil.writestandin(repo, f, '', False) + for standin in orphans: + repo.wvfs.unlinkpath(standin, ignoremissing=True) + lfdirstate = lfutil.openlfdirstate(ui, repo) + orphans = set(lfdirstate) lfiles = lfutil.listlfiles(repo) - oldlfiles = lfutil.listlfiles(repo, repo[None].parents()[0].rev()) for file in lfiles: - if file in oldlfiles: - lfdirstate.normallookup(file) - else: - lfdirstate.add(file) + lfutil.synclfdirstate(repo, lfdirstate, file, True) + orphans.discard(file) + for lfile in orphans: + lfdirstate.drop(lfile) lfdirstate.write() finally: wlock.release() @@ -1243,3 +1264,67 @@ def mercurialsinkafter(orig, sink): sink.repo._isconverting = False orig(sink) + +def mergeupdate(orig, repo, node, branchmerge, force, partial, + *args, **kwargs): + wlock = repo.wlock() + try: + # branch | | | + # merge | force | partial | action + # -------+-------+---------+-------------- + # x | x | x | linear-merge + # o | x | x | branch-merge + # x | o | x | overwrite (as clean update) + # o | o | x | force-branch-merge (*1) + # x | x | o | (*) + # o | x | o | (*) + # x | o | o | overwrite (as revert) + # o | o | o | (*) + # + # (*) don't care + # (*1) deprecated, but used internally (e.g: "rebase --collapse") + + linearmerge = not branchmerge and not force and not partial + + if linearmerge or (branchmerge and force and not partial): + # update standins for linear-merge or force-branch-merge, + # because largefiles in the working directory may be modified + lfdirstate = lfutil.openlfdirstate(repo.ui, repo) + s = lfdirstate.status(match_.always(repo.root, repo.getcwd()), + [], False, False, False) + unsure, modified, added = s[:3] + for lfile in unsure + modified + added: + lfutil.updatestandin(repo, lfutil.standin(lfile)) + + if linearmerge: + # Only call updatelfiles on the standins that have changed + # to save time + oldstandins = lfutil.getstandinsstate(repo) + + result = orig(repo, node, branchmerge, force, partial, *args, **kwargs) + + filelist = None + if linearmerge: + newstandins = lfutil.getstandinsstate(repo) + filelist = lfutil.getlfilestoupdate(oldstandins, newstandins) + + # suppress status message while automated committing + printmessage = not (getattr(repo, "_isrebasing", False) or + getattr(repo, "_istransplanting", False)) + lfcommands.updatelfiles(repo.ui, repo, filelist=filelist, + printmessage=printmessage, + normallookup=partial) + + return result + finally: + wlock.release() + +def scmutilmarktouched(orig, repo, files, *args, **kwargs): + result = orig(repo, files, *args, **kwargs) + + filelist = [lfutil.splitstandin(f) for f in files if lfutil.isstandin(f)] + if filelist: + lfcommands.updatelfiles(repo.ui, repo, filelist=filelist, + printmessage=False, normallookup=True) + + return result
--- a/hgext/largefiles/reposetup.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/largefiles/reposetup.py Sat Sep 27 14:47:52 2014 -0500 @@ -37,11 +37,8 @@ if self.lfstatus: class lfilesmanifestdict(manifest.manifestdict): def __contains__(self, filename): - if super(lfilesmanifestdict, - self).__contains__(filename): - return True - return super(lfilesmanifestdict, - self).__contains__(lfutil.standin(filename)) + orig = super(lfilesmanifestdict, self).__contains__ + return orig(filename) or orig(lfutil.standin(filename)) class lfilesctx(ctx.__class__): def files(self): filenames = super(lfilesctx, self).files() @@ -51,22 +48,20 @@ man1.__class__ = lfilesmanifestdict return man1 def filectx(self, path, fileid=None, filelog=None): + orig = super(lfilesctx, self).filectx try: if filelog is not None: - result = super(lfilesctx, self).filectx( - path, fileid, filelog) + result = orig(path, fileid, filelog) else: - result = super(lfilesctx, self).filectx( - path, fileid) + result = orig(path, fileid) except error.LookupError: # Adding a null character will cause Mercurial to # identify this as a binary file. if filelog is not None: - result = super(lfilesctx, self).filectx( - lfutil.standin(path), fileid, filelog) + result = orig(lfutil.standin(path), fileid, + filelog) else: - result = super(lfilesctx, self).filectx( - lfutil.standin(path), fileid) + result = orig(lfutil.standin(path), fileid) olddata = result.data result.data = lambda: olddata() + '\0' return result @@ -83,178 +78,171 @@ def status(self, node1='.', node2=None, match=None, ignored=False, clean=False, unknown=False, listsubrepos=False): listignored, listclean, listunknown = ignored, clean, unknown + orig = super(lfilesrepo, self).status if not self.lfstatus: - return super(lfilesrepo, self).status(node1, node2, match, - listignored, listclean, listunknown, listsubrepos) - else: - # some calls in this function rely on the old version of status - self.lfstatus = False - ctx1 = self[node1] - ctx2 = self[node2] - working = ctx2.rev() is None - parentworking = working and ctx1 == self['.'] + return orig(node1, node2, match, listignored, listclean, + listunknown, listsubrepos) - def inctx(file, ctx): - try: - if ctx.rev() is None: - return file in ctx.manifest() - ctx[file] - return True - except KeyError: - return False + # some calls in this function rely on the old version of status + self.lfstatus = False + ctx1 = self[node1] + ctx2 = self[node2] + working = ctx2.rev() is None + parentworking = working and ctx1 == self['.'] + + def inctx(file, ctx): + try: + if ctx.rev() is None: + return file in ctx.manifest() + ctx[file] + return True + except KeyError: + return False - if match is None: - match = match_.always(self.root, self.getcwd()) + if match is None: + match = match_.always(self.root, self.getcwd()) - wlock = None + wlock = None + try: try: - try: - # updating the dirstate is optional - # so we don't wait on the lock - wlock = self.wlock(False) - except error.LockError: - pass + # updating the dirstate is optional + # so we don't wait on the lock + wlock = self.wlock(False) + except error.LockError: + pass - # First check if there were files specified on the - # command line. If there were, and none of them were - # largefiles, we should just bail here and let super - # handle it -- thus gaining a big performance boost. - lfdirstate = lfutil.openlfdirstate(ui, self) - if match.files() and not match.anypats(): - for f in lfdirstate: - if match(f): - break - else: - return super(lfilesrepo, self).status(node1, node2, - match, listignored, listclean, + # First check if there were files specified on the + # command line. If there were, and none of them were + # largefiles, we should just bail here and let super + # handle it -- thus gaining a big performance boost. + lfdirstate = lfutil.openlfdirstate(ui, self) + if match.files() and not match.anypats(): + for f in lfdirstate: + if match(f): + break + else: + return orig(node1, node2, match, listignored, listclean, listunknown, listsubrepos) - # Create a copy of match that matches standins instead - # of largefiles. - def tostandins(files): - if not working: - return files - newfiles = [] - dirstate = self.dirstate - for f in files: - sf = lfutil.standin(f) - if sf in dirstate: - newfiles.append(sf) - elif sf in dirstate.dirs(): - # Directory entries could be regular or - # standin, check both - newfiles.extend((f, sf)) - else: - newfiles.append(f) - return newfiles + # Create a copy of match that matches standins instead + # of largefiles. + def tostandins(files): + if not working: + return files + newfiles = [] + dirstate = self.dirstate + for f in files: + sf = lfutil.standin(f) + if sf in dirstate: + newfiles.append(sf) + elif sf in dirstate.dirs(): + # Directory entries could be regular or + # standin, check both + newfiles.extend((f, sf)) + else: + newfiles.append(f) + return newfiles - m = copy.copy(match) - m._files = tostandins(m._files) + m = copy.copy(match) + m._files = tostandins(m._files) - result = super(lfilesrepo, self).status(node1, node2, m, - ignored, clean, unknown, listsubrepos) - if working: + result = orig(node1, node2, m, ignored, clean, unknown, + listsubrepos) + if working: - def sfindirstate(f): - sf = lfutil.standin(f) - dirstate = self.dirstate - return sf in dirstate or sf in dirstate.dirs() + def sfindirstate(f): + sf = lfutil.standin(f) + dirstate = self.dirstate + return sf in dirstate or sf in dirstate.dirs() - match._files = [f for f in match._files - if sfindirstate(f)] - # Don't waste time getting the ignored and unknown - # files from lfdirstate - s = lfdirstate.status(match, [], False, - listclean, False) - (unsure, modified, added, removed, missing, _unknown, - _ignored, clean) = s - if parentworking: - for lfile in unsure: - standin = lfutil.standin(lfile) - if standin not in ctx1: - # from second parent - modified.append(lfile) - elif ctx1[standin].data().strip() \ - != lfutil.hashfile(self.wjoin(lfile)): - modified.append(lfile) - else: + match._files = [f for f in match._files + if sfindirstate(f)] + # Don't waste time getting the ignored and unknown + # files from lfdirstate + s = lfdirstate.status(match, [], False, + listclean, False) + (unsure, modified, added, removed, missing, _unknown, + _ignored, clean) = s + if parentworking: + for lfile in unsure: + standin = lfutil.standin(lfile) + if standin not in ctx1: + # from second parent + modified.append(lfile) + elif ctx1[standin].data().strip() \ + != lfutil.hashfile(self.wjoin(lfile)): + modified.append(lfile) + else: + if listclean: clean.append(lfile) - lfdirstate.normal(lfile) - else: - tocheck = unsure + modified + added + clean - modified, added, clean = [], [], [] + lfdirstate.normal(lfile) + else: + tocheck = unsure + modified + added + clean + modified, added, clean = [], [], [] - for lfile in tocheck: - standin = lfutil.standin(lfile) - if inctx(standin, ctx1): - if ctx1[standin].data().strip() != \ - lfutil.hashfile(self.wjoin(lfile)): - modified.append(lfile) - else: - clean.append(lfile) - else: - added.append(lfile) + for lfile in tocheck: + standin = lfutil.standin(lfile) + if inctx(standin, ctx1): + if ctx1[standin].data().strip() != \ + lfutil.hashfile(self.wjoin(lfile)): + modified.append(lfile) + elif listclean: + clean.append(lfile) + else: + added.append(lfile) - # Standins no longer found in lfdirstate has been - # removed - for standin in ctx1.manifest(): - if not lfutil.isstandin(standin): - continue - lfile = lfutil.splitstandin(standin) - if not match(lfile): - continue - if lfile not in lfdirstate: - removed.append(lfile) + # Standins no longer found in lfdirstate has been + # removed + for standin in ctx1.walk(lfutil.getstandinmatcher(self)): + lfile = lfutil.splitstandin(standin) + if not match(lfile): + continue + if lfile not in lfdirstate: + removed.append(lfile) - # Filter result lists - result = list(result) - - # Largefiles are not really removed when they're - # still in the normal dirstate. Likewise, normal - # files are not really removed if they are still in - # lfdirstate. This happens in merges where files - # change type. - removed = [f for f in removed - if f not in self.dirstate] - result[2] = [f for f in result[2] - if f not in lfdirstate] + # Filter result lists + result = list(result) - lfiles = set(lfdirstate._map) - # Unknown files - result[4] = set(result[4]).difference(lfiles) - # Ignored files - result[5] = set(result[5]).difference(lfiles) - # combine normal files and largefiles - normals = [[fn for fn in filelist - if not lfutil.isstandin(fn)] - for filelist in result] - lfiles = (modified, added, removed, missing, [], [], - clean) - result = [sorted(list1 + list2) - for (list1, list2) in zip(normals, lfiles)] - else: - def toname(f): - if lfutil.isstandin(f): - return lfutil.splitstandin(f) - return f - result = [[toname(f) for f in items] - for items in result] + # Largefiles are not really removed when they're + # still in the normal dirstate. Likewise, normal + # files are not really removed if they are still in + # lfdirstate. This happens in merges where files + # change type. + removed = [f for f in removed + if f not in self.dirstate] + result[2] = [f for f in result[2] + if f not in lfdirstate] - if wlock: - lfdirstate.write() - - finally: - if wlock: - wlock.release() + lfiles = set(lfdirstate._map) + # Unknown files + result[4] = set(result[4]).difference(lfiles) + # Ignored files + result[5] = set(result[5]).difference(lfiles) + # combine normal files and largefiles + normals = [[fn for fn in filelist + if not lfutil.isstandin(fn)] + for filelist in result] + lfstatus = (modified, added, removed, missing, [], [], + clean) + result = [sorted(list1 + list2) + for (list1, list2) in zip(normals, lfstatus)] + else: + def toname(f): + if lfutil.isstandin(f): + return lfutil.splitstandin(f) + return f + result = [[toname(f) for f in items] + for items in result] - if not listunknown: - result[4] = [] - if not listignored: - result[5] = [] - if not listclean: - result[6] = [] - self.lfstatus = True - return result + if wlock: + lfdirstate.write() + + finally: + if wlock: + wlock.release() + + self.lfstatus = True + return result # As part of committing, copy all of the largefiles into the # cache. @@ -272,19 +260,29 @@ wlock = self.wlock() try: - # Case 0: Rebase or Transplant - # We have to take the time to pull down the new largefiles now. - # Otherwise, any largefiles that were modified in the - # destination changesets get overwritten, either by the rebase - # or in the first commit after the rebase or transplant. - # updatelfiles will update the dirstate to mark any pulled - # largefiles as modified + # Case 0: Automated committing + # + # While automated committing (like rebase, transplant + # and so on), this code path is used to avoid: + # (1) updating standins, because standins should + # be already updated at this point + # (2) aborting when stadnins are matched by "match", + # because automated committing may specify them directly + # if getattr(self, "_isrebasing", False) or \ getattr(self, "_istransplanting", False): - lfcommands.updatelfiles(self.ui, self, filelist=None, - printmessage=False) result = orig(text=text, user=user, date=date, match=match, force=force, editor=editor, extra=extra) + + if result: + lfdirstate = lfutil.openlfdirstate(ui, self) + for f in self[result].files(): + if lfutil.isstandin(f): + lfile = lfutil.splitstandin(f) + lfutil.synclfdirstate(self, lfdirstate, lfile, + False) + lfdirstate.write() + return result # Case 1: user calls commit with no specific files or # include/exclude patterns: refresh and commit all files that @@ -381,10 +379,6 @@ if f in lfiles or fstandin in standins: continue - # append directory separator to avoid collisions - if not fstandin.endswith(os.sep): - fstandin += os.sep - actualfiles.append(f) match._files = actualfiles
--- a/hgext/largefiles/uisetup.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/largefiles/uisetup.py Sat Sep 27 14:47:52 2014 -0500 @@ -99,6 +99,10 @@ overrides.overridecheckunknownfile) entry = extensions.wrapfunction(merge, 'calculateupdates', overrides.overridecalculateupdates) + entry = extensions.wrapfunction(merge, 'recordupdates', + overrides.mergerecordupdates) + entry = extensions.wrapfunction(merge, 'update', + overrides.mergeupdate) entry = extensions.wrapfunction(filemerge, 'filemerge', overrides.overridefilemerge) entry = extensions.wrapfunction(cmdutil, 'copy', @@ -115,15 +119,15 @@ entry = extensions.wrapfunction(commands, 'revert', overrides.overriderevert) - extensions.wrapfunction(hg, 'updaterepo', overrides.hgupdaterepo) - extensions.wrapfunction(hg, 'merge', overrides.hgmerge) - extensions.wrapfunction(archival, 'archive', overrides.overridearchive) extensions.wrapfunction(subrepo.hgsubrepo, 'archive', overrides.hgsubrepoarchive) extensions.wrapfunction(cmdutil, 'bailifchanged', overrides.overridebailifchanged) + extensions.wrapfunction(scmutil, 'marktouched', + overrides.scmutilmarktouched) + # create the new wireproto commands ... wireproto.commands['putlfile'] = (proto.putlfile, 'sha') wireproto.commands['getlfile'] = (proto.getlfile, 'sha')
--- a/hgext/mq.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/mq.py Sat Sep 27 14:47:52 2014 -0500 @@ -104,6 +104,52 @@ def __repr__(self): return hex(self.node) + ':' + self.name +# The order of the headers in 'hg export' HG patches: +HGHEADERS = [ +# '# HG changeset patch', + '# User ', + '# Date ', + '# ', + '# Branch ', + '# Node ID ', + '# Parent ', # can occur twice for merges - but that is not relevant for mq + '', # all lines after headers 'has' this prefix - simplifies the algorithm + ] + +def inserthgheader(lines, header, value): + """Assuming lines contains a HG patch header, add a header line with value. + >>> try: inserthgheader([], '# Date ', 'z') + ... except ValueError, inst: print "oops" + oops + >>> inserthgheader(['# HG changeset patch'], '# Date ', 'z') + ['# HG changeset patch', '# Date z'] + >>> inserthgheader(['# HG changeset patch', ''], '# Date ', 'z') + ['# HG changeset patch', '# Date z', ''] + >>> inserthgheader(['# HG changeset patch', '# User y'], '# Date ', 'z') + ['# HG changeset patch', '# User y', '# Date z'] + >>> inserthgheader(['# HG changeset patch', '# Date y'], '# Date ', 'z') + ['# HG changeset patch', '# Date z'] + >>> inserthgheader(['# HG changeset patch', '', '# Date y'], '# Date ', 'z') + ['# HG changeset patch', '# Date z', '', '# Date y'] + >>> inserthgheader(['# HG changeset patch', '# Parent y'], '# Date ', 'z') + ['# HG changeset patch', '# Date z', '# Parent y'] + """ + start = lines.index('# HG changeset patch') + 1 + newindex = HGHEADERS.index(header) + for i in range(start, len(lines)): + line = lines[i] + for lineindex, h in enumerate(HGHEADERS): + if line.startswith(h): + if lineindex < newindex: + break # next line + if lineindex == newindex: + lines[i] = header + value + else: + lines.insert(i, header + value) + return lines + lines.append(header + value) + return lines + class patchheader(object): def __init__(self, pf, plainmode=False): def eatdiff(lines): @@ -150,7 +196,7 @@ elif line.startswith("# Date "): date = line[7:] elif line.startswith("# Parent "): - parent = line[9:].lstrip() + parent = line[9:].lstrip() # handle double trailing space elif line.startswith("# Branch "): branch = line[9:] elif line.startswith("# Node ID "): @@ -191,7 +237,6 @@ # make sure message isn't empty if format and format.startswith("tag") and subject: - message.insert(0, "") message.insert(0, subject) self.message = message @@ -203,41 +248,45 @@ self.nodeid = nodeid self.branch = branch self.haspatch = diffstart > 1 - self.plainmode = plainmode + self.plainmode = (plainmode or + '# HG changeset patch' not in self.comments and + util.any(c.startswith('Date: ') or + c.startswith('From: ') + for c in self.comments)) def setuser(self, user): if not self.updateheader(['From: ', '# User '], user): try: - patchheaderat = self.comments.index('# HG changeset patch') - self.comments.insert(patchheaderat + 1, '# User ' + user) + inserthgheader(self.comments, '# User ', user) except ValueError: - if self.plainmode or self._hasheader(['Date: ']): + if self.plainmode: self.comments = ['From: ' + user] + self.comments else: - tmp = ['# HG changeset patch', '# User ' + user, ''] + tmp = ['# HG changeset patch', '# User ' + user] self.comments = tmp + self.comments self.user = user def setdate(self, date): if not self.updateheader(['Date: ', '# Date '], date): try: - patchheaderat = self.comments.index('# HG changeset patch') - self.comments.insert(patchheaderat + 1, '# Date ' + date) + inserthgheader(self.comments, '# Date ', date) except ValueError: - if self.plainmode or self._hasheader(['From: ']): + if self.plainmode: self.comments = ['Date: ' + date] + self.comments else: - tmp = ['# HG changeset patch', '# Date ' + date, ''] + tmp = ['# HG changeset patch', '# Date ' + date] self.comments = tmp + self.comments self.date = date def setparent(self, parent): - if not self.updateheader(['# Parent '], parent): + if not (self.updateheader(['# Parent '], parent) or + self.updateheader(['# Parent '], parent)): try: - patchheaderat = self.comments.index('# HG changeset patch') - self.comments.insert(patchheaderat + 1, '# Parent ' + parent) + inserthgheader(self.comments, '# Parent ', parent) except ValueError: - pass + if not self.plainmode: + tmp = ['# HG changeset patch', '# Parent ' + parent] + self.comments = tmp + self.comments self.parent = parent def setmessage(self, message): @@ -258,18 +307,11 @@ break return res - def _hasheader(self, prefixes): - '''Check if a header starts with any of the given prefixes.''' - for prefix in prefixes: - for comment in self.comments: - if comment.startswith(prefix): - return True - return False - def __str__(self): - if not self.comments: + s = '\n'.join(self.comments).rstrip() + if not s: return '' - return '\n'.join(self.comments) + '\n\n' + return s + '\n\n' def _delmsg(self): '''Remove existing message, keeping the rest of the comments fields. @@ -621,7 +663,7 @@ # apply failed, strip away that rev and merge. hg.clean(repo, head) - strip(self.ui, repo, [n], update=False, backup='strip') + strip(self.ui, repo, [n], update=False, backup=False) ctx = repo[rev] ret = hg.merge(repo, rev) @@ -816,12 +858,14 @@ merged.append(f) else: removed.append(f) + repo.dirstate.beginparentchange() for f in removed: repo.dirstate.remove(f) for f in merged: repo.dirstate.merge(f) p1, p2 = repo.dirstate.parents() repo.setparents(p1, merge) + repo.dirstate.endparentchange() if all_files and '.hgsubstate' in all_files: wctx = repo[None] @@ -930,7 +974,12 @@ oldqbase = repo[qfinished[0]] tphase = repo.ui.config('phases', 'new-commit', phases.draft) if oldqbase.phase() > tphase and oldqbase.p1().phase() <= tphase: - phases.advanceboundary(repo, tphase, qfinished) + tr = repo.transaction('qfinish') + try: + phases.advanceboundary(repo, tr, tphase, qfinished) + tr.close() + finally: + tr.release() def delete(self, repo, patches, opts): if not patches and not opts.get('rev'): @@ -1025,6 +1074,7 @@ """ msg = opts.get('msg') edit = opts.get('edit') + editform = opts.get('editform', 'mq.qnew') user = opts.get('user') date = opts.get('date') if date: @@ -1062,24 +1112,8 @@ raise util.Abort(_('cannot write patch "%s": %s') % (patchfn, e.strerror)) try: - if self.plainmode: - if user: - p.write("From: " + user + "\n") - if not date: - p.write("\n") - if date: - p.write("Date: %d %d\n\n" % date) - else: - p.write("# HG changeset patch\n") - p.write("# Parent " - + hex(repo[None].p1().node()) + "\n") - if user: - p.write("# User " + user + "\n") - if date: - p.write("# Date %s %s\n\n" % date) - defaultmsg = "[mq]: %s" % patchfn - editor = cmdutil.getcommiteditor() + editor = cmdutil.getcommiteditor(editform=editform) if edit: def finishdesc(desc): if desc.rstrip(): @@ -1089,7 +1123,8 @@ # i18n: this message is shown in editor with "HG: " prefix extramsg = _('Leave message empty to use default message.') editor = cmdutil.getcommiteditor(finishdesc=finishdesc, - extramsg=extramsg) + extramsg=extramsg, + editform=editform) commitmsg = msg else: commitmsg = msg or defaultmsg @@ -1105,9 +1140,17 @@ self.seriesdirty = True self.applieddirty = True nctx = repo[n] - if nctx.description() != defaultmsg.rstrip(): - msg = nctx.description() + "\n\n" - p.write(msg) + ph = patchheader(self.join(patchfn), self.plainmode) + if user: + ph.setuser(user) + if date: + ph.setdate('%s %s' % date) + ph.setparent(hex(nctx.p1().node())) + msg = nctx.description().strip() + if msg == defaultmsg.strip(): + msg = '' + ph.setmessage(msg) + p.write(str(ph)) if commitfiles: parent = self.qparents(repo, n) if inclsubs: @@ -1444,7 +1487,7 @@ if keepchanges and tobackup: raise util.Abort(_("local changes found, refresh first")) self.backup(repo, tobackup) - + repo.dirstate.beginparentchange() for f in a: util.unlinkpath(repo.wjoin(f), ignoremissing=True) repo.dirstate.drop(f) @@ -1453,10 +1496,11 @@ repo.wwrite(f, fctx.data(), fctx.flags()) repo.dirstate.normal(f) repo.setparents(qp, nullid) + repo.dirstate.endparentchange() for patch in reversed(self.applied[start:end]): self.ui.status(_("popping %s\n") % patch.name) del self.applied[start:end] - strip(self.ui, repo, [rev], update=False, backup='strip') + strip(self.ui, repo, [rev], update=False, backup=False) for s, state in repo['.'].substate.items(): repo['.'].sub(s).get(state) if self.applied: @@ -1485,6 +1529,7 @@ return 1 msg = opts.get('msg', '').rstrip() edit = opts.get('edit') + editform = opts.get('editform', 'mq.qrefresh') newuser = opts.get('user') newdate = opts.get('date') if newdate: @@ -1591,6 +1636,7 @@ bmlist = repo[top].bookmarks() try: + repo.dirstate.beginparentchange() if diffopts.git or diffopts.upgrade: copies = {} for dst in a: @@ -1643,9 +1689,10 @@ # 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='strip') + strip(self.ui, repo, [top], update=False, backup=False) except: # re-raises repo.dirstate.invalidate() raise @@ -1654,7 +1701,7 @@ # might be nice to attempt to roll back strip after this defaultmsg = "[mq]: %s" % patchfn - editor = cmdutil.getcommiteditor() + editor = cmdutil.getcommiteditor(editform=editform) if edit: def finishdesc(desc): if desc.rstrip(): @@ -1664,7 +1711,8 @@ # i18n: this message is shown in editor with "HG: " prefix extramsg = _('Leave message empty to use default message.') editor = cmdutil.getcommiteditor(finishdesc=finishdesc, - extramsg=extramsg) + extramsg=extramsg, + editform=editform) message = msg or "\n".join(ph.message) elif not msg: if not ph.message: @@ -1842,7 +1890,7 @@ update = True else: update = False - strip(self.ui, repo, [rev], update=update, backup='strip') + strip(self.ui, repo, [rev], update=update, backup=False) if qpp: self.ui.warn(_("saved queue repository parents: %s %s\n") % (short(qpp[0]), short(qpp[1]))) @@ -1966,41 +2014,49 @@ lastparent = None diffopts = self.diffopts({'git': git}) - for r in rev: - if not repo[r].mutable(): - raise util.Abort(_('revision %d is not mutable') % r, - hint=_('see "hg help phases" for details')) - p1, p2 = repo.changelog.parentrevs(r) - n = repo.changelog.node(r) - if p2 != nullrev: - raise util.Abort(_('cannot import merge revision %d') % r) - if lastparent and lastparent != r: - raise util.Abort(_('revision %d is not the parent of %d') - % (r, lastparent)) - lastparent = p1 - - if not patchname: - patchname = normname('%d.diff' % r) - checkseries(patchname) - self.checkpatchname(patchname, force) - self.fullseries.insert(0, patchname) - - patchf = self.opener(patchname, "w") - cmdutil.export(repo, [n], fp=patchf, opts=diffopts) - patchf.close() - - se = statusentry(n, patchname) - self.applied.insert(0, se) - - self.added.append(patchname) - imported.append(patchname) - patchname = None - if rev and repo.ui.configbool('mq', 'secret', False): - # if we added anything with --rev, move the secret root - phases.retractboundary(repo, phases.secret, [n]) - self.parseseries() - self.applieddirty = True - self.seriesdirty = True + tr = repo.transaction('qimport') + try: + for r in rev: + if not repo[r].mutable(): + raise util.Abort(_('revision %d is not mutable') % r, + hint=_('see "hg help phases" ' + 'for details')) + p1, p2 = repo.changelog.parentrevs(r) + n = repo.changelog.node(r) + if p2 != nullrev: + raise util.Abort(_('cannot import merge revision %d') + % r) + if lastparent and lastparent != r: + raise util.Abort(_('revision %d is not the parent of ' + '%d') + % (r, lastparent)) + lastparent = p1 + + if not patchname: + patchname = normname('%d.diff' % r) + checkseries(patchname) + self.checkpatchname(patchname, force) + self.fullseries.insert(0, patchname) + + patchf = self.opener(patchname, "w") + cmdutil.export(repo, [n], fp=patchf, opts=diffopts) + patchf.close() + + se = statusentry(n, patchname) + self.applied.insert(0, se) + + self.added.append(patchname) + imported.append(patchname) + patchname = None + if rev and repo.ui.configbool('mq', 'secret', False): + # if we added anything with --rev, move the secret root + phases.retractboundary(repo, tr, phases.secret, [n]) + self.parseseries() + self.applieddirty = True + self.seriesdirty = True + tr.close() + finally: + tr.release() for i, filename in enumerate(files): if existing: @@ -2585,7 +2641,8 @@ diffopts = q.patchopts(q.diffopts(), *patches) wlock = repo.wlock() try: - q.refresh(repo, msg=message, git=diffopts.git, edit=opts.get('edit')) + q.refresh(repo, msg=message, git=diffopts.git, edit=opts.get('edit'), + editform='mq.qfold') q.delete(repo, patches, opts) q.savedirty() finally:
--- a/hgext/purge.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/purge.py Sat Sep 27 14:47:52 2014 -0500 @@ -26,7 +26,7 @@ from mercurial import util, commands, cmdutil, scmutil from mercurial.i18n import _ -import os, stat +import os cmdtable = {} command = cmdutil.command(cmdtable) @@ -95,27 +95,17 @@ else: ui.write('%s%s' % (name, eol)) - def removefile(path): - try: - os.remove(path) - except OSError: - # read-only files cannot be unlinked under Windows - s = os.stat(path) - if (s.st_mode & stat.S_IWRITE) != 0: - raise - os.chmod(path, stat.S_IMODE(s.st_mode) | stat.S_IWRITE) - os.remove(path) - - directories = [] match = scmutil.match(repo[None], dirs, opts) - match.explicitdir = match.traversedir = directories.append + if removedirs: + directories = [] + match.explicitdir = match.traversedir = directories.append status = repo.status(match=match, ignored=opts['all'], unknown=True) if removefiles: for f in sorted(status[4] + status[5]): if act: ui.note(_('removing file %s\n') % f) - remove(removefile, f) + remove(util.unlink, f) if removedirs: for f in sorted(directories, reverse=True):
--- a/hgext/rebase.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/rebase.py Sat Sep 27 14:47:52 2014 -0500 @@ -52,8 +52,8 @@ [('s', 'source', '', _('rebase from the specified changeset'), _('REV')), ('b', 'base', '', - _('rebase from the base of the specified changeset ' - '(up to greatest common ancestor of base and dest)'), + _('rebase the tree around the specified changeset without ' + 'ancestors of dest'), _('REV')), ('r', 'rev', [], _('rebase these revisions'), @@ -69,6 +69,7 @@ ('', 'keep', False, _('keep original changesets')), ('', 'keepbranches', False, _('keep original branch names')), ('D', 'detach', False, _('(DEPRECATED)')), + ('i', 'interactive', False, _('(DEPRECATED)')), ('t', 'tool', '', _('specify merge tool')), ('c', 'continue', False, _('continue an interrupted rebase')), ('a', 'abort', False, _('abort an interrupted rebase'))] + @@ -138,7 +139,6 @@ skipped = set() targetancestors = set() - editor = cmdutil.getcommiteditor(**opts) lock = wlock = None try: @@ -164,6 +164,11 @@ # other extensions keepopen = opts.get('keepopen', False) + if opts.get('interactive'): + msg = _("interactive history editing is supported by the " + "'histedit' extension (see 'hg help histedit')") + raise util.Abort(msg) + if collapsemsg and not collapsef: raise util.Abort( _('message can only be specified with collapse')) @@ -354,11 +359,16 @@ p1rev = repo[rev].p1().rev() cmdutil.duplicatecopies(repo, rev, p1rev, skiprev=target) if not collapsef: + merging = repo[p2].rev() != nullrev + editform = cmdutil.mergeeditform(merging, 'rebase') + editor = cmdutil.getcommiteditor(editform=editform, **opts) newrev = concludenode(repo, rev, p1, p2, extrafn=extrafn, editor=editor) else: # Skip commit if we are collapsing + repo.dirstate.beginparentchange() repo.setparents(repo[p1].node()) + repo.dirstate.endparentchange() newrev = None # Update the state if newrev is not None: @@ -376,6 +386,8 @@ if collapsef and not keepopen: p1, p2 = defineparents(repo, min(state), target, state, targetancestors) + editopt = opts.get('edit') + editform = 'rebase.collapse' if collapsemsg: commitmsg = collapsemsg else: @@ -383,7 +395,8 @@ for rebased in state: if rebased not in skipped and state[rebased] > nullmerge: commitmsg += '\n* %s' % repo[rebased].description() - editor = cmdutil.getcommiteditor(edit=True) + editopt = True + editor = cmdutil.getcommiteditor(edit=editopt, editform=editform) newrev = concludenode(repo, rev, p1, external, commitmsg=commitmsg, extrafn=extrafn, editor=editor) for oldrev in state.iterkeys(): @@ -461,22 +474,27 @@ def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None): 'Commit the changes and store useful information in extra' 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() extra = {'rebase_source': ctx.hex()} if extrafn: extrafn(ctx, extra) - # Commit might fail if unresolved files exist - newrev = repo.commit(text=commitmsg, user=ctx.user(), - date=ctx.date(), extra=extra, editor=editor) + + backup = repo.ui.backupconfig('phases', 'new-commit') + try: + targetphase = max(ctx.phase(), phases.draft) + repo.ui.setconfig('phases', 'new-commit', targetphase, 'rebase') + # Commit might fail if unresolved files exist + newrev = repo.commit(text=commitmsg, user=ctx.user(), + date=ctx.date(), extra=extra, editor=editor) + finally: + repo.ui.restoreconfig(backup) + repo.dirstate.setbranch(repo[newrev].branch()) - targetphase = max(ctx.phase(), phases.draft) - # retractboundary doesn't overwrite upper phase inherited from parent - newnode = repo[newrev].node() - if newnode: - phases.retractboundary(repo, targetphase, [newnode]) return newrev except util.Abort: # Invalidate the previous setparents
--- a/hgext/shelve.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/shelve.py Sat Sep 27 14:47:52 2014 -0500 @@ -25,7 +25,7 @@ from mercurial.node import nullid, nullrev, bin, hex from mercurial import changegroup, cmdutil, scmutil, phases, commands from mercurial import error, hg, mdiff, merge, patch, repair, util -from mercurial import templatefilters, changegroup, exchange +from mercurial import templatefilters, exchange from mercurial import lock as lockmod from hgext import rebase import errno @@ -73,7 +73,8 @@ try: gen = exchange.readbundle(self.repo.ui, fp, self.fname, self.vfs) changegroup.addchangegroup(self.repo, gen, 'unshelve', - 'bundle:' + self.vfs.join(self.fname)) + 'bundle:' + self.vfs.join(self.fname), + targetphase=phases.secret) finally: fp.close() @@ -177,10 +178,14 @@ hasmq = util.safehasattr(repo, 'mq') if hasmq: saved, repo.mq.checkapplied = repo.mq.checkapplied, False + backup = repo.ui.backupconfig('phases', 'new-commit') try: + repo.ui. setconfig('phases', 'new-commit', phases.secret) + editor = cmdutil.getcommiteditor(editform='shelve.shelve', **opts) return repo.commit(message, user, opts.get('date'), match, - editor=cmdutil.getcommiteditor(**opts)) + editor=editor) finally: + repo.ui.restoreconfig(backup) if hasmq: repo.mq.checkapplied = saved @@ -234,8 +239,6 @@ ui.status(_("nothing changed\n")) return 1 - phases.retractboundary(repo, phases.secret, [node]) - fp = shelvedfile(repo, name, 'files').opener('wb') fp.write('\0'.join(shelvedfiles)) @@ -266,7 +269,7 @@ wlock = None try: wlock = repo.wlock() - for (name, _) in repo.vfs.readdir('shelved'): + for (name, _type) in repo.vfs.readdir('shelved'): suffix = name.rsplit('.', 1)[-1] if suffix in ('hg', 'files', 'patch'): shelvedfile(repo, name).unlink() @@ -300,7 +303,7 @@ raise return [] info = [] - for (name, _) in names: + for (name, _type) in names: pfx, sfx = name.rsplit('.', 1) if not pfx or sfx != 'patch': continue @@ -388,7 +391,7 @@ mergefiles(ui, repo, state.wctx, state.pendingctx) - repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve') + repair.strip(ui, repo, state.stripnodes, backup=False, topic='shelve') shelvedstate.clear(repo) ui.warn(_("unshelve of '%s' aborted\n") % state.name) finally: @@ -410,9 +413,11 @@ for file in u: if file in files: util.rename(file, file + ".orig") + ui.pushbuffer(True) cmdutil.revert(ui, repo, shelvectx, repo.dirstate.parents(), *pathtofiles(repo, files), **{'no_backup': True}) + ui.popbuffer() finally: ui.quiet = oldquiet @@ -457,7 +462,7 @@ mergefiles(ui, repo, state.wctx, shelvectx) state.stripnodes.append(shelvectx.node()) - repair.strip(ui, repo, state.stripnodes, backup='none', topic='shelve') + repair.strip(ui, repo, state.stripnodes, backup=False, topic='shelve') shelvedstate.clear(repo) unshelvecleanup(ui, repo, state.name, opts) ui.status(_("unshelve of '%s' complete\n") % state.name) @@ -558,10 +563,13 @@ if hasmq: saved, repo.mq.checkapplied = repo.mq.checkapplied, False + backup = repo.ui.backupconfig('phases', 'new-commit') try: + repo.ui. setconfig('phases', 'new-commit', phases.secret) return repo.commit(message, 'shelve@localhost', opts.get('date'), match) finally: + repo.ui.restoreconfig(backup) if hasmq: repo.mq.checkapplied = saved @@ -574,8 +582,6 @@ ui.quiet = True shelvedfile(repo, basename, 'hg').applybundle() - nodes = [ctx.node() for ctx in repo.set('%d:', oldtiprev)] - phases.retractboundary(repo, phases.secret, nodes) ui.quiet = oldquiet
--- a/hgext/strip.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/strip.py Sat Sep 27 14:47:52 2014 -0500 @@ -42,7 +42,7 @@ raise util.Abort(_("local changed subrepos found" + excsuffix)) return m, a, r, d -def strip(ui, repo, revs, update=True, backup="all", force=None, bookmark=None): +def strip(ui, repo, revs, update=True, backup=True, force=None, bookmark=None): wlock = lock = None try: wlock = repo.wlock() @@ -114,11 +114,9 @@ Return 0 on success. """ - backup = 'all' - if opts.get('backup'): - backup = 'strip' - elif opts.get('no_backup') or opts.get('nobackup'): - backup = 'none' + backup = True + if opts.get('no_backup') or opts.get('nobackup'): + backup = False cl = repo.changelog revs = list(revs) + opts.get('rev')
--- a/hgext/transplant.py Mon Sep 22 23:46:38 2014 +0900 +++ b/hgext/transplant.py Sat Sep 27 14:47:52 2014 -0500 @@ -86,7 +86,10 @@ self.opener = scmutil.opener(self.path) self.transplants = transplants(self.path, 'transplants', opener=self.opener) - self.editor = cmdutil.getcommiteditor(**opts) + def getcommiteditor(): + editform = cmdutil.mergeeditform(repo[None], 'transplant') + return cmdutil.getcommiteditor(editform=editform, **opts) + self.getcommiteditor = getcommiteditor def applied(self, repo, node, parent): '''returns True if a node is already an ancestor of parent @@ -286,7 +289,7 @@ m = match.exact(repo.root, '', files) n = repo.commit(message, user, date, extra=extra, match=m, - editor=self.editor) + editor=self.getcommiteditor()) if not n: self.ui.warn(_('skipping emptied changeset %s\n') % short(node)) return None @@ -342,7 +345,7 @@ if merge: repo.setparents(p1, parents[1]) n = repo.commit(message, user, date, extra=extra, - editor=self.editor) + editor=self.getcommiteditor()) if not n: raise util.Abort(_('commit failed')) if not merge:
--- a/i18n/check-translation.py Mon Sep 22 23:46:38 2014 +0900 +++ b/i18n/check-translation.py Sat Sep 27 14:47:52 2014 -0500 @@ -7,7 +7,7 @@ checkers = [] -def checker(level, msgidpat): +def levelchecker(level, msgidpat): def decorator(func): if msgidpat: match = re.compile(msgidpat).search @@ -33,7 +33,7 @@ #################### def fatalchecker(msgidpat=None): - return checker('fatal', msgidpat) + return levelchecker('fatal', msgidpat) @fatalchecker(r'\$\$') def promptchoice(pe): @@ -64,7 +64,7 @@ #################### def warningchecker(msgidpat=None): - return checker('warning', msgidpat) + return levelchecker('warning', msgidpat) @warningchecker() def taildoublecolons(pe):
--- a/mercurial/ancestor.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/ancestor.py Sat Sep 27 14:47:52 2014 -0500 @@ -246,6 +246,14 @@ else: self._containsseen = set() + def __nonzero__(self): + """False if the set is empty, True otherwise.""" + try: + iter(self).next() + return True + except StopIteration: + return False + def __iter__(self): """Generate the ancestors of _initrevs in reverse topological order.
--- a/mercurial/bookmarks.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/bookmarks.py Sat Sep 27 14:47:52 2014 -0500 @@ -228,7 +228,8 @@ w = repo.wlock() try: marks = repo._bookmarks - if hex(marks.get(key, '')) != old: + existing = hex(marks.get(key, '')) + if existing != old and existing != new: return False if new == '': del marks[key]
--- a/mercurial/branchmap.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/branchmap.py Sat Sep 27 14:47:52 2014 -0500 @@ -62,8 +62,6 @@ partial = None return partial - - ### Nearest subset relation # Nearest subset of filter X is a filter Y so that: # * Y is included in X, @@ -241,6 +239,10 @@ newbranches.setdefault(branch, []).append(r) if closesbranch: self._closednodes.add(cl.node(r)) + + # fetch current topological heads to speed up filtering + topoheads = set(cl.headrevs()) + # if older branchheads are reachable from new ones, they aren't # really branchheads. Note checking parents is insufficient: # 1 (branch a) -> 2 (branch b) -> 3 (branch a) @@ -254,14 +256,13 @@ newheadrevs.sort() bheadset.update(newheadrevs) - # This loop prunes out two kinds of heads - heads that are - # superseded by a head in newheadrevs, and newheadrevs that are not - # heads because an existing head is their descendant. - while newheadrevs: - latest = newheadrevs.pop() - if latest not in bheadset: - continue - ancestors = set(cl.ancestors([latest], min(bheadset))) + # This prunes out two kinds of heads - heads that are superseded by + # a head in newheadrevs, and newheadrevs that are not heads because + # an existing head is their descendant. + uncertain = bheadset - topoheads + if uncertain: + floorrev = min(uncertain) + ancestors = set(cl.ancestors(newheadrevs, floorrev)) bheadset -= ancestors bheadrevs = sorted(bheadset) self[branch] = [cl.node(rev) for rev in bheadrevs]
--- a/mercurial/bundle2.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/bundle2.py Sat Sep 27 14:47:52 2014 -0500 @@ -146,6 +146,7 @@ import struct import urllib import string +import obsolete import pushkey import changegroup, error @@ -775,6 +776,23 @@ self.consumed = True return data +capabilities = {'HG2X': (), + 'b2x:listkeys': (), + 'b2x:pushkey': (), + 'b2x:changegroup': (), + } + +def getrepocaps(repo): + """return the bundle2 capabilities for a given repo + + Exists to allow extensions (like evolution) to mutate the capabilities. + """ + caps = capabilities.copy() + if obsolete._enabled: + supportedformat = tuple('V%i' % v for v in obsolete.formats) + caps['b2x:obsmarkers'] = supportedformat + return caps + def bundle2caps(remote): """return the bundlecapabilities of a peer as dict""" raw = remote.capable('bundle2-exp') @@ -783,6 +801,12 @@ capsblob = urllib.unquote(remote.capable('bundle2-exp')) return decodecaps(capsblob) +def obsmarkersversion(caps): + """extract the list of supported obsmarkers versions from a bundle2caps dict + """ + obscaps = caps.get('b2x:obsmarkers', ()) + return [int(c[1:]) for c in obscaps if c.startswith('V')] + @parthandler('b2x:changegroup') def handlechangegroup(op, inpart): """apply a changegroup part on the repo @@ -796,7 +820,7 @@ # we need to make sure we trigger the creation of a transaction object used # for the whole processing scope. op.gettransaction() - cg = changegroup.unbundle10(inpart, 'UN') + cg = changegroup.cg1unpacker(inpart, 'UN') ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2') op.records.add('changegroup', {'return': ret}) if op.reply is not None: @@ -808,13 +832,13 @@ assert not inpart.read() @parthandler('b2x:reply:changegroup', ('return', 'in-reply-to')) -def handlechangegroup(op, inpart): +def handlereplychangegroup(op, inpart): ret = int(inpart.params['return']) replyto = int(inpart.params['in-reply-to']) op.records.add('changegroup', {'return': ret}, replyto) @parthandler('b2x:check:heads') -def handlechangegroup(op, inpart): +def handlecheckheads(op, inpart): """check that head of the repo did not change This is used to detect a push race when using unbundle. @@ -899,3 +923,24 @@ ret = int(inpart.params['return']) partid = int(inpart.params['in-reply-to']) op.records.add('pushkey', {'return': ret}, partid) + +@parthandler('b2x:obsmarkers') +def handleobsmarker(op, inpart): + """add a stream of obsmarkers to the repo""" + tr = op.gettransaction() + new = op.repo.obsstore.mergemarkers(tr, inpart.read()) + if new: + op.repo.ui.status(_('%i new obsolescence markers\n') % new) + op.records.add('obsmarkers', {'new': new}) + if op.reply is not None: + rpart = op.reply.newpart('b2x:reply:obsmarkers') + rpart.addparam('in-reply-to', str(inpart.id), mandatory=False) + rpart.addparam('new', '%i' % new, mandatory=False) + + +@parthandler('b2x:reply:obsmarkers', ('new', 'in-reply-to')) +def handlepushkeyreply(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)
--- a/mercurial/changegroup.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/changegroup.py Sat Sep 27 14:47:52 2014 -0500 @@ -12,7 +12,7 @@ import struct, os, bz2, zlib, tempfile import discovery, error, phases, branchmap -_BUNDLE10_DELTA_HEADER = "20s20s20s20s" +_CHANGEGROUPV1_DELTA_HEADER = "20s20s20s20s" def readexactly(stream, n): '''read n bytes from stream.read and abort if less was available''' @@ -123,8 +123,8 @@ raise util.Abort("unknown bundle compression '%s'" % alg) return util.chunkbuffer(generator(fh)) -class unbundle10(object): - deltaheader = _BUNDLE10_DELTA_HEADER +class cg1unpacker(object): + deltaheader = _CHANGEGROUPV1_DELTA_HEADER deltaheadersize = struct.calcsize(deltaheader) def __init__(self, fh, alg): self._stream = decompressor(fh, alg) @@ -227,8 +227,8 @@ return d return readexactly(self._fh, n) -class bundle10(object): - deltaheader = _BUNDLE10_DELTA_HEADER +class cg1packer(object): + deltaheader = _CHANGEGROUPV1_DELTA_HEADER def __init__(self, repo, bundlecaps=None): """Given a source repo, construct a bundler. @@ -456,7 +456,7 @@ repo.hook('preoutgoing', throw=True, source=source) _changegroupinfo(repo, csets, source) gengroup = bundler.generate(commonrevs, csets, fastpathlinkrev, source) - return unbundle10(util.chunkbuffer(gengroup), 'UN') + return cg1unpacker(util.chunkbuffer(gengroup), 'UN') def changegroupsubset(repo, roots, heads, source): """Compute a changegroup consisting of all the nodes that are @@ -480,17 +480,17 @@ for n in roots: discbases.extend([p for p in cl.parents(n) if p != nullid]) outgoing = discovery.outgoing(cl, discbases, heads) - bundler = bundle10(repo) + bundler = cg1packer(repo) return getsubset(repo, outgoing, bundler, source) -def getlocalbundle(repo, source, outgoing, bundlecaps=None): +def getlocalchangegroup(repo, source, outgoing, bundlecaps=None): """Like getbundle, but taking a discovery.outgoing as an argument. This is only implemented for local repos and reuses potentially precomputed sets in outgoing.""" if not outgoing.missing: return None - bundler = bundle10(repo, bundlecaps) + bundler = cg1packer(repo, bundlecaps) return getsubset(repo, outgoing, bundler, source) def _computeoutgoing(repo, heads, common): @@ -512,7 +512,7 @@ heads = cl.heads() return discovery.outgoing(cl, common, heads) -def getbundle(repo, source, heads=None, common=None, bundlecaps=None): +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. @@ -522,7 +522,7 @@ current discovery protocol works. """ outgoing = _computeoutgoing(repo, heads, common) - return getlocalbundle(repo, source, outgoing, bundlecaps=bundlecaps) + return getlocalchangegroup(repo, source, outgoing, bundlecaps=bundlecaps) def changegroup(repo, basenodes, source): # to avoid a race we use changegroupsubset() (issue1320) @@ -569,7 +569,8 @@ return revisions, files -def addchangegroup(repo, source, srctype, url, emptyok=False): +def addchangegroup(repo, source, srctype, url, emptyok=False, + targetphase=phases.draft): """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. @@ -699,15 +700,18 @@ # We should not use added here but the list of all change in # the bundle if publishing: - phases.advanceboundary(repo, phases.public, srccontent) + phases.advanceboundary(repo, tr, phases.public, srccontent) else: - phases.advanceboundary(repo, phases.draft, srccontent) - phases.retractboundary(repo, phases.draft, added) + # Those changesets have been pushed from the outside, their + # phases are going to be pushed alongside. Therefor + # `targetphase` is ignored. + phases.advanceboundary(repo, tr, phases.draft, srccontent) + phases.retractboundary(repo, tr, phases.draft, added) elif srctype != 'strip': # publishing only alter behavior during push # # strip should not touch boundary at all - phases.retractboundary(repo, phases.draft, added) + phases.retractboundary(repo, tr, targetphase, added) # make changelog see real files again cl.finalize(trp)
--- a/mercurial/changelog.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/changelog.py Sat Sep 27 14:47:52 2014 -0500 @@ -171,8 +171,13 @@ def headrevs(self): if self.filteredrevs: - # XXX we should fix and use the C version - return self._headrevs() + try: + return self.index.headrevs(self.filteredrevs) + # AttributeError covers non-c-extension environments. + # TypeError allows us work with old c extensions. + except (AttributeError, TypeError): + return self._headrevs() + return super(changelog, self).headrevs() def strip(self, *args, **kwargs):
--- a/mercurial/cmdutil.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/cmdutil.py Sat Sep 27 14:47:52 2014 -0500 @@ -13,6 +13,7 @@ import context, repair, graphmod, revset, phases, obsolete, pathutil import changelog import bookmarks +import encoding import lock as lockmod def parsealiases(cmd): @@ -109,7 +110,25 @@ (logfile, inst.strerror)) return message -def getcommiteditor(edit=False, finishdesc=None, extramsg=None, **opts): +def mergeeditform(ctxorbool, baseform): + """build appropriate editform from ctxorbool and baseform + + 'cxtorbool' is one of a ctx to be committed, or a bool whether + merging is committed. + + This returns editform 'baseform' with '.merge' if merging is + committed, or one with '.normal' suffix otherwise. + """ + if isinstance(ctxorbool, bool): + if ctxorbool: + return baseform + ".merge" + elif 1 < len(ctxorbool.parents()): + return baseform + ".merge" + + return baseform + ".normal" + +def getcommiteditor(edit=False, finishdesc=None, extramsg=None, + editform='', **opts): """get appropriate commit message editor according to '--edit' option 'finishdesc' is a function to be called with edited commit message @@ -122,6 +141,9 @@ 'Leave message empty to abort commit' line. 'HG: ' prefix and EOL is automatically added. + 'editform' is a dot-separated list of names, to distinguish + the purpose of commit text editing. + 'getcommiteditor' returns 'commitforceeditor' regardless of 'edit', if one of 'finishdesc' or 'extramsg' is specified, because they are specific for usage in MQ. @@ -129,7 +151,10 @@ if edit or finishdesc or extramsg: return lambda r, c, s: commitforceeditor(r, c, s, finishdesc=finishdesc, - extramsg=extramsg) + extramsg=extramsg, + editform=editform) + elif editform: + return lambda r, c, s: commiteditor(r, c, s, editform=editform) else: return commiteditor @@ -586,7 +611,6 @@ tmpname, message, user, date, branch, nodeid, p1, p2 = \ patch.extract(ui, hunk) - editor = getcommiteditor(**opts) update = not opts.get('bypass') strip = opts["strip"] sim = float(opts.get('similarity') or 0) @@ -636,6 +660,7 @@ n = None if update: + repo.dirstate.beginparentchange() if p1 != parents[0]: updatefunc(repo, p1.node()) if p2 != parents[1]: @@ -667,9 +692,15 @@ m = None else: m = scmutil.matchfiles(repo, files or []) + editform = mergeeditform(repo[None], 'import.normal') + if opts.get('exact'): + 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() else: if opts.get('exact') or opts.get('import_branch'): branch = branch or 'default' @@ -683,16 +714,24 @@ files, eolmode=None) except patch.PatchError, e: raise util.Abort(str(e)) + if opts.get('exact'): + editor = None + else: + editor = getcommiteditor(editform='import.bypass') memctx = context.makememctx(repo, (p1.node(), p2.node()), message, opts.get('user') or user, opts.get('date') or date, branch, files, store, - editor=getcommiteditor()) + editor=editor) n = memctx.commit() finally: store.close() - if opts.get('exact') and hex(n) != nodeid: + if opts.get('exact') and opts.get('no_commit'): + # --exact with --no-commit is still useful in that it does merge + # and branch bits + ui.warn(_("warning: can't check exact import with --no-commit\n")) + elif opts.get('exact') and hex(n) != nodeid: raise util.Abort(_('patch is damaged or loses information')) if n: # i18n: refers to a short changeset id @@ -805,11 +844,11 @@ class changeset_printer(object): '''show changeset information when templating not requested.''' - def __init__(self, ui, repo, patch, diffopts, buffered): + def __init__(self, ui, repo, matchfn, diffopts, buffered): self.ui = ui self.repo = repo self.buffered = buffered - self.patch = patch + self.matchfn = matchfn self.diffopts = diffopts self.header = {} self.hunk = {} @@ -948,7 +987,7 @@ def showpatch(self, node, matchfn): if not matchfn: - matchfn = self.patch + matchfn = self.matchfn if matchfn: stat = self.diffopts.get('stat') diff = self.diffopts.get('patch') @@ -979,12 +1018,101 @@ parents = [parents[0]] return parents +class jsonchangeset(changeset_printer): + '''format changeset information.''' + + def __init__(self, ui, repo, matchfn, diffopts, buffered): + changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered) + self.cache = {} + self._first = True + + def close(self): + if not self._first: + self.ui.write("\n]\n") + else: + self.ui.write("[]\n") + + def _show(self, ctx, copies, matchfn, props): + '''show a single changeset or file revision''' + hexnode = hex(ctx.node()) + rev = ctx.rev() + j = encoding.jsonescape + + if self._first: + self.ui.write("[\n {") + self._first = False + else: + self.ui.write(",\n {") + + if self.ui.quiet: + self.ui.write('\n "rev": %d' % rev) + self.ui.write(',\n "node": "%s"' % hexnode) + self.ui.write('\n }') + return + + self.ui.write('\n "rev": %d' % rev) + self.ui.write(',\n "node": "%s"' % hexnode) + self.ui.write(',\n "branch": "%s"' % j(ctx.branch())) + self.ui.write(',\n "phase": "%s"' % ctx.phasestr()) + self.ui.write(',\n "user": "%s"' % j(ctx.user())) + self.ui.write(',\n "date": [%d, %d]' % ctx.date()) + self.ui.write(',\n "desc": "%s"' % j(ctx.description())) + + self.ui.write(',\n "bookmarks": [%s]' % + ", ".join('"%s"' % j(b) for b in ctx.bookmarks())) + self.ui.write(',\n "tags": [%s]' % + ", ".join('"%s"' % j(t) for t in ctx.tags())) + self.ui.write(',\n "parents": [%s]' % + ", ".join('"%s"' % c.hex() for c in ctx.parents())) + + if self.ui.debugflag: + self.ui.write(',\n "manifest": "%s"' % hex(ctx.manifestnode())) + + self.ui.write(',\n "extra": {%s}' % + ", ".join('"%s": "%s"' % (j(k), j(v)) + for k, v in ctx.extra().items())) + + files = ctx.status(ctx.p1()) + self.ui.write(',\n "modified": [%s]' % + ", ".join('"%s"' % j(f) for f in files[0])) + self.ui.write(',\n "added": [%s]' % + ", ".join('"%s"' % j(f) for f in files[1])) + self.ui.write(',\n "removed": [%s]' % + ", ".join('"%s"' % j(f) for f in files[2])) + + elif self.ui.verbose: + self.ui.write(',\n "files": [%s]' % + ", ".join('"%s"' % j(f) for f in ctx.files())) + + if copies: + self.ui.write(',\n "copies": {%s}' % + ", ".join('"%s": %s' % (j(k), j(copies[k])) + for k in copies)) + + matchfn = self.matchfn + if matchfn: + stat = self.diffopts.get('stat') + diff = self.diffopts.get('patch') + diffopts = patch.diffopts(self.ui, self.diffopts) + node, prev = ctx.node(), ctx.p1().node() + if stat: + self.ui.pushbuffer() + diffordiffstat(self.ui, self.repo, diffopts, prev, node, + match=matchfn, stat=True) + self.ui.write(',\n "diffstat": "%s"' % j(self.ui.popbuffer())) + if diff: + self.ui.pushbuffer() + diffordiffstat(self.ui, self.repo, diffopts, prev, node, + match=matchfn, stat=False) + self.ui.write(',\n "diff": "%s"' % j(self.ui.popbuffer())) + + self.ui.write("\n }") class changeset_templater(changeset_printer): '''format changeset information.''' - def __init__(self, ui, repo, patch, diffopts, tmpl, mapfile, buffered): - changeset_printer.__init__(self, ui, repo, patch, diffopts, buffered) + def __init__(self, ui, repo, matchfn, diffopts, tmpl, mapfile, buffered): + changeset_printer.__init__(self, ui, repo, matchfn, diffopts, buffered) formatnode = ui.debugflag and (lambda x: x) or (lambda x: x[:12]) defaulttempl = { 'parent': '{rev}:{node|formatnode} ', @@ -1157,17 +1285,21 @@ regular display via changeset_printer() is done. """ # options - patch = None + matchfn = None if opts.get('patch') or opts.get('stat'): - patch = scmutil.matchall(repo) + matchfn = scmutil.matchall(repo) + + if opts.get('template') == 'json': + return jsonchangeset(ui, repo, matchfn, opts, buffered) tmpl, mapfile = gettemplate(ui, opts.get('template'), opts.get('style')) if not tmpl and not mapfile: - return changeset_printer(ui, repo, patch, opts, buffered) + return changeset_printer(ui, repo, matchfn, opts, buffered) try: - t = changeset_templater(ui, repo, patch, opts, tmpl, mapfile, buffered) + t = changeset_templater(ui, repo, matchfn, opts, tmpl, mapfile, + buffered) except SyntaxError, inst: raise util.Abort(inst.args[0]) return t @@ -1180,9 +1312,14 @@ for repl in marker.succnodes(): ui.write(' ') ui.write(hex(repl)) - ui.write(' %X ' % marker._data[2]) + ui.write(' %X ' % marker.flags()) + parents = marker.parentnodes() + if parents is not None: + ui.write('{%s} ' % ', '.join(hex(p) for p in parents)) + ui.write('(%s) ' % util.datestr(marker.date())) ui.write('{%s}' % (', '.join('%r: %r' % t for t in - sorted(marker.metadata().items())))) + sorted(marker.metadata().items()) + if t[0] != 'date'))) ui.write('\n') def finddate(ui, repo, date): @@ -1578,8 +1715,14 @@ if not slowpath: for f in match.files(): if follow and f not in pctx: - raise util.Abort(_('cannot follow file not in parent ' - 'revision: "%s"') % f) + # If the file exists, it may be a directory, so let it + # take the slow path. + if os.path.exists(repo.wjoin(f)): + slowpath = True + continue + else: + raise util.Abort(_('cannot follow file not in parent ' + 'revision: "%s"') % f) filelog = repo.file(f) if not filelog: # A zero count may be a directory or deleted file, so @@ -1603,9 +1746,6 @@ if slowpath: # See walkchangerevs() slow path. # - if follow: - raise util.Abort(_('can only follow copies/renames for explicit ' - 'filenames')) # pats/include/exclude cannot be represented as separate # revset expressions as their filtering logic applies at file # level. For instance "-I a -X a" matches a revision touching @@ -1637,7 +1777,10 @@ filematcher = None if opts.get('patch') or opts.get('stat'): - if follow and not match.always(): + # When following files, track renames via a special matcher. + # If we're forced to take the slowpath it means we're following + # at least one pattern/directory, so don't bother with rename tracking. + if follow and not match.always() and not slowpath: # _makelogfilematcher expects its files argument to be relative to # the repo root, so use match.files(), not pats. filematcher = _makefollowlogfilematcher(repo, match.files(), @@ -2091,7 +2234,7 @@ copied=copied.get(path)) return mctx except KeyError: - raise IOError + return None else: ui.note(_('copying changeset %s to %s\n') % (old, base)) @@ -2100,13 +2243,14 @@ try: return old.filectx(path) except KeyError: - raise IOError + return None user = opts.get('user') or old.user() date = opts.get('date') or old.date() - editor = getcommiteditor(**opts) + editform = mergeeditform(old, 'commit.amend') + editor = getcommiteditor(editform=editform, **opts) if not message: - editor = getcommiteditor(edit=True) + editor = getcommiteditor(edit=True, editform=editform) message = old.description() pureextra = extra.copy() @@ -2180,24 +2324,31 @@ lockmod.release(lock, wlock) return newid -def commiteditor(repo, ctx, subs): +def commiteditor(repo, ctx, subs, editform=''): if ctx.description(): return ctx.description() - return commitforceeditor(repo, ctx, subs) - -def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None): + return commitforceeditor(repo, ctx, subs, editform=editform) + +def commitforceeditor(repo, ctx, subs, finishdesc=None, extramsg=None, + editform=''): if not extramsg: extramsg = _("Leave message empty to abort commit.") - tmpl = repo.ui.config('committemplate', 'changeset', '').strip() - if tmpl: - committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl) + + forms = [e for e in editform.split('.') if e] + forms.insert(0, 'changeset') + while forms: + tmpl = repo.ui.config('committemplate', '.'.join(forms)) + if tmpl: + committext = buildcommittemplate(repo, ctx, subs, extramsg, tmpl) + break + forms.pop() else: committext = buildcommittext(repo, ctx, subs, extramsg) # run editor in the repository root olddir = os.getcwd() os.chdir(repo.root) - text = repo.ui.edit(committext, ctx.user(), ctx.extra()) + text = repo.ui.edit(committext, ctx.user(), ctx.extra(), editform=editform) text = re.sub("(?m)^HG:.*(\n|$)", "", text) os.chdir(olddir) @@ -2217,6 +2368,10 @@ except SyntaxError, inst: raise util.Abort(inst.args[0]) + for k, v in repo.ui.configitems('committemplate'): + if k != 'changeset': + t.t.cache[k] = v + if not extramsg: extramsg = '' # ensure that extramsg is string @@ -2348,118 +2503,196 @@ if abs not in names: names[abs] = m.rel(abs), m.exact(abs) - # get the list of subrepos that must be reverted - targetsubs = sorted(s for s in ctx.substate if m(s)) - - # Find status of all file in `names`. (Against working directory parent) + # Find status of all file in `names`. m = scmutil.matchfiles(repo, names) - changes = repo.status(node1=parent, match=m)[:4] - modified, added, removed, deleted = map(set, changes) + + changes = repo.status(node1=node, match=m, + unknown=True, ignored=True, clean=True) + modified = set(changes[0]) + added = set(changes[1]) + removed = set(changes[2]) + _deleted = set(changes[3]) + unknown = set(changes[4]) + unknown.update(changes[5]) + clean = set(changes[6]) + + # split between files known in target manifest and the others + smf = set(mf) + + # determine the exact nature of the deleted changesets + deladded = _deleted - smf + deleted = _deleted - deladded + + # We need to account for the state of file in the dirstate + # + # Even, when we revert agains something else than parent. this will + # slightly alter the behavior of revert (doing back up or not, delete + # or just forget etc) + if parent == node: + dsmodified = modified + dsadded = added + dsremoved = removed + modified, added, removed = set(), set(), set() + else: + changes = repo.status(node1=parent, match=m) + dsmodified = set(changes[0]) + dsadded = set(changes[1]) + dsremoved = set(changes[2]) + + # only take into account for removes between wc and target + clean |= dsremoved - removed + dsremoved &= removed + # distinct between dirstate remove and other + removed -= dsremoved + + # tell newly modified apart. + dsmodified &= modified + dsmodified |= modified & dsadded # dirstate added may needs backup + modified -= dsmodified + + # We need to wait for some post-processing to update this set + # before making the distinction. The dirstate will be used for + # that purpose. + dsadded = added + + # in case of merge, files that are actually added can be reported as + # modified, we need to post process the result + if p2 != nullid: + if pmf is None: + # only need parent manifest in the merge case, + # so do not read by default + pmf = repo[parent].manifest() + mergeadd = dsmodified - set(pmf) + dsadded |= mergeadd + dsmodified -= mergeadd # if f is a rename, update `names` to also revert the source cwd = repo.getcwd() - for f in added: + for f in dsadded: src = repo.dirstate.copied(f) + # XXX should we check for rename down to target node? if src and src not in names and repo.dirstate[src] == 'r': - removed.add(src) + dsremoved.add(src) names[src] = (repo.pathto(src, cwd), True) - ## computation of the action to performs on `names` content. - - def removeforget(abs): + # distinguish between file to forget and the other + added = set() + for abs in dsadded: + if repo.dirstate[abs] != 'a': + added.add(abs) + dsadded -= added + + for abs in deladded: if repo.dirstate[abs] == 'a': - return _('forgetting %s\n') - return _('removing %s\n') + dsadded.add(abs) + deladded -= dsadded + + # For files marked as removed, we check if an unknown file is present at + # the same path. If a such file exists it may need to be backed up. + # Making the distinction at this stage helps have simpler backup + # logic. + removunk = set() + for abs in removed: + target = repo.wjoin(abs) + if os.path.lexists(target): + removunk.add(abs) + removed -= removunk + + dsremovunk = set() + for abs in dsremoved: + target = repo.wjoin(abs) + if os.path.lexists(target): + dsremovunk.add(abs) + dsremoved -= dsremovunk # action to be actually performed by revert # (<list of file>, message>) tuple actions = {'revert': ([], _('reverting %s\n')), 'add': ([], _('adding %s\n')), - 'remove': ([], removeforget), - 'undelete': ([], _('undeleting %s\n'))} + 'remove': ([], _('removing %s\n')), + 'drop': ([], _('removing %s\n')), + 'forget': ([], _('forgetting %s\n')), + 'undelete': ([], _('undeleting %s\n')), + 'noop': (None, _('no changes needed to %s\n')), + 'unknown': (None, _('file not managed: %s\n')), + } + + + # should we do a backup? + backup = not opts.get('no_backup') + discard = False disptable = ( # dispatch table: # file state - # action if in target manifest - # action if not in target manifest - # make backup if in target manifest - # make backup if not in target manifest - (modified, (actions['revert'], True), - (actions['remove'], True)), - (added, (actions['revert'], True), - (actions['remove'], False)), - (removed, (actions['undelete'], True), - (None, False)), - (deleted, (actions['revert'], False), - (actions['remove'], False)), + # action + # make backup + + ## Sets that results that will change file on disk + # Modified compared to target, no local change + (modified, actions['revert'], discard), + # Modified compared to target, but local file is deleted + (deleted, actions['revert'], discard), + # Modified compared to target, local change + (dsmodified, actions['revert'], backup), + # Added since target + (added, actions['remove'], discard), + # Added in working directory + (dsadded, actions['forget'], discard), + # Added since target but file is missing in working directory + (deladded, actions['drop'], discard), + # Removed since target, before working copy parent + (removed, actions['add'], discard), + # Same as `removed` but an unknown file exists at the same path + (removunk, actions['add'], backup), + # Removed since targe, marked as such in working copy parent + (dsremoved, actions['undelete'], discard), + # Same as `dsremoved` but an unknown file exists at the same path + (dsremovunk, actions['undelete'], backup), + ## the following sets does not result in any file changes + # File with no modification + (clean, actions['noop'], discard), + # Existing file, not tracked anywhere + (unknown, actions['unknown'], discard), ) + needdata = ('revert', 'add', 'undelete') + _revertprefetch(repo, ctx, *[actions[name][0] for name in needdata]) + + wctx = repo[None] for abs, (rel, exact) in sorted(names.items()): - # hash on file in target manifest (or None if missing from target) - mfentry = mf.get(abs) # target file to be touch on disk (relative to cwd) target = repo.wjoin(abs) - def handle(xlist, dobackup): - xlist[0].append(abs) - if (dobackup and not opts.get('no_backup') and - os.path.lexists(target) and - abs in ctx and repo[None][abs].cmp(ctx[abs])): - bakname = "%s.orig" % rel - ui.note(_('saving current version of %s as %s\n') % - (rel, bakname)) - if not opts.get('dry_run'): - util.rename(target, bakname) - if ui.verbose or not exact: - msg = xlist[1] - if not isinstance(msg, basestring): - msg = msg(abs) - ui.status(msg % rel) # search the entry in the dispatch table. - # if the file is in any of this sets, it was touched in the working + # if the file is in any of these sets, it was touched in the working # directory parent and we are sure it needs to be reverted. - for table, hit, miss in disptable: + for table, (xlist, msg), dobackup in disptable: if abs not in table: continue - # file has changed in dirstate - if mfentry: - handle(*hit) - elif miss[0] is not None: - handle(*miss) + if xlist is not None: + xlist.append(abs) + if (dobackup and wctx[abs].cmp(ctx[abs])): + bakname = "%s.orig" % rel + ui.note(_('saving current version of %s as %s\n') % + (rel, bakname)) + if not opts.get('dry_run'): + util.rename(target, bakname) + if ui.verbose or not exact: + if not isinstance(msg, basestring): + msg = msg(abs) + ui.status(msg % rel) + elif exact: + ui.warn(msg % rel) break - else: - # Not touched in current dirstate. - - # file is unknown in parent, restore older version or ignore. - if abs not in repo.dirstate: - if mfentry: - handle(actions['add'], True) - elif exact: - ui.warn(_('file not managed: %s\n') % rel) - continue - - # parent is target, no changes mean no changes - if node == parent: - if exact: - ui.warn(_('no changes needed to %s\n') % rel) - continue - # no change in dirstate but parent and target may differ - if pmf is None: - # only need parent manifest in this unlikely case, - # so do not read by default - pmf = repo[parent].manifest() - if abs in pmf and mfentry: - # if version of file is same in parent and target - # manifests, do nothing - if (pmf[abs] != mfentry or - pmf.flags(abs) != mf.flags(abs)): - handle(actions['revert'], False) - else: - handle(actions['remove'], False) + if not opts.get('dry_run'): _performrevert(repo, parents, ctx, actions) + # get the list of subrepos that must be reverted + subrepomatch = scmutil.match(ctx, pats, opts) + targetsubs = sorted(s for s in ctx.substate if subrepomatch(s)) + if targetsubs: # Revert the subrepos on the revert list for sub in targetsubs: @@ -2467,6 +2700,10 @@ finally: wlock.release() +def _revertprefetch(repo, ctx, *files): + """Let extension changing the storage layer prefetch content""" + pass + def _performrevert(repo, parents, ctx, actions): """function that actually perform all the actions computed for revert @@ -2482,15 +2719,14 @@ repo.wwrite(f, fc.data(), fc.flags()) audit_path = pathutil.pathauditor(repo.root) + for f in actions['forget'][0]: + repo.dirstate.drop(f) for f in actions['remove'][0]: - if repo.dirstate[f] == 'a': - repo.dirstate.drop(f) - continue audit_path(f) - try: - util.unlinkpath(repo.wjoin(f)) - except OSError: - pass + util.unlinkpath(repo.wjoin(f)) + repo.dirstate.remove(f) + for f in actions['drop'][0]: + audit_path(f) repo.dirstate.remove(f) normal = None
--- a/mercurial/commands.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/commands.py Sat Sep 27 14:47:52 2014 -0500 @@ -9,7 +9,7 @@ from lock import release from i18n import _ import os, re, difflib, time, tempfile, errno, shlex -import sys +import sys, socket import hg, scmutil, util, revlog, copies, error, bookmarks import patch, help, encoding, templatekw, discovery import archival, changegroup, cmdutil, hbisect @@ -101,6 +101,12 @@ _('record the specified user as committer'), _('USER')), ] +# hidden for now +formatteropts = [ + ('T', 'template', '', + _('display with template (DEPRECATED)'), _('TEMPLATE')), +] + templateopts = [ ('', 'style', '', _('display using template map file (DEPRECATED)'), _('STYLE')), @@ -241,7 +247,7 @@ ('n', 'number', None, _('list the revision number (default)')), ('c', 'changeset', None, _('list the changeset')), ('l', 'line-number', None, _('show line number at the first appearance')) - ] + diffwsopts + walkopts, + ] + diffwsopts + walkopts + formatteropts, _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'), inferrepo=True) def annotate(ui, repo, *pats, **opts): @@ -260,26 +266,29 @@ Returns 0 on success. """ + if not pats: + raise util.Abort(_('at least one filename or pattern is required')) + if opts.get('follow'): # --follow is deprecated and now just an alias for -f/--file # to mimic the behavior of Mercurial before version 1.5 opts['file'] = True + fm = ui.formatter('annotate', opts) datefunc = ui.quiet and util.shortdate or util.datestr - getdate = util.cachefunc(lambda x: datefunc(x[0].date())) - - if not pats: - raise util.Abort(_('at least one filename or pattern is required')) - - hexfn = ui.debugflag and hex or short - - opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())), - ('number', ' ', lambda x: str(x[0].rev())), - ('changeset', ' ', lambda x: hexfn(x[0].node())), - ('date', ' ', getdate), - ('file', ' ', lambda x: x[0].path()), - ('line_number', ':', lambda x: str(x[1])), + if fm or ui.debugflag: + hexfn = hex + else: + hexfn = short + + opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser), + ('number', ' ', lambda x: x[0].rev(), str), + ('changeset', ' ', lambda x: hexfn(x[0].node()), str), + ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)), + ('file', ' ', lambda x: x[0].path(), str), + ('line_number', ':', lambda x: x[1], str), ] + fieldnamemap = {'number': 'rev', 'changeset': 'node'} if (not opts.get('user') and not opts.get('changeset') and not opts.get('date') and not opts.get('file')): @@ -289,8 +298,17 @@ if linenumber and (not opts.get('changeset')) and (not opts.get('number')): raise util.Abort(_('at least one of -n/-c is required for -l')) - funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)] + if fm: + def makefunc(get, fmt): + return get + else: + def makefunc(get, fmt): + return lambda x: fmt(get(x)) + funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap + if opts.get(op)] funcmap[0] = (funcmap[0][0], '') # no separator in front of first column + fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap + if opts.get(op)) def bad(x, y): raise util.Abort("%s: %s" % (x, y)) @@ -303,27 +321,34 @@ for abs in ctx.walk(m): fctx = ctx[abs] if not opts.get('text') and util.binary(fctx.data()): - ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs)) + fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs)) continue lines = fctx.annotate(follow=follow, linenumber=linenumber, diffopts=diffopts) + formats = [] pieces = [] for f, sep in funcmap: l = [f(n) for n, dummy in lines] if l: - sized = [(x, encoding.colwidth(x)) for x in l] - ml = max([w for x, w in sized]) - pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x) - for x, w in sized]) - - if pieces: - for p, l in zip(zip(*pieces), lines): - ui.write("%s: %s" % ("".join(p), l[1])) - - if lines and not lines[-1][1].endswith('\n'): - ui.write('\n') + if fm: + formats.append(['%s' for x in l]) + else: + sizes = [encoding.colwidth(x) for x in l] + ml = max(sizes) + formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes]) + pieces.append(l) + + for f, p, l in zip(zip(*formats), zip(*pieces), lines): + fm.startitem() + fm.write(fields, "".join(f), *p) + fm.write('line', ": %s", l[1]) + + if lines and not lines[-1][1].endswith('\n'): + fm.plain('\n') + + fm.end() @command('archive', [('', 'no-decode', None, _('do not pass files through decoders')), @@ -455,7 +480,7 @@ node = scmutil.revsingle(repo, rev).node() op1, op2 = repo.dirstate.parents() - if node not in repo.changelog.commonancestorsheads(op1, node): + if not repo.changelog.isancestor(node, op1): raise util.Abort(_('cannot backout change that is not an ancestor')) p1, p2 = repo.changelog.parents(node) @@ -484,9 +509,11 @@ try: ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'backout') + repo.dirstate.beginparentchange() stats = mergemod.update(repo, parent, True, True, False, node, False) repo.setparents(op1, op2) + repo.dirstate.endparentchange() hg._showstats(repo, stats) if stats[3]: repo.ui.status(_("use 'hg resolve' to retry unresolved " @@ -505,11 +532,12 @@ def commitfunc(ui, repo, message, match, opts): - e = cmdutil.getcommiteditor(**opts) + editform = 'backout' + e = cmdutil.getcommiteditor(editform=editform, **opts) if not message: # we don't translate commit messages message = "Backed out changeset %s" % short(node) - e = cmdutil.getcommiteditor(edit=True) + e = cmdutil.getcommiteditor(edit=True, editform=editform) return repo.commit(message, opts.get('user'), opts.get('date'), match, editor=e) newnode = cmdutil.commit(ui, repo, commitfunc, [], opts) @@ -1159,8 +1187,8 @@ "a destination")) common = [repo.lookup(rev) for rev in base] heads = revs and map(repo.lookup, revs) or revs - cg = changegroup.getbundle(repo, 'bundle', heads=heads, common=common, - bundlecaps=bundlecaps) + cg = changegroup.getchangegroup(repo, 'bundle', heads=heads, + common=common, bundlecaps=bundlecaps) outgoing = None else: dest = ui.expandpath(dest or 'default-push', dest or 'default') @@ -1172,7 +1200,8 @@ onlyheads=heads, force=opts.get('force'), portable=True) - cg = changegroup.getlocalbundle(repo, 'bundle', outgoing, bundlecaps) + cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing, + bundlecaps) if not cg: scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded) return 1 @@ -1385,9 +1414,6 @@ # Let --subrepos on the command line override config setting. ui.setconfig('ui', 'commitsubrepos', True, 'commit') - # Save this for restoring it later - oldcommitphase = ui.config('phases', 'new-commit') - cmdutil.checkunfinished(repo, commit=True) branch = repo[None].branch() @@ -1409,7 +1435,7 @@ raise util.Abort(_('cannot amend with ui.commitsubrepos enabled')) old = repo['.'] - if old.phase() == phases.public: + if not old.mutable(): raise util.Abort(_('cannot amend public changesets')) if len(repo[None].parents()) > 1: raise util.Abort(_('cannot amend while merging')) @@ -1441,21 +1467,24 @@ newmarks.write() else: def commitfunc(ui, repo, message, match, opts): + backup = ui.backupconfig('phases', 'new-commit') + baseui = repo.baseui + basebackup = baseui.backupconfig('phases', 'new-commit') try: if opts.get('secret'): ui.setconfig('phases', 'new-commit', 'secret', 'commit') # Propagate to subrepos - repo.baseui.setconfig('phases', 'new-commit', 'secret', - 'commit') - + baseui.setconfig('phases', 'new-commit', 'secret', 'commit') + + editform = cmdutil.mergeeditform(repo[None], 'commit.normal') + editor = cmdutil.getcommiteditor(editform=editform, **opts) return repo.commit(message, opts.get('user'), opts.get('date'), match, - editor=cmdutil.getcommiteditor(**opts), + editor=editor, extra=extra) finally: - ui.setconfig('phases', 'new-commit', oldcommitphase, 'commit') - repo.baseui.setconfig('phases', 'new-commit', oldcommitphase, - 'commit') + ui.restoreconfig(backup) + repo.baseui.restoreconfig(basebackup) node = cmdutil.commit(ui, repo, commitfunc, pats, opts) @@ -1519,22 +1548,18 @@ if os.path.exists(f): break else: + from ui import samplehgrcs + + if opts.get('global'): + samplehgrc = samplehgrcs['global'] + elif opts.get('local'): + samplehgrc = samplehgrcs['local'] + else: + samplehgrc = samplehgrcs['user'] + f = paths[0] fp = open(f, "w") - fp.write( - '# example config (see "hg help config" for more info)\n' - '\n' - '[ui]\n' - '# name and email, e.g.\n' - '# username = Jane Doe <jdoe@example.com>\n' - 'username =\n' - '\n' - '[extensions]\n' - '# uncomment these lines to enable some popular extensions\n' - '# (see "hg help extensions" for more info)\n' - '# pager =\n' - '# progress =\n' - '# color =\n') + fp.write(samplehgrc) fp.close() editor = ui.geteditor() @@ -1912,8 +1937,8 @@ revs = set((int(r) for r in revs)) def events(): for r in rlog: - yield 'n', (r, list(set(p for p in rlog.parentrevs(r) - if p != -1))) + yield 'n', (r, list(p for p in rlog.parentrevs(r) + if p != -1)) if r in revs: yield 'l', (r, "r%i" % r) elif repo: @@ -1932,8 +1957,8 @@ if newb != b: yield 'a', newb b = newb - yield 'n', (r, list(set(p for p in cl.parentrevs(r) - if p != -1))) + yield 'n', (r, list(p for p in cl.parentrevs(r) + if p != -1)) if tags: ls = labels.get(r) if ls: @@ -2313,8 +2338,83 @@ ui.write('\n'.join(sorted(completions))) ui.write('\n') +@command('debuglocks', + [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')), + ('W', 'force-wlock', None, + _('free the working state lock (DANGEROUS)'))], + _('')) +def debuglocks(ui, repo, **opts): + """show or modify state of locks + + By default, this command will show which locks are held. This + includes the user and process holding the lock, the amount of time + the lock has been held, and the machine name where the process is + running if it's not local. + + Locks protect the integrity of Mercurial's data, so should be + treated with care. System crashes or other interruptions may cause + locks to not be properly released, though Mercurial will usually + detect and remove such stale locks automatically. + + However, detecting stale locks may not always be possible (for + instance, on a shared filesystem). Removing locks may also be + blocked by filesystem permissions. + + Returns 0 if no locks are held. + + """ + + if opts.get('force_lock'): + repo.svfs.unlink('lock') + if opts.get('force_wlock'): + repo.vfs.unlink('wlock') + if opts.get('force_lock') or opts.get('force_lock'): + return 0 + + now = time.time() + held = 0 + + def report(vfs, name, method): + # this causes stale locks to get reaped for more accurate reporting + try: + l = method(False) + except error.LockHeld: + l = None + + if l: + l.release() + else: + try: + stat = repo.svfs.lstat(name) + age = now - stat.st_mtime + user = util.username(stat.st_uid) + locker = vfs.readlock(name) + if ":" in locker: + host, pid = locker.split(':') + if host == socket.gethostname(): + locker = 'user %s, process %s' % (user, pid) + else: + locker = 'user %s, process %s, host %s' \ + % (user, pid, host) + ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age)) + return 1 + except OSError, e: + if e.errno != errno.ENOENT: + raise + + ui.write("%-6s free\n" % (name + ":")) + return 0 + + held += report(repo.svfs, "lock", repo.lock) + held += report(repo.vfs, "wlock", repo.wlock) + + return held + @command('debugobsolete', [('', 'flags', 0, _('markers flag')), + ('', 'record-parents', False, + _('record parent information for the precursor')), + ('r', 'rev', [], _('display markers relevant to REV')), ] + commitopts2, _('[OBSOLETED [REPLACEMENT] [REPL... ]')) def debugobsolete(ui, repo, precursor=None, *successors, **opts): @@ -2336,9 +2436,9 @@ 'node identifiers') if precursor is not None: + if opts['rev']: + raise util.Abort('cannot select revision when creating marker') metadata = {} - if 'date' in opts: - metadata['date'] = opts['date'] metadata['user'] = opts['user'] or ui.username() succs = tuple(parsenodeid(succ) for succ in successors) l = repo.lock() @@ -2346,8 +2446,22 @@ tr = repo.transaction('debugobsolete') try: try: - repo.obsstore.create(tr, parsenodeid(precursor), succs, - opts['flags'], metadata) + 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) @@ -2356,7 +2470,15 @@ finally: l.release() else: - for m in obsolete.allmarkers(repo): + if opts['rev']: + revs = scmutil.revrange(repo, opts['rev']) + nodes = [repo[r].node() for r in revs] + markers = list(obsolete.getmarkers(repo, nodes=nodes)) + markers.sort(key=lambda x: x._data) + else: + markers = obsolete.getmarkers(repo) + + for m in markers: cmdutil.showmarker(ui, m) @command('debugpathcomplete', @@ -2518,24 +2640,36 @@ if opts.get("dump"): numrevs = len(r) ui.write("# rev p1rev p2rev start end deltastart base p1 p2" - " rawsize totalsize compression heads\n") + " rawsize totalsize compression heads chainlen\n") ts = 0 heads = set() + rindex = r.index + + def chainbaseandlen(rev): + clen = 0 + base = rindex[rev][3] + while base != rev: + clen += 1 + rev = base + base = rindex[rev][3] + return base, clen + for rev in xrange(numrevs): dbase = r.deltaparent(rev) if dbase == -1: dbase = rev - cbase = r.chainbase(rev) + cbase, clen = chainbaseandlen(rev) p1, p2 = r.parentrevs(rev) rs = r.rawsize(rev) ts = ts + rs heads -= set(r.parentrevs(rev)) heads.add(rev) - ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d %11d %5d\n" % + ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d " + "%11d %5d %8d\n" % (rev, p1, p2, r.start(rev), r.end(rev), r.start(dbase), r.start(cbase), r.start(p1), r.start(p2), - rs, ts, ts / r.end(rev), len(heads))) + rs, ts, ts / r.end(rev), len(heads), clen)) return 0 v = r.version @@ -2716,7 +2850,9 @@ wlock = repo.wlock() try: + repo.dirstate.beginparentchange() repo.setparents(r1, r2) + repo.dirstate.endparentchange() finally: wlock.release() @@ -3023,6 +3159,81 @@ switch_parent=opts.get('switch_parent'), opts=patch.diffopts(ui, opts)) +@command('files', + [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')), + ('0', 'print0', None, _('end filenames with NUL, for use with xargs')), + ] + walkopts + formatteropts, + _('[OPTION]... [PATTERN]...')) +def files(ui, repo, *pats, **opts): + """list tracked files + + Print files under Mercurial control in the working directory or + specified revision whose names match the given patterns (excluding + removed files). + + If no patterns are given to match, this command prints the names + of all files under Mercurial control in the working copy. + + .. container:: verbose + + Examples: + + - list all files under the current directory:: + + hg files . + + - shows sizes and flags for current revision:: + + hg files -vr . + + - list all files named README:: + + hg files -I "**/README" + + - list all binary files:: + + hg files "set:binary()" + + - find files containing a regular expression: + + hg files "set:grep('bob')" + + - search tracked file contents with xargs and grep:: + + hg files -0 | xargs -0 grep foo + + See :hg:'help pattern' and :hg:'help revsets' for more information + on specifying file patterns. + + Returns 0 if a match is found, 1 otherwise. + + """ + ctx = scmutil.revsingle(repo, opts.get('rev'), None) + rev = ctx.rev() + ret = 1 + + end = '\n' + if opts.get('print0'): + end = '\0' + fm = ui.formatter('files', opts) + fmt = '%s' + end + + m = scmutil.match(ctx, pats, opts) + for f in ctx.walk(m): + if rev is None and repo.dirstate[f] in 'R?!': + continue + fm.startitem() + if ui.verbose: + fc = ctx[f] + fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags()) + fm.data(abspath=f) + fm.write('path', fmt, m.rel(f)) + ret = 0 + + fm.end() + + return ret + @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True) def forget(ui, repo, *pats, **opts): """forget the specified files on the next commit @@ -3064,6 +3275,7 @@ ('c', 'continue', False, _('resume interrupted graft')), ('e', 'edit', False, _('invoke editor on commit messages')), ('', 'log', None, _('append graft info to log message')), + ('f', 'force', False, _('force graft')), ('D', 'currentdate', False, _('record the current date as commit date')), ('U', 'currentuser', False, @@ -3087,6 +3299,10 @@ (grafted from CHANGESETHASH) + If --force is specified, revisions will be grafted even if they + are already ancestors of or have been grafted to the destination. + This is useful when the revisions have since been backed out. + If a graft merge results in conflicts, the graft process is interrupted so that the current merge can be manually resolved. Once all conflicts are addressed, the graft process can be @@ -3094,7 +3310,8 @@ .. note:: - The -c/--continue option does not reapply earlier options. + The -c/--continue option does not reapply earlier options, except + for --force. .. container:: verbose @@ -3131,7 +3348,7 @@ if not opts.get('date') and opts.get('currentdate'): opts['date'] = "%d %d" % util.makedate() - editor = cmdutil.getcommiteditor(**opts) + editor = cmdutil.getcommiteditor(editform='graft', **opts) cont = False if opts['continue']: @@ -3160,61 +3377,68 @@ if not revs: return -1 - # check for ancestors of dest branch - crev = repo['.'].rev() - ancestors = repo.changelog.ancestors([crev], inclusive=True) - # Cannot use x.remove(y) on smart set, this has to be a list. - # XXX make this lazy in the future - revs = list(revs) - # don't mutate while iterating, create a copy - for rev in list(revs): - if rev in ancestors: - ui.warn(_('skipping ancestor revision %s\n') % rev) - # XXX remove on list is slow - revs.remove(rev) - if not revs: - return -1 - - # analyze revs for earlier grafts - ids = {} - for ctx in repo.set("%ld", revs): - ids[ctx.hex()] = ctx.rev() - n = ctx.extra().get('source') - if n: - ids[n] = ctx.rev() - - # check ancestors for earlier grafts - ui.debug('scanning for duplicate grafts\n') - - for rev in repo.changelog.findmissingrevs(revs, [crev]): - ctx = repo[rev] - n = ctx.extra().get('source') - if n in ids: - try: - r = repo[n].rev() - except error.RepoLookupError: - r = None - if r in revs: - ui.warn(_('skipping revision %s (already grafted to %s)\n') - % (r, rev)) + # Don't check in the --continue case, in effect retaining --force across + # --continues. That's because without --force, any revisions we decided to + # skip would have been filtered out here, so they wouldn't have made their + # way to the graftstate. With --force, any revisions we would have otherwise + # skipped would not have been filtered out, and if they hadn't been applied + # already, they'd have been in the graftstate. + if not (cont or opts.get('force')): + # check for ancestors of dest branch + crev = repo['.'].rev() + ancestors = repo.changelog.ancestors([crev], inclusive=True) + # Cannot use x.remove(y) on smart set, this has to be a list. + # XXX make this lazy in the future + revs = list(revs) + # don't mutate while iterating, create a copy + for rev in list(revs): + if rev in ancestors: + ui.warn(_('skipping ancestor revision %s\n') % rev) + # XXX remove on list is slow + revs.remove(rev) + if not revs: + return -1 + + # analyze revs for earlier grafts + ids = {} + for ctx in repo.set("%ld", revs): + ids[ctx.hex()] = ctx.rev() + n = ctx.extra().get('source') + if n: + ids[n] = ctx.rev() + + # check ancestors for earlier grafts + ui.debug('scanning for duplicate grafts\n') + + for rev in repo.changelog.findmissingrevs(revs, [crev]): + ctx = repo[rev] + n = ctx.extra().get('source') + if n in ids: + try: + r = repo[n].rev() + except error.RepoLookupError: + r = None + if r in revs: + ui.warn(_('skipping revision %s (already grafted to %s)\n') + % (r, rev)) + revs.remove(r) + elif ids[n] in revs: + if r is None: + ui.warn(_('skipping already grafted revision %s ' + '(%s also has unknown origin %s)\n') + % (ids[n], rev, n)) + else: + ui.warn(_('skipping already grafted revision %s ' + '(%s also has origin %d)\n') + % (ids[n], rev, r)) + revs.remove(ids[n]) + elif ctx.hex() in ids: + r = ids[ctx.hex()] + ui.warn(_('skipping already grafted revision %s ' + '(was grafted from %d)\n') % (r, rev)) revs.remove(r) - elif ids[n] in revs: - if r is None: - ui.warn(_('skipping already grafted revision %s ' - '(%s also has unknown origin %s)\n') - % (ids[n], rev, n)) - else: - ui.warn(_('skipping already grafted revision %s ' - '(%s also has origin %d)\n') - % (ids[n], rev, r)) - revs.remove(ids[n]) - elif ctx.hex() in ids: - r = ids[ctx.hex()] - ui.warn(_('skipping already grafted revision %s ' - '(was grafted from %d)\n') % (r, rev)) - revs.remove(r) - if not revs: - return -1 + if not revs: + return -1 wlock = repo.wlock() try: @@ -3263,10 +3487,12 @@ cont = False # drop the second merge parent + repo.dirstate.beginparentchange() repo.setparents(current.node(), nullid) repo.dirstate.write() # fix up dirstate for copies and renames cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev()) + repo.dirstate.endparentchange() # commit node = repo.commit(text=message, user=user, @@ -3858,6 +4084,8 @@ raise util.Abort(_('similarity must be between 0 and 100')) if sim and not update: raise util.Abort(_('cannot use --similarity with --bypass')) + if opts.get('exact') and opts.get('edit'): + raise util.Abort(_('cannot use --exact with --edit')) if update: cmdutil.checkunfinished(repo) @@ -3873,6 +4101,7 @@ try: try: wlock = repo.wlock() + repo.dirstate.beginparentchange() if not opts.get('no_commit'): lock = repo.lock() tr = repo.transaction('import') @@ -3913,6 +4142,7 @@ tr.close() if msgs: repo.savecommitmessage('\n* * *\n'.join(msgs)) + repo.dirstate.endparentchange() return ret except: # re-raises # wlock.release() indirectly calls dirstate.write(): since @@ -4023,7 +4253,7 @@ ] + walkopts, _('[OPTION]... [PATTERN]...')) def locate(ui, repo, *pats, **opts): - """locate files matching specific patterns + """locate files matching specific patterns (DEPRECATED) Print files under Mercurial control in the working directory whose names match the given patterns. @@ -4040,17 +4270,19 @@ will avoid the problem of "xargs" treating single filenames that contain whitespace as multiple filenames. + See :hg:`help files` for a more versatile command. + Returns 0 if a match is found, 1 otherwise. """ end = opts.get('print0') and '\0' or '\n' rev = scmutil.revsingle(repo, opts.get('rev'), None).node() ret = 1 - m = scmutil.match(repo[rev], pats, opts, default='relglob') + ctx = repo[rev] + m = scmutil.match(ctx, pats, opts, default='relglob') m.bad = lambda x, y: False - for abs in repo[rev].walk(m): - if not rev and abs not in repo.dirstate: - continue + + for abs in ctx.matches(m): if opts.get('fullpath'): ui.write(repo.wjoin(abs), end) else: @@ -4211,7 +4443,8 @@ @command('manifest', [('r', 'rev', '', _('revision to display'), _('REV')), - ('', 'all', False, _("list files from all revisions"))], + ('', 'all', False, _("list files from all revisions"))] + + formatteropts, _('[-r REV]')) def manifest(ui, repo, node=None, rev=None, **opts): """output the current or given revision of the project manifest @@ -4446,7 +4679,7 @@ _('[-r REV] [FILE]'), inferrepo=True) def parents(ui, repo, file_=None, **opts): - """show the parents of the working directory or revision + """show the parents of the working directory or revision (DEPRECATED) Print the working directory's parent revisions. If a revision is given via -r/--rev, the parent of that revision will be printed. @@ -4454,6 +4687,8 @@ last changed (before the working directory revision or the argument to --rev if given) is printed. + See :hg:`summary` and :hg:`help revsets` for related information. + Returns 0 on success. """ @@ -4579,17 +4814,22 @@ ctx = repo[r] ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr())) else: + tr = None lock = repo.lock() try: + tr = repo.transaction("phase") # set phase if not revs: raise util.Abort(_('empty revision set')) nodes = [repo[r].node() for r in revs] olddata = repo._phasecache.getphaserevs(repo)[:] - phases.advanceboundary(repo, targetphase, nodes) + phases.advanceboundary(repo, tr, targetphase, nodes) if opts['force']: - phases.retractboundary(repo, targetphase, nodes) + phases.retractboundary(repo, tr, targetphase, nodes) + tr.close() finally: + if tr is not None: + tr.release() lock.release() # moving revision from public to draft may hide them # We have to check result on an unfiltered repository @@ -5365,7 +5605,7 @@ ('0', 'print0', None, _('end filenames with NUL, for use with xargs')), ('', 'rev', [], _('show difference from revision'), _('REV')), ('', 'change', '', _('list the changed files of a revision'), _('REV')), - ] + walkopts + subrepoopts, + ] + walkopts + subrepoopts + formatteropts, _('[OPTION]... [FILE]...'), inferrepo=True) def status(ui, repo, *pats, **opts): @@ -5593,7 +5833,7 @@ ui.write(_('commit: %s\n') % t.strip()) # all ancestors of branch heads - all ancestors of parent = new csets - new = len(repo.changelog.findmissing([ctx.node() for ctx in parents], + new = len(repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)) if new == 0: @@ -5804,7 +6044,11 @@ if date: date = util.parsedate(date) - editor = cmdutil.getcommiteditor(**opts) + if opts.get('remove'): + editform = 'tag.remove' + else: + editform = 'tag.add' + editor = cmdutil.getcommiteditor(editform=editform, **opts) # don't allow tagging the null rev if (not opts.get('remove') and @@ -5816,7 +6060,7 @@ finally: release(lock, wlock) -@command('tags', [], '') +@command('tags', formatteropts, '') def tags(ui, repo, **opts): """list repository tags @@ -5827,7 +6071,10 @@ """ fm = ui.formatter('tags', opts) - hexfunc = ui.debugflag and hex or short + if fm or ui.debugflag: + hexfunc = hex + else: + hexfunc = short tagtype = "" for t, n in reversed(repo.tagslist()): @@ -5841,7 +6088,7 @@ fm.startitem() fm.write('tag', '%s', t, label=label) fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s' - fm.condwrite(not ui.quiet, 'rev id', fmt, + fm.condwrite(not ui.quiet, 'rev node', fmt, repo.changelog.rev(n), hn, label=label) fm.condwrite(ui.verbose and tagtype, 'type', ' %s', tagtype, label=label)
--- a/mercurial/config.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/config.py Sat Sep 27 14:47:52 2014 -0500 @@ -76,7 +76,7 @@ # no data before, remove everything section, item = data if section in self._data: - del self._data[section][item] + self._data[section].pop(item, None) self._source.pop((section, item), None) def parse(self, src, data, sections=None, remap=None, include=None):
--- a/mercurial/context.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/context.py Sat Sep 27 14:47:52 2014 -0500 @@ -276,7 +276,7 @@ def dirs(self): return self._dirs - def dirty(self): + def dirty(self, missing=False, merge=True, branch=True): return False def status(self, other=None, match=None, listignored=False, @@ -347,7 +347,10 @@ def makememctx(repo, parents, text, user, date, branch, files, store, editor=None): def getfilectx(repo, memctx, path): - data, (islink, isexec), copied = store.getfile(path) + data, mode, copied = store.getfile(path) + if data is None: + return None + islink, isexec = mode return memfilectx(repo, path, data, islink=islink, isexec=isexec, copied=copied, memctx=memctx) extra = {} @@ -539,9 +542,11 @@ changectx=self, filelog=filelog) def ancestor(self, c2, warn=False): - """ - return the "best" ancestor context of self and c2 - """ + """return the "best" ancestor context of self and c2 + + If there are multiple candidates, it will show a message and check + merge.preferancestor configuration before falling back to the + revlog ancestor.""" # deal with workingctxs n2 = c2._node if n2 is None: @@ -600,6 +605,9 @@ continue match.bad(fn, _('no such file in rev %s') % self) + def matches(self, match): + return self.walk(match) + class basefilectx(object): """A filecontext object represents the common logic for its children: filectx: read-only access to a filerevision that is already present @@ -713,6 +721,10 @@ return util.binary(self.data()) except IOError: return False + def isexec(self): + return 'x' in self.flags() + def islink(self): + return 'l' in self.flags() def cmp(self, fctx): """compare with other file context @@ -730,9 +742,9 @@ return True def parents(self): - p = self._path + _path = self._path fl = self._filelog - pl = [(p, n, fl) for n in self._filelog.parents(self._filenode)] + pl = [(_path, n, fl) for n in self._filelog.parents(self._filenode)] r = self._filelog.renamed(self._filenode) if r: @@ -762,19 +774,16 @@ this returns fixed value(False is used) as linenumber, if "linenumber" parameter is "False".''' - def decorate_compat(text, rev): - return ([rev] * len(text.splitlines()), text) - - def without_linenumber(text, rev): - return ([(rev, False)] * len(text.splitlines()), text) - - def with_linenumber(text, rev): - size = len(text.splitlines()) - return ([(rev, i) for i in xrange(1, size + 1)], text) - - decorate = (((linenumber is None) and decorate_compat) or - (linenumber and with_linenumber) or - without_linenumber) + if linenumber is None: + def decorate(text, rev): + return ([rev] * len(text.splitlines()), text) + elif linenumber: + def decorate(text, rev): + size = len(text.splitlines()) + return ([(rev, i) for i in xrange(1, size + 1)], text) + else: + def decorate(text, rev): + return ([(rev, False)] * len(text.splitlines()), text) def pair(parent, child): blocks = mdiff.allblocks(parent[1], child[1], opts=diffopts, @@ -1139,13 +1148,16 @@ return '' def ancestor(self, c2): - """return the ancestor context of self and c2""" + """return the "best" ancestor context of self and c2""" return self._parents[0].ancestor(c2) # punt on two parents for now def walk(self, match): return sorted(self._repo.dirstate.walk(match, sorted(self.substate), True, False)) + def matches(self, match): + return sorted(self._repo.dirstate.matches(match)) + def ancestors(self): for a in self._repo.changelog.ancestors( [p.rev() for p in self._parents]): @@ -1161,11 +1173,13 @@ """ + self._repo.dirstate.beginparentchange() for f in self.modified() + self.added(): self._repo.dirstate.normal(f) for f in self.removed(): self._repo.dirstate.drop(f) self._repo.dirstate.setparents(node) + self._repo.dirstate.endparentchange() def dirs(self): return self._repo.dirstate.dirs() @@ -1548,6 +1562,14 @@ # invert comparison to reuse the same code path return fctx.cmp(self) + def remove(self, ignoremissing=False): + """wraps unlink for a repo's working directory""" + util.unlinkpath(self._repo.wjoin(self._path), ignoremissing) + + def write(self, data, flags): + """wraps repo.wwrite""" + self._repo.wwrite(self._path, data, flags) + class memctx(committablectx): """Use memctx to perform in-memory commits via localrepo.commitctx(). @@ -1575,6 +1597,12 @@ supported by util.parsedate() and defaults to current date, extra is a dictionary of metadata or is left empty. """ + + # Mercurial <= 3.1 expects the filectxfn to raise IOError for missing files. + # Extensions that need to retain compatibility across Mercurial 3.1 can use + # this field to determine what to do in filectxfn. + _returnnoneformissingfiles = True + def __init__(self, repo, parents, text, files, filectxfn, user=None, date=None, extra=None, editor=False): super(memctx, self).__init__(repo, text, user, date, extra) @@ -1588,6 +1616,20 @@ self._filectxfn = filectxfn self.substate = {} + # if store is not callable, wrap it in a function + if not callable(filectxfn): + def getfilectx(repo, memctx, path): + fctx = filectxfn[path] + # this is weird but apparently we only keep track of one parent + # (why not only store that instead of a tuple?) + copied = fctx.renamed() + if copied: + copied = copied[0] + return memfilectx(repo, path, fctx.data(), + islink=fctx.islink(), isexec=fctx.isexec(), + copied=copied, memctx=memctx) + self._filectxfn = getfilectx + self._extra = extra and extra.copy() or {} if self._extra.get('branch', '') == '': self._extra['branch'] = 'default' @@ -1597,7 +1639,9 @@ self._repo.savecommitmessage(self._text) def filectx(self, path, filelog=None): - """get a file context from the working directory""" + """get a file context from the working directory + + Returns None if file doesn't exist and should be removed.""" return self._filectxfn(self._repo, self, path) def commit(self): @@ -1615,7 +1659,7 @@ for f, fnode in man.iteritems(): p1node = nullid p2node = nullid - p = pctx[f].parents() + p = pctx[f].parents() # if file isn't in pctx, check p2? if len(p) > 0: p1node = p[0].node() if len(p) > 1: @@ -1652,9 +1696,14 @@ return len(self.data()) def flags(self): return self._flags - def isexec(self): - return 'x' in self._flags - def islink(self): - return 'l' in self._flags def renamed(self): return self._copied + + def remove(self, ignoremissing=False): + """wraps unlink for a repo's working directory""" + # need to figure out what to do here + del self._changectx[self._path] + + def write(self, data, flags): + """wraps repo.wwrite""" + self._data = data
--- a/mercurial/dagutil.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/dagutil.py Sat Sep 27 14:47:52 2014 -0500 @@ -62,7 +62,7 @@ raise NotImplementedError def externalize(self, ix): - '''return a list of (or set if given a set) of node ids''' + '''return a node id''' return self._externalize(ix) def externalizeall(self, ixs): @@ -73,7 +73,7 @@ return list(ids) def internalize(self, id): - '''return a list of (or set if given a set) of node ixs''' + '''return a node ix''' return self._internalize(id) def internalizeall(self, ids, filterunknown=False):
--- a/mercurial/dirstate.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/dirstate.py Sat Sep 27 14:47:52 2014 -0500 @@ -44,6 +44,30 @@ self._lastnormaltime = 0 self._ui = ui self._filecache = {} + self._parentwriters = 0 + + def beginparentchange(self): + '''Marks the beginning of a set of changes that involve changing + the dirstate parents. If there is an exception during this time, + the dirstate will not be written when the wlock is released. This + prevents writing an incoherent dirstate where the parent doesn't + match the contents. + ''' + self._parentwriters += 1 + + def endparentchange(self): + '''Marks the end of a set of changes that involve changing the + dirstate parents. Once all parent changes have been marked done, + the wlock will be free to write the dirstate on release. + ''' + if self._parentwriters > 0: + self._parentwriters -= 1 + + def pendingparentchange(self): + '''Returns true if the dirstate is in the middle of a set of changes + that modify the dirstate parent. + ''' + return self._parentwriters > 0 @propertycache def _map(self): @@ -232,6 +256,10 @@ See localrepo.setparents() """ + if self._parentwriters == 0: + raise ValueError("cannot set dirstate parent without " + "calling dirstate.beginparentchange") + self._dirty = self._dirtypl = True oldp2 = self._pl[1] self._pl = p1, p2 @@ -300,6 +328,7 @@ delattr(self, a) self._lastnormaltime = 0 self._dirty = False + self._parentwriters = 0 def copy(self, source, dest): """Mark dest as a copy of source. Unmark dest if source is None.""" @@ -873,3 +902,21 @@ return (lookup, modified, added, removed, deleted, unknown, ignored, clean) + + def matches(self, match): + ''' + return files in the dirstate (in whatever state) filtered by match + ''' + dmap = self._map + if match.always(): + return dmap.keys() + files = match.files() + if match.matchfn == match.exact: + # 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): + # fast path -- all the values are known to be files, so just return + # that + return list(files) + return [f for f in dmap if match(f)]
--- a/mercurial/dispatch.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/dispatch.py Sat Sep 27 14:47:52 2014 -0500 @@ -58,6 +58,8 @@ if len(inst.args) > 1: ferr.write(_("hg: parse error at %s: %s\n") % (inst.args[1], inst.args[0])) + if (inst.args[0][0] == ' '): + ferr.write(_("unexpected leading whitespace\n")) else: ferr.write(_("hg: parse error: %s\n") % inst.args[0]) return -1 @@ -155,6 +157,8 @@ if len(inst.args) > 1: ui.warn(_("hg: parse error at %s: %s\n") % (inst.args[1], inst.args[0])) + if (inst.args[0][0] == ' '): + ui.warn(_("unexpected leading whitespace\n")) else: ui.warn(_("hg: parse error: %s\n") % inst.args[0]) return -1 @@ -331,17 +335,40 @@ args = shlex.split(cmd) return args + givenargs +def aliasinterpolate(name, args, cmd): + '''interpolate args into cmd for shell aliases + + This also handles $0, $@ and "$@". + ''' + # util.interpolate can't deal with "$@" (with quotes) because it's only + # built to match prefix + patterns. + replacemap = dict(('$%d' % (i + 1), arg) for i, arg in enumerate(args)) + replacemap['$0'] = name + replacemap['$$'] = '$' + replacemap['$@'] = ' '.join(args) + # Typical Unix shells interpolate "$@" (with quotes) as all the positional + # parameters, separated out into words. Emulate the same behavior here by + # quoting the arguments individually. POSIX shells will then typically + # tokenize each argument into exactly one word. + replacemap['"$@"'] = ' '.join(util.shellquote(arg) for arg in args) + # escape '\$' for regex + regex = '|'.join(replacemap.keys()).replace('$', r'\$') + r = re.compile(regex) + return r.sub(lambda x: replacemap[x.group()], cmd) + class cmdalias(object): def __init__(self, name, definition, cmdtable): self.name = self.cmd = name self.cmdname = '' self.definition = definition + self.fn = None self.args = [] self.opts = [] self.help = '' self.norepo = True self.optionalrepo = False - self.badalias = False + self.badalias = None + self.unknowncmd = False try: aliases, entry = cmdutil.findcmd(self.name, cmdtable) @@ -354,11 +381,7 @@ self.shadows = False if not self.definition: - def fn(ui, *args): - ui.warn(_("no definition for alias '%s'\n") % self.name) - return -1 - self.fn = fn - self.badalias = True + self.badalias = _("no definition for alias '%s'") % self.name return if self.definition.startswith('!'): @@ -376,10 +399,7 @@ % (int(m.groups()[0]), self.name)) return '' cmd = re.sub(r'\$(\d+|\$)', _checkvar, self.definition[1:]) - replace = dict((str(i + 1), arg) for i, arg in enumerate(args)) - replace['0'] = self.name - replace['@'] = ' '.join(args) - cmd = util.interpolate(r'\$', replace, cmd, escape_prefix=True) + cmd = aliasinterpolate(self.name, args, cmd) return util.system(cmd, environ=env, out=ui.fout) self.fn = fn return @@ -387,26 +407,17 @@ try: args = shlex.split(self.definition) except ValueError, inst: - def fn(ui, *args): - ui.warn(_("error in definition for alias '%s': %s\n") - % (self.name, inst)) - return -1 - self.fn = fn - self.badalias = True + self.badalias = (_("error in definition for alias '%s': %s") + % (self.name, inst)) return self.cmdname = cmd = args.pop(0) args = map(util.expandpath, args) for invalidarg in ("--cwd", "-R", "--repository", "--repo", "--config"): if _earlygetopt([invalidarg], args): - def fn(ui, *args): - ui.warn(_("error in definition for alias '%s': %s may only " - "be given on the command line\n") - % (self.name, invalidarg)) - return -1 - - self.fn = fn - self.badalias = True + self.badalias = (_("error in definition for alias '%s': %s may " + "only be given on the command line") + % (self.name, invalidarg)) return try: @@ -427,26 +438,24 @@ self.__doc__ = self.fn.__doc__ except error.UnknownCommand: - def fn(ui, *args): - ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \ - % (self.name, cmd)) + self.badalias = (_("alias '%s' resolves to unknown command '%s'") + % (self.name, cmd)) + self.unknowncmd = True + except error.AmbiguousCommand: + self.badalias = (_("alias '%s' resolves to ambiguous command '%s'") + % (self.name, cmd)) + + def __call__(self, ui, *args, **opts): + if self.badalias: + hint = None + if self.unknowncmd: try: # check if the command is in a disabled extension - commands.help_(ui, cmd, unknowncmd=True) + cmd, ext = extensions.disabledcmd(ui, self.cmdname)[:2] + hint = _("'%s' is provided by '%s' extension") % (cmd, ext) except error.UnknownCommand: pass - return -1 - self.fn = fn - self.badalias = True - except error.AmbiguousCommand: - def fn(ui, *args): - ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \ - % (self.name, cmd)) - return -1 - self.fn = fn - self.badalias = True - - def __call__(self, ui, *args, **opts): + raise util.Abort(self.badalias, hint=hint) if self.shadows: ui.debug("alias '%s' shadows command '%s'\n" % (self.name, self.cmdname))
--- a/mercurial/encoding.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/encoding.py Sat Sep 27 14:47:52 2014 -0500 @@ -302,6 +302,49 @@ except LookupError, k: raise error.Abort(k, hint="please check your locale settings") +_jsonmap = {} + +def jsonescape(s): + '''returns a string suitable for JSON + + JSON is problematic for us because it doesn't support non-Unicode + bytes. To deal with this, we take the following approach: + + - localstr objects are converted back to UTF-8 + - valid UTF-8/ASCII strings are passed as-is + - other strings are converted to UTF-8b surrogate encoding + - apply JSON-specified string escaping + + (escapes are doubled in these tests) + + >>> jsonescape('this is a test') + 'this is a test' + >>> jsonescape('escape characters: \\0 \\x0b \\t \\n \\r \\" \\\\') + 'escape characters: \\\\u0000 \\\\u000b \\\\t \\\\n \\\\r \\\\" \\\\\\\\' + >>> jsonescape('a weird byte: \\xdd') + 'a weird byte: \\xed\\xb3\\x9d' + >>> jsonescape('utf-8: caf\\xc3\\xa9') + 'utf-8: caf\\xc3\\xa9' + >>> jsonescape('') + '' + ''' + + if not _jsonmap: + for x in xrange(32): + _jsonmap[chr(x)] = "\u%04x" %x + for x in xrange(32, 256): + c = chr(x) + _jsonmap[c] = c + _jsonmap['\t'] = '\\t' + _jsonmap['\n'] = '\\n' + _jsonmap['\"'] = '\\"' + _jsonmap['\\'] = '\\\\' + _jsonmap['\b'] = '\\b' + _jsonmap['\f'] = '\\f' + _jsonmap['\r'] = '\\r' + + return ''.join(_jsonmap[c] for c in toutf8b(s)) + def toutf8b(s): '''convert a local, possibly-binary string into UTF-8b @@ -336,8 +379,8 @@ return s._utf8 try: - if s.decode('utf-8'): - return s + s.decode('utf-8') + return s except UnicodeDecodeError: # surrogate-encode any characters that don't round-trip s2 = s.decode('utf-8', 'ignore').encode('utf-8')
--- a/mercurial/error.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/error.py Sat Sep 27 14:47:52 2014 -0500 @@ -43,13 +43,13 @@ self.hint = kw.get('hint') class ConfigError(Abort): - 'Exception raised when parsing config files' + """Exception raised when parsing config files""" class OutOfBandError(Exception): - 'Exception raised when a remote repo reports failure' + """Exception raised when a remote repo reports failure""" class ParseError(Exception): - 'Exception raised when parsing config files (msg[, pos])' + """Exception raised when parsing config files (msg[, pos])""" class RepoError(Exception): def __init__(self, *args, **kw):
--- a/mercurial/exchange.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/exchange.py Sat Sep 27 14:47:52 2014 -0500 @@ -31,12 +31,26 @@ if version == '10': if alg is None: alg = changegroup.readexactly(fh, 2) - return changegroup.unbundle10(fh, alg) + return changegroup.cg1unpacker(fh, alg) elif version == '2X': return bundle2.unbundle20(ui, fh, header=magic + version) else: raise util.Abort(_('%s: unknown bundle version %s') % (fname, version)) +def buildobsmarkerspart(bundler, markers): + """add an obsmarker part to the bundler with <markers> + + No part is created if markers is empty. + Raises ValueError if the bundler doesn't support any known obsmarker format. + """ + if markers: + remoteversions = bundle2.obsmarkersversion(bundler.capabilities) + version = obsolete.commonversion(remoteversions) + if version is None: + raise ValueError('bundler do not support common obsmarker format') + stream = obsolete.encodemarkers(markers, True, version=version) + return bundler.newpart('B2X:OBSMARKERS', data=stream) + return None class pushoperation(object): """A object that represent a single push operation @@ -77,8 +91,59 @@ self.remoteheads = None # testable as a boolean indicating if any nodes are missing locally. self.incoming = None - # set of all heads common after changeset bundle push - self.commonheads = None + # phases changes that must be pushed along side the changesets + self.outdatedphases = None + # phases changes that must be pushed if changeset push fails + self.fallbackoutdatedphases = None + # outgoing obsmarkers + self.outobsmarkers = set() + # outgoing bookmarks + self.outbookmarks = [] + + @util.propertycache + def futureheads(self): + """future remote heads if the changeset push succeeds""" + return self.outgoing.missingheads + + @util.propertycache + def fallbackheads(self): + """future remote heads if the changeset push fails""" + if self.revs is None: + # not target to push, all common are relevant + return self.outgoing.commonheads + unfi = self.repo.unfiltered() + # I want cheads = heads(::missingheads and ::commonheads) + # (missingheads is revs with secret changeset filtered out) + # + # This can be expressed as: + # cheads = ( (missingheads and ::commonheads) + # + (commonheads and ::missingheads))" + # ) + # + # while trying to push we already computed the following: + # common = (::commonheads) + # missing = ((commonheads::missingheads) - commonheads) + # + # We can pick: + # * missingheads part of common (::commonheads) + common = set(self.outgoing.common) + nm = self.repo.changelog.nodemap + cheads = [node for node in self.revs if nm[node] in common] + # and + # * commonheads parents on missing + revset = unfi.set('%ln and parents(roots(%ln))', + self.outgoing.commonheads, + self.outgoing.missing) + cheads.extend(c.node() for c in revset) + return cheads + + @property + def commonheads(self): + """set of all common heads after changeset bundle push""" + if self.ret: + return self.futureheads + else: + return self.fallbackheads def push(repo, remote, force=False, revs=None, newbranch=False): '''Push outgoing changesets (limited by revs) from a local @@ -136,9 +201,9 @@ and pushop.remote.capable('bundle2-exp')): _pushbundle2(pushop) _pushchangeset(pushop) - _pushcomputecommonheads(pushop) _pushsyncphase(pushop) _pushobsolete(pushop) + _pushbookmark(pushop) finally: if lock is not None: lock.release() @@ -146,11 +211,41 @@ if locallock is not None: locallock.release() - _pushbookmark(pushop) return pushop.ret +# list of steps to perform discovery before push +pushdiscoveryorder = [] + +# Mapping between step name and function +# +# This exists to help extensions wrap steps if necessary +pushdiscoverymapping = {} + +def pushdiscovery(stepname): + """decorator for function performing discovery before push + + The function is added to the step -> function mapping and appended to the + list of steps. Beware that decorated function will be added in order (this + may matter). + + You can only use this decorator for a new step, if you want to wrap a step + from an extension, change the pushdiscovery dictionary directly.""" + def dec(func): + assert stepname not in pushdiscoverymapping + pushdiscoverymapping[stepname] = func + pushdiscoveryorder.append(stepname) + return func + return dec + def _pushdiscovery(pushop): - # discovery + """Run all discovery steps""" + for stepname in pushdiscoveryorder: + step = pushdiscoverymapping[stepname] + step(pushop) + +@pushdiscovery('changeset') +def _pushdiscoverychangeset(pushop): + """discover the changeset that need to be pushed""" unfi = pushop.repo.unfiltered() fci = discovery.findcommonincoming commoninc = fci(unfi, pushop.remote, force=pushop.force) @@ -162,6 +257,70 @@ pushop.remoteheads = remoteheads pushop.incoming = inc +@pushdiscovery('phase') +def _pushdiscoveryphase(pushop): + """discover the phase that needs to be pushed + + (computed for both success and failure case for changesets push)""" + outgoing = pushop.outgoing + unfi = pushop.repo.unfiltered() + remotephases = pushop.remote.listkeys('phases') + publishing = remotephases.get('publishing', False) + ana = phases.analyzeremotephases(pushop.repo, + pushop.fallbackheads, + remotephases) + pheads, droots = ana + extracond = '' + if not publishing: + extracond = ' and public()' + revset = 'heads((%%ln::%%ln) %s)' % extracond + # Get the list of all revs draft on remote by public here. + # XXX Beware that revset break if droots is not strictly + # XXX root we may want to ensure it is but it is costly + fallback = list(unfi.set(revset, droots, pushop.fallbackheads)) + if not outgoing.missing: + future = fallback + else: + # adds changeset we are going to push as draft + # + # should not be necessary for pushblishing server, but because of an + # issue fixed in xxxxx we have to do it anyway. + fdroots = list(unfi.set('roots(%ln + %ln::)', + outgoing.missing, droots)) + fdroots = [f.node() for f in fdroots] + future = list(unfi.set(revset, fdroots, pushop.futureheads)) + pushop.outdatedphases = future + pushop.fallbackoutdatedphases = fallback + +@pushdiscovery('obsmarker') +def _pushdiscoveryobsmarkers(pushop): + if (obsolete._enabled + and pushop.repo.obsstore + and 'obsolete' in pushop.remote.listkeys('namespaces')): + repo = pushop.repo + # very naive computation, that can be quite expensive on big repo. + # However: evolution is currently slow on them anyway. + nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads)) + pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes) + +@pushdiscovery('bookmarks') +def _pushdiscoverybookmarks(pushop): + ui = pushop.ui + repo = pushop.repo.unfiltered() + remote = pushop.remote + ui.debug("checking for updated bookmarks\n") + ancestors = () + if pushop.revs: + revnums = map(repo.changelog.rev, pushop.revs) + ancestors = repo.changelog.ancestors(revnums, inclusive=True) + remotebookmark = remote.listkeys('bookmarks') + + comp = bookmarks.compare(repo, repo._bookmarks, remotebookmark, srchex=hex) + addsrc, adddst, advsrc, advdst, diverge, differ, invalid = comp + for b, scid, dcid in advsrc: + if not ancestors or repo[scid].rev() in ancestors: + pushop.outbookmarks.append((b, dcid, scid)) + def _pushcheckoutgoing(pushop): outgoing = pushop.outgoing unfi = pushop.repo.unfiltered() @@ -201,6 +360,31 @@ newbm) return True +# List of names of steps to perform for an outgoing bundle2, order matters. +b2partsgenorder = [] + +# Mapping between step name and function +# +# This exists to help extensions wrap steps if necessary +b2partsgenmapping = {} + +def b2partsgenerator(stepname): + """decorator for function generating bundle2 part + + The function is added to the step -> function mapping and appended to the + list of steps. Beware that decorated functions will be added in order + (this may matter). + + You can only use this decorator for new steps, if you want to wrap a step + from an extension, attack the b2partsgenmapping dictionary directly.""" + def dec(func): + assert stepname not in b2partsgenmapping + b2partsgenmapping[stepname] = func + b2partsgenorder.append(stepname) + return func + return dec + +@b2partsgenerator('changeset') def _pushb2ctx(pushop, bundler): """handle changegroup push through bundle2 @@ -210,7 +394,6 @@ return pushop.stepsdone.add('changesets') # Send known heads to the server for race detection. - pushop.stepsdone.add('changesets') if not _pushcheckoutgoing(pushop): return pushop.repo.prepushoutgoinghooks(pushop.repo, @@ -218,7 +401,7 @@ pushop.outgoing) if not pushop.force: bundler.newpart('B2X:CHECK:HEADS', data=iter(pushop.remoteheads)) - cg = changegroup.getlocalbundle(pushop.repo, 'push', pushop.outgoing) + cg = changegroup.getlocalchangegroup(pushop.repo, 'push', pushop.outgoing) cgpart = bundler.newpart('B2X:CHANGEGROUP', data=cg.getchunks()) def handlereply(op): """extract addchangroup returns from server reply""" @@ -227,8 +410,82 @@ pushop.ret = cgreplies['changegroup'][0]['return'] return handlereply -# list of function that may decide to add parts to an outgoing bundle2 -bundle2partsgenerators = [_pushb2ctx] +@b2partsgenerator('phase') +def _pushb2phases(pushop, bundler): + """handle phase push through bundle2""" + if 'phases' in pushop.stepsdone: + return + b2caps = bundle2.bundle2caps(pushop.remote) + if not 'b2x:pushkey' in b2caps: + return + pushop.stepsdone.add('phases') + part2node = [] + enc = pushkey.encode + for newremotehead in pushop.outdatedphases: + part = bundler.newpart('b2x:pushkey') + part.addparam('namespace', enc('phases')) + part.addparam('key', enc(newremotehead.hex())) + part.addparam('old', enc(str(phases.draft))) + part.addparam('new', enc(str(phases.public))) + part2node.append((part.id, newremotehead)) + def handlereply(op): + for partid, node in part2node: + partrep = op.records.getreplies(partid) + results = partrep['pushkey'] + assert len(results) <= 1 + msg = None + if not results: + msg = _('server ignored update of %s to public!\n') % node + elif not int(results[0]['return']): + msg = _('updating %s to public failed!\n') % node + if msg is not None: + pushop.ui.warn(msg) + return handlereply + +@b2partsgenerator('obsmarkers') +def _pushb2obsmarkers(pushop, bundler): + if 'obsmarkers' in pushop.stepsdone: + return + remoteversions = bundle2.obsmarkersversion(bundler.capabilities) + if obsolete.commonversion(remoteversions) is None: + return + pushop.stepsdone.add('obsmarkers') + if pushop.outobsmarkers: + buildobsmarkerspart(bundler, pushop.outobsmarkers) + +@b2partsgenerator('bookmarks') +def _pushb2bookmarks(pushop, bundler): + """handle phase push through bundle2""" + if 'bookmarks' in pushop.stepsdone: + return + b2caps = bundle2.bundle2caps(pushop.remote) + if 'b2x:pushkey' not in b2caps: + return + pushop.stepsdone.add('bookmarks') + part2book = [] + enc = pushkey.encode + for book, old, new in pushop.outbookmarks: + part = bundler.newpart('b2x:pushkey') + part.addparam('namespace', enc('bookmarks')) + part.addparam('key', enc(book)) + part.addparam('old', enc(old)) + part.addparam('new', enc(new)) + part2book.append((part.id, book)) + def handlereply(op): + for partid, book in part2book: + partrep = op.records.getreplies(partid) + results = partrep['pushkey'] + assert len(results) <= 1 + if not results: + pushop.ui.warn(_('server ignored bookmark %s update\n') % book) + else: + ret = int(results[0]['return']) + if ret: + pushop.ui.status(_("updating bookmark %s\n") % book) + else: + pushop.ui.warn(_('updating bookmark %s failed!\n') % book) + return handlereply + def _pushbundle2(pushop): """push data to the remote using bundle2 @@ -237,10 +494,11 @@ evolve in the future.""" bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote)) # create reply capability - capsblob = bundle2.encodecaps(pushop.repo.bundle2caps) + capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo)) bundler.newpart('b2x:replycaps', data=capsblob) replyhandlers = [] - for partgen in bundle2partsgenerators: + for partgenname in b2partsgenorder: + partgen = b2partsgenmapping[partgenname] ret = partgen(pushop, bundler) if callable(ret): replyhandlers.append(ret) @@ -278,14 +536,14 @@ or pushop.repo.changelog.filteredrevs): # push everything, # use the fast path, no race possible on push - bundler = changegroup.bundle10(pushop.repo, bundlecaps) + bundler = changegroup.cg1packer(pushop.repo, bundlecaps) cg = changegroup.getsubset(pushop.repo, outgoing, bundler, 'push', fastpath=True) else: - cg = changegroup.getlocalbundle(pushop.repo, 'push', outgoing, + cg = changegroup.getlocalchangegroup(pushop.repo, 'push', outgoing, bundlecaps) # apply changegroup to remote @@ -307,43 +565,8 @@ # change pushop.ret = pushop.remote.addchangegroup(cg, 'push', pushop.repo.url()) -def _pushcomputecommonheads(pushop): - unfi = pushop.repo.unfiltered() - if pushop.ret: - # push succeed, synchronize target of the push - cheads = pushop.outgoing.missingheads - elif pushop.revs is None: - # All out push fails. synchronize all common - cheads = pushop.outgoing.commonheads - else: - # I want cheads = heads(::missingheads and ::commonheads) - # (missingheads is revs with secret changeset filtered out) - # - # This can be expressed as: - # cheads = ( (missingheads and ::commonheads) - # + (commonheads and ::missingheads))" - # ) - # - # while trying to push we already computed the following: - # common = (::commonheads) - # missing = ((commonheads::missingheads) - commonheads) - # - # We can pick: - # * missingheads part of common (::commonheads) - common = set(pushop.outgoing.common) - nm = pushop.repo.changelog.nodemap - cheads = [node for node in pushop.revs if nm[node] in common] - # and - # * commonheads parents on missing - revset = unfi.set('%ln and parents(roots(%ln))', - pushop.outgoing.commonheads, - pushop.outgoing.missing) - cheads.extend(c.node() for c in revset) - pushop.commonheads = cheads - def _pushsyncphase(pushop): """synchronise phase information locally and remotely""" - unfi = pushop.repo.unfiltered() cheads = pushop.commonheads # even when we don't push, exchanging phase data is useful remotephases = pushop.remote.listkeys('phases') @@ -376,19 +599,25 @@ _localphasemove(pushop, cheads, phases.draft) ### Apply local phase on remote - # Get the list of all revs draft on remote by public here. - # XXX Beware that revset break if droots is not strictly - # XXX root we may want to ensure it is but it is costly - outdated = unfi.set('heads((%ln::%ln) and public())', - droots, cheads) + if pushop.ret: + if 'phases' in pushop.stepsdone: + # phases already pushed though bundle2 + return + outdated = pushop.outdatedphases + else: + outdated = pushop.fallbackoutdatedphases + pushop.stepsdone.add('phases') + + # filter heads already turned public by the push + outdated = [c for c in outdated if c.node() not in pheads] b2caps = bundle2.bundle2caps(pushop.remote) if 'b2x:pushkey' in b2caps: # server supports bundle2, let's do a batched push through it # # This will eventually be unified with the changesets bundle2 push bundler = bundle2.bundle20(pushop.ui, b2caps) - capsblob = bundle2.encodecaps(pushop.repo.bundle2caps) + capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo)) bundler.newpart('b2x:replycaps', data=capsblob) part2node = [] enc = pushkey.encode @@ -431,7 +660,12 @@ def _localphasemove(pushop, nodes, phase=phases.public): """move <nodes> to <phase> in the local source repo""" if pushop.locallocked: - phases.advanceboundary(pushop.repo, phase, nodes) + tr = pushop.repo.transaction('push-phase-sync') + try: + phases.advanceboundary(pushop.repo, tr, phase, nodes) + tr.close() + finally: + tr.release() else: # repo is not locked, do not change any phases! # Informs the user that phases should have been moved when @@ -444,13 +678,15 @@ def _pushobsolete(pushop): """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 - if (obsolete._enabled and repo.obsstore and - 'obsolete' in remote.listkeys('namespaces')): + pushop.stepsdone.add('obsmarkers') + if pushop.outobsmarkers: rslts = [] - remotedata = repo.listkeys('obsolete') + remotedata = obsolete._pushkeyescape(pushop.outobsmarkers) for key in sorted(remotedata, reverse=True): # reverse sort to ensure we end with dump0 data = remotedata[key] @@ -461,20 +697,13 @@ def _pushbookmark(pushop): """Update bookmark position on remote""" + if pushop.ret == 0 or 'bookmarks' in pushop.stepsdone: + return + pushop.stepsdone.add('bookmarks') ui = pushop.ui - repo = pushop.repo.unfiltered() remote = pushop.remote - ui.debug("checking for updated bookmarks\n") - revnums = map(repo.changelog.rev, pushop.revs or []) - ancestors = [a for a in repo.changelog.ancestors(revnums, inclusive=True)] - (addsrc, adddst, advsrc, advdst, diverge, differ, invalid - ) = bookmarks.compare(repo, repo._bookmarks, remote.listkeys('bookmarks'), - srchex=hex) - - for b, scid, dcid in advsrc: - if ancestors and repo[scid].rev() not in ancestors: - continue - if remote.pushkey('bookmarks', b, dcid, scid): + for b, old, new in pushop.outbookmarks: + if remote.pushkey('bookmarks', b, old, new): ui.status(_("updating bookmark %s\n") % b) else: ui.warn(_('updating bookmark %s failed!\n') % b) @@ -597,6 +826,7 @@ kwargs['common'] = pullop.common kwargs['heads'] = pullop.heads or pullop.rheads + kwargs['cg'] = pullop.fetch if 'b2x:listkeys' in remotecaps: kwargs['listkeys'] = ['phase'] if not pullop.fetch: @@ -605,6 +835,11 @@ else: if pullop.heads is None and list(pullop.common) == [nullid]: pullop.repo.ui.status(_("requesting all changes\n")) + if obsolete._enabled: + remoteversions = bundle2.obsmarkersversion(remotecaps) + if obsolete.commonversion(remoteversions) is not None: + kwargs['obsmarkers'] = True + pullop.todosteps.remove('obsmarkers') _pullbundle2extraprepare(pullop, kwargs) if kwargs.keys() == ['format']: return # nothing to pull @@ -673,14 +908,29 @@ pheads, _dr = phases.analyzeremotephases(pullop.repo, pullop.pulledsubset, remotephases) - phases.advanceboundary(pullop.repo, phases.public, pheads) - phases.advanceboundary(pullop.repo, phases.draft, - pullop.pulledsubset) + dheads = pullop.pulledsubset else: # Remote is old or publishing all common changesets # should be seen as public - phases.advanceboundary(pullop.repo, phases.public, - pullop.pulledsubset) + pheads = pullop.pulledsubset + dheads = [] + unfi = pullop.repo.unfiltered() + phase = unfi._phasecache.phase + rev = unfi.changelog.nodemap.get + public = phases.public + draft = phases.draft + + # exclude changesets already public locally and update the others + pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public] + if pheads: + tr = pullop.gettransaction() + phases.advanceboundary(pullop.repo, tr, public, pheads) + + # exclude changesets already draft locally and update the others + dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft] + if dheads: + tr = pullop.gettransaction() + phases.advanceboundary(pullop.repo, tr, draft, dheads) def _pullobsolete(pullop): """utility function to pull obsolete markers from a remote @@ -707,10 +957,34 @@ def caps20to10(repo): """return a set with appropriate options to use bundle20 during getbundle""" caps = set(['HG2X']) - capsblob = bundle2.encodecaps(repo.bundle2caps) + capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo)) caps.add('bundle2=' + urllib.quote(capsblob)) return caps +# List of names of steps to perform for a bundle2 for getbundle, order matters. +getbundle2partsorder = [] + +# Mapping between step name and function +# +# This exists to help extensions wrap steps if necessary +getbundle2partsmapping = {} + +def getbundle2partsgenerator(stepname): + """decorator for function generating bundle2 part for getbundle + + The function is added to the step -> function mapping and appended to the + list of steps. Beware that decorated functions will be added in order + (this may matter). + + You can only use this decorator for new steps, if you want to wrap a step + from an extension, attack the getbundle2partsmapping dictionary directly.""" + def dec(func): + assert stepname not in getbundle2partsmapping + getbundle2partsmapping[stepname] = func + getbundle2partsorder.append(stepname) + return func + return dec + def getbundle(repo, source, heads=None, common=None, bundlecaps=None, **kwargs): """return a full bundle (with potentially multiple kind of parts) @@ -719,43 +993,79 @@ passed. For now, the bundle can contain only changegroup, but this will changes when more part type will be available for bundle2. - This is different from changegroup.getbundle that only returns an HG10 + This is different from changegroup.getchangegroup that only returns an HG10 changegroup bundle. They may eventually get reunited in the future when we have a clearer idea of the API we what to query different data. The implementation is at a very early stage and will get massive rework when the API of bundle is refined. """ - # build changegroup bundle here. - cg = changegroup.getbundle(repo, source, heads=heads, - common=common, bundlecaps=bundlecaps) + # bundle10 case if bundlecaps is None or 'HG2X' not in bundlecaps: + if bundlecaps and not kwargs.get('cg', True): + raise ValueError(_('request for bundle10 must include changegroup')) + if kwargs: raise ValueError(_('unsupported getbundle arguments: %s') % ', '.join(sorted(kwargs.keys()))) - return cg - # very crude first implementation, - # the bundle API will change and the generation will be done lazily. + return changegroup.getchangegroup(repo, source, heads=heads, + common=common, bundlecaps=bundlecaps) + + # bundle20 case b2caps = {} for bcaps in bundlecaps: if bcaps.startswith('bundle2='): blob = urllib.unquote(bcaps[len('bundle2='):]) b2caps.update(bundle2.decodecaps(blob)) bundler = bundle2.bundle20(repo.ui, b2caps) + + for name in getbundle2partsorder: + func = getbundle2partsmapping[name] + kwargs['heads'] = heads + kwargs['common'] = common + func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps, + **kwargs) + + return util.chunkbuffer(bundler.getchunks()) + +@getbundle2partsgenerator('changegroup') +def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None, + b2caps=None, heads=None, common=None, **kwargs): + """add a changegroup part to the requested bundle""" + cg = None + if kwargs.get('cg', True): + # build changegroup bundle here. + cg = changegroup.getchangegroup(repo, source, heads=heads, + common=common, bundlecaps=bundlecaps) + if cg: bundler.newpart('b2x:changegroup', data=cg.getchunks()) + +@getbundle2partsgenerator('listkeys') +def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None, + b2caps=None, **kwargs): + """add parts containing listkeys namespaces to the requested bundle""" listkeys = kwargs.get('listkeys', ()) for namespace in listkeys: part = bundler.newpart('b2x:listkeys') part.addparam('namespace', namespace) keys = repo.listkeys(namespace).items() part.data = pushkey.encodekeys(keys) - _getbundleextrapart(bundler, repo, source, heads=heads, common=common, - bundlecaps=bundlecaps, **kwargs) - return util.chunkbuffer(bundler.getchunks()) -def _getbundleextrapart(bundler, repo, source, heads=None, common=None, - bundlecaps=None, **kwargs): +@getbundle2partsgenerator('obsmarkers') +def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None, + b2caps=None, heads=None, **kwargs): + """add an obsolescence markers part to the requested bundle""" + if kwargs.get('obsmarkers', False): + if heads is None: + heads = repo.heads() + subset = [c.node() for c in repo.set('::%ln', heads)] + markers = repo.obsstore.relevantmarkers(subset) + buildobsmarkerspart(bundler, markers) + +@getbundle2partsgenerator('extra') +def _getbundleextrapart(bundler, repo, source, bundlecaps=None, + b2caps=None, **kwargs): """hook function to let extensions add parts to the requested bundle""" pass
--- a/mercurial/filelog.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/filelog.py Sat Sep 27 14:47:52 2014 -0500 @@ -9,25 +9,23 @@ import re _mdre = re.compile('\1\n') -def _parsemeta(text): +def parsemeta(text): """return (metadatadict, keylist, metadatasize)""" # text can be buffer, so we can't use .startswith or .index if text[:2] != '\1\n': - return None, None, None + return None, None s = _mdre.search(text, 2).start() mtext = text[2:s] meta = {} - keys = [] for l in mtext.splitlines(): k, v = l.split(": ", 1) meta[k] = v - keys.append(k) - return meta, keys, (s + 2) + return meta, (s + 2) -def _packmeta(meta, keys=None): - if not keys: - keys = sorted(meta.iterkeys()) - return "".join("%s: %s\n" % (k, meta[k]) for k in keys) +def packmeta(meta, text): + keys = sorted(meta.iterkeys()) + metatext = "".join("%s: %s\n" % (k, meta[k]) for k in keys) + return "\1\n%s\1\n%s" % (metatext, text) class filelog(revlog.revlog): def __init__(self, opener, path): @@ -43,14 +41,14 @@ def add(self, text, meta, transaction, link, p1=None, p2=None): if meta or text.startswith('\1\n'): - text = "\1\n%s\1\n%s" % (_packmeta(meta), text) + text = packmeta(meta, text) return self.addrevision(text, transaction, link, p1, p2) def renamed(self, node): if self.parents(node)[0] != revlog.nullid: return False t = self.revision(node) - m = _parsemeta(t)[0] + m = parsemeta(t)[0] if m and "copy" in m: return (m["copy"], revlog.bin(m["copyrev"])) return False
--- a/mercurial/filemerge.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/filemerge.py Sat Sep 27 14:47:52 2014 -0500 @@ -178,24 +178,30 @@ ui = repo.ui + validkeep = ['keep', 'keep-merge3'] + # do we attempt to simplemerge first? try: premerge = _toolbool(ui, tool, "premerge", not binary) except error.ConfigError: premerge = _toolstr(ui, tool, "premerge").lower() - valid = 'keep'.split() - if premerge not in valid: - _valid = ', '.join(["'" + v + "'" for v in valid]) + if premerge not in validkeep: + _valid = ', '.join(["'" + v + "'" for v in validkeep]) raise error.ConfigError(_("%s.premerge not valid " "('%s' is neither boolean nor %s)") % (tool, premerge, _valid)) if premerge: + if premerge == 'keep-merge3': + if not labels: + labels = _defaultconflictlabels + if len(labels) < 3: + labels.append('base') r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels) if not r: ui.debug(" premerge successful\n") return 0 - if premerge != 'keep': + if premerge not in validkeep: util.copyfile(back, a) # restore from backup and try again return 1 # continue merging @@ -206,7 +212,8 @@ """ Uses the internal non-interactive simple merge algorithm for merging files. It will fail if there are any conflicts and leave markers in - the partially merged file.""" + the partially merged file. Markers will have two sections, one for each side + of merge.""" tool, toolpath, binary, symlink = toolconf if symlink: repo.ui.warn(_('warning: internal:merge cannot merge symlinks ' @@ -218,10 +225,25 @@ ui = repo.ui - r = simplemerge.simplemerge(ui, a, b, c, label=labels, no_minimal=True) + r = simplemerge.simplemerge(ui, a, b, c, label=labels) return True, r return False, 0 +@internaltool('merge3', True, + _("merging %s incomplete! " + "(edit conflicts, then use 'hg resolve --mark')\n")) +def _imerge3(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None): + """ + Uses the internal non-interactive simple merge algorithm for merging + files. It will fail if there are any conflicts and leave markers in + the partially merged file. Marker will have three sections, one from each + side of the merge and one for the base content.""" + if not labels: + labels = _defaultconflictlabels + if len(labels) < 3: + labels.append('base') + return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels) + @internaltool('tagmerge', True, _("automatic tag merging of %s failed! " "(use 'hg resolve --tool internal:merge' or another merge " @@ -312,23 +334,27 @@ _defaultconflictlabels = ['local', 'other'] -def _formatlabels(repo, fcd, fco, labels): +def _formatlabels(repo, fcd, fco, fca, labels): """Formats the given labels using the conflict marker template. Returns a list of formatted labels. """ cd = fcd.changectx() co = fco.changectx() + ca = fca.changectx() ui = repo.ui template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker) template = templater.parsestring(template, quoted=False) - tmpl = templater.templater(None, cache={ 'conflictmarker' : template }) + tmpl = templater.templater(None, cache={'conflictmarker': template}) + + pad = max(len(l) for l in labels) - pad = max(len(labels[0]), len(labels[1])) - - return [_formatconflictmarker(repo, cd, tmpl, labels[0], pad), - _formatconflictmarker(repo, co, tmpl, labels[1], pad)] + newlabels = [_formatconflictmarker(repo, cd, tmpl, labels[0], pad), + _formatconflictmarker(repo, co, tmpl, labels[1], pad)] + if len(labels) > 2: + newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad)) + return newlabels def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None): """perform a 3-way merge in the working directory @@ -388,16 +414,13 @@ ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca)) markerstyle = ui.config('ui', 'mergemarkers', 'basic') - if markerstyle == 'basic': - formattedlabels = _defaultconflictlabels - else: - if not labels: - labels = _defaultconflictlabels - - formattedlabels = _formatlabels(repo, fcd, fco, labels) + if not labels: + labels = _defaultconflictlabels + if markerstyle != 'basic': + labels = _formatlabels(repo, fcd, fco, fca, labels) needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf, - (a, b, c, back), labels=formattedlabels) + (a, b, c, back), labels=labels) if not needcheck: if r: if onfailure:
--- a/mercurial/formatter.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/formatter.py Sat Sep 27 14:47:52 2014 -0500 @@ -5,6 +5,10 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. +import cPickle +from i18n import _ +import encoding, util + class baseformatter(object): def __init__(self, ui, topic, opts): self._ui = ui @@ -12,7 +16,7 @@ self._style = opts.get("style") self._template = opts.get("template") self._item = None - def __bool__(self): + def __nonzero__(self): '''return False if we're not doing real templating so we can skip extra work''' return True @@ -47,7 +51,7 @@ '''the default text output scheme''' def __init__(self, ui, topic, opts): baseformatter.__init__(self, ui, topic, opts) - def __bool__(self): + def __nonzero__(self): return False def startitem(self): pass @@ -67,14 +71,67 @@ class debugformatter(baseformatter): def __init__(self, ui, topic, opts): baseformatter.__init__(self, ui, topic, opts) - self._ui.write("%s = {\n" % self._topic) + self._ui.write("%s = [\n" % self._topic) def _showitem(self): self._ui.write(" " + repr(self._item) + ",\n") def end(self): baseformatter.end(self) - self._ui.write("}\n") + self._ui.write("]\n") + +class pickleformatter(baseformatter): + def __init__(self, ui, topic, opts): + baseformatter.__init__(self, ui, topic, opts) + self._data = [] + def _showitem(self): + self._data.append(self._item) + def end(self): + baseformatter.end(self) + self._ui.write(cPickle.dumps(self._data)) + +def _jsonifyobj(v): + if isinstance(v, tuple): + return '[' + ', '.join(_jsonifyobj(e) for e in v) + ']' + elif isinstance(v, (int, float)): + return str(v) + else: + return '"%s"' % encoding.jsonescape(v) + +class jsonformatter(baseformatter): + def __init__(self, ui, topic, opts): + baseformatter.__init__(self, ui, topic, opts) + self._ui.write("[") + self._ui._first = True + def _showitem(self): + if self._ui._first: + self._ui._first = False + else: + self._ui.write(",") + + self._ui.write("\n {\n") + first = True + for k, v in sorted(self._item.items()): + if first: + first = False + else: + self._ui.write(",\n") + self._ui.write(' "%s": %s' % (k, _jsonifyobj(v))) + self._ui.write("\n }") + def end(self): + baseformatter.end(self) + self._ui.write("\n]\n") def formatter(ui, topic, opts): - if ui.configbool('ui', 'formatdebug'): + template = opts.get("template", "") + if template == "json": + return jsonformatter(ui, topic, opts) + elif template == "pickle": + return pickleformatter(ui, topic, opts) + elif template == "debug": return debugformatter(ui, topic, opts) + elif template != "": + raise util.Abort(_("custom templates not yet supported")) + elif ui.configbool('ui', 'formatdebug'): + return debugformatter(ui, topic, opts) + elif ui.configbool('ui', 'formatjson'): + return jsonformatter(ui, topic, opts) return plainformatter(ui, topic, opts)
--- a/mercurial/help.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/help.py Sat Sep 27 14:47:52 2014 -0500 @@ -31,7 +31,7 @@ doc = ''.join(rst) return doc -def optrst(options, verbose): +def optrst(header, options, verbose): data = [] multioccur = False for option in options: @@ -59,10 +59,11 @@ data.append((so, lo, desc)) - rst = minirst.maketable(data, 1) + if multioccur: + header += (_(" ([+] can be repeated)")) - if multioccur: - rst.append(_("\n[+] marked option can be specified multiple times\n")) + rst = ['\n%s:\n\n' % header] + rst.extend(minirst.maketable(data, 1)) return ''.join(rst) @@ -235,11 +236,13 @@ rst = [] # check if it's an invalid alias and display its error if it is - if getattr(entry[0], 'badalias', False): - if not unknowncmd: - ui.pushbuffer() - entry[0](ui) - rst.append(ui.popbuffer()) + if getattr(entry[0], 'badalias', None): + rst.append(entry[0].badalias + '\n') + if entry[0].unknowncmd: + try: + rst.extend(helpextcmd(entry[0].cmdname)) + except error.UnknownCommand: + pass return rst # synopsis @@ -277,31 +280,27 @@ mod = extensions.find(name) doc = gettext(mod.__doc__) or '' if '\n' in doc.strip(): - msg = _('use "hg help -e %s" to show help for ' - 'the %s extension') % (name, name) + msg = _('(use "hg help -e %s" to show help for ' + 'the %s extension)') % (name, name) rst.append('\n%s\n' % msg) except KeyError: pass # options if not ui.quiet and entry[1]: - rst.append('\n%s\n\n' % _("options:")) - rst.append(optrst(entry[1], ui.verbose)) + rst.append(optrst(_("options"), entry[1], ui.verbose)) if ui.verbose: - rst.append('\n%s\n\n' % _("global options:")) - rst.append(optrst(commands.globalopts, ui.verbose)) + rst.append(optrst(_("global options"), + commands.globalopts, ui.verbose)) if not ui.verbose: if not full: - rst.append(_('\nuse "hg help %s" to show the full help text\n') + rst.append(_('\n(use "hg %s -h" to show more help)\n') % name) elif not ui.quiet: - omitted = _('use "hg -v help %s" to show more complete' - ' help and the global options') % name - notomitted = _('use "hg -v help %s" to show' - ' the global options') % name - indicateomitted(rst, omitted, notomitted) + rst.append(_('\n(some details hidden, use --verbose ' + 'to show complete help)')) return rst @@ -367,30 +366,25 @@ for t, desc in topics: rst.append(" :%s: %s\n" % (t, desc)) - optlist = [] - if not ui.quiet: - if ui.verbose: - optlist.append((_("global options:"), commands.globalopts)) - if name == 'shortlist': - optlist.append((_('use "hg help" for the full list ' - 'of commands'), ())) + if ui.quiet: + pass + elif ui.verbose: + rst.append('\n%s\n' % optrst(_("global options"), + commands.globalopts, ui.verbose)) + if name == 'shortlist': + rst.append(_('\n(use "hg help" for the full list ' + 'of commands)\n')) + else: + if name == 'shortlist': + rst.append(_('\n(use "hg help" for the full list of commands ' + 'or "hg -v" for details)\n')) + elif name and not full: + rst.append(_('\n(use "hg help %s" to show the full help ' + 'text)\n') % name) else: - if name == 'shortlist': - msg = _('use "hg help" for the full list of commands ' - 'or "hg -v" for details') - elif name and not full: - msg = _('use "hg help %s" to show the full help ' - 'text') % name - else: - msg = _('use "hg -v help%s" to show builtin aliases and ' - 'global options') % (name and " " + name or "") - optlist.append((msg, ())) - - if optlist: - for title, options in optlist: - rst.append('\n%s\n' % title) - if options: - rst.append('\n%s\n' % optrst(options, ui.verbose)) + rst.append(_('\n(use "hg help -v%s" to show built-in aliases ' + 'and global options)\n') + % (name and " " + name or "")) return rst def helptopic(name): @@ -409,8 +403,8 @@ rst += [" %s\n" % l for l in doc().splitlines()] if not ui.verbose: - omitted = (_('use "hg help -v %s" to show more complete help') % - name) + omitted = _('(some details hidden, use --verbose' + ' to show complete help)') indicateomitted(rst, omitted) try: @@ -441,8 +435,8 @@ rst.append('\n') if not ui.verbose: - omitted = (_('use "hg help -v %s" to show more complete help') % - name) + omitted = _('(some details hidden, use --verbose' + ' to show complete help)') indicateomitted(rst, omitted) if mod: @@ -453,8 +447,8 @@ modcmds = set([c.split('|', 1)[0] for c in ct]) rst.extend(helplist(modcmds.__contains__)) else: - rst.append(_('use "hg help extensions" for information on enabling ' - 'extensions\n')) + rst.append(_('(use "hg help extensions" for information on enabling' + ' extensions)\n')) return rst def helpextcmd(name): @@ -465,8 +459,8 @@ rst = listexts(_("'%s' is provided by the following " "extension:") % cmd, {ext: doc}, indent=4) rst.append('\n') - rst.append(_('use "hg help extensions" for information on enabling ' - 'extensions\n')) + rst.append(_('(use "hg help extensions" for information on enabling ' + 'extensions)\n')) return rst
--- a/mercurial/help/config.txt Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/help/config.txt Sat Sep 27 14:47:52 2014 -0500 @@ -229,8 +229,9 @@ Positional arguments like ``$1``, ``$2``, etc. in the alias definition expand to the command arguments. Unmatched arguments are removed. ``$0`` expands to the alias name and ``$@`` expands to all -arguments separated by a space. These expansions happen before the -command is passed to the shell. +arguments separated by a space. ``"$@"`` (with quotes) expands to all +arguments quoted individually and separated by a space. These expansions +happen before the command is passed to the shell. Shell aliases are executed in an environment where ``$HG`` expands to the path of the Mercurial that was used to execute the alias. This is @@ -388,6 +389,57 @@ - :hg:`tag` - :hg:`transplant` +Configuring items below instead of ``changeset`` allows showing +customized message only for specific actions, or showing different +messages for each actions. + +- ``changeset.backout`` for :hg:`backout` +- ``changeset.commit.amend.merge`` for :hg:`commit --amend` on merges +- ``changeset.commit.amend.normal`` for :hg:`commit --amend` on other +- ``changeset.commit.normal.merge`` for :hg:`commit` on merges +- ``changeset.commit.normal.normal`` for :hg:`commit` on other +- ``changeset.fetch`` for :hg:`fetch` (impling merge commit) +- ``changeset.gpg.sign`` for :hg:`sign` +- ``changeset.graft`` for :hg:`graft` +- ``changeset.histedit.edit`` for ``edit`` of :hg:`histedit` +- ``changeset.histedit.fold`` for ``fold`` of :hg:`histedit` +- ``changeset.histedit.mess`` for ``mess`` of :hg:`histedit` +- ``changeset.histedit.pick`` for ``pick`` of :hg:`histedit` +- ``changeset.import.bypass`` for :hg:`import --bypass` +- ``changeset.import.normal.merge`` for :hg:`import` on merges +- ``changeset.import.normal.normal`` for :hg:`import` on other +- ``changeset.mq.qnew`` for :hg:`qnew` +- ``changeset.mq.qfold`` for :hg:`qfold` +- ``changeset.mq.qrefresh`` for :hg:`qrefresh` +- ``changeset.rebase.collapse`` for :hg:`rebase --collapse` +- ``changeset.rebase.merge`` for :hg:`rebase` on merges +- ``changeset.rebase.normal`` for :hg:`rebase` on other +- ``changeset.shelve.shelve`` for :hg:`shelve` +- ``changeset.tag.add`` for :hg:`tag` without ``--remove`` +- ``changeset.tag.remove`` for :hg:`tag --remove` +- ``changeset.transplant.merge`` for :hg:`transplant` on merges +- ``changeset.transplant.normal`` for :hg:`transplant` on other + +These dot-separated lists of names are treated as hierarchical ones. +For example, ``changeset.tag.remove`` customizes the commit message +only for :hg:`tag --remove`, but ``changeset.tag`` customizes the +commit message for :hg:`tag` regardless of ``--remove`` option. + +At the external editor invocation for committing, corresponding +dot-separated list of names without ``changeset.`` prefix +(e.g. ``commit.normal.normal``) is in ``HGEDITFORM`` environment variable. + +In this section, items other than ``changeset`` can be referred from +others. For example, the configuration to list committed files up +below can be referred as ``{listupfiles}``:: + + [committemplate] + listupfiles = {file_adds % + "HG: added {file}\n" }{file_mods % + "HG: changed {file}\n" }{file_dels % + "HG: removed {file}\n" }{if(files, "", + "HG: no files changed\n")} + ``decode/encode`` ----------------- @@ -912,8 +964,10 @@ ``premerge`` Attempt to run internal non-interactive 3-way merge tool before - launching external tool. Options are ``true``, ``false``, or ``keep`` - to leave markers in the file if the premerge fails. + launching external tool. Options are ``true``, ``false``, ``keep`` or + ``keep-merge3``. The ``keep`` option will leave markers in the file if the + premerge fails. The ``keep-merge3`` will do the same but include information + about the base of the merge in the marker (see internal:merge3). Default: True ``binary`` @@ -1586,10 +1640,13 @@ Default is 1; set to 0 to disable. ``style`` - Which template map style to use. + Which template map style to use. The available options are the names of + subdirectories in the HTML templates path. Default is ``paper``. + Example: ``monoblue`` ``templates`` - Where to find the HTML templates. Default is install path. + Where to find the HTML templates. The default path to the HTML templates + can be obtained from ``hg debuginstall``. ``websub`` ----------
--- a/mercurial/help/templates.txt Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/help/templates.txt Sat Sep 27 14:47:52 2014 -0500 @@ -43,6 +43,8 @@ - date(date[, fmt]) +- diff([includepattern [, excludepattern]]) + - fill(text[, width]) - get(dict, key)
--- a/mercurial/hg.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/hg.py Sat Sep 27 14:47:52 2014 -0500 @@ -11,7 +11,7 @@ from node import hex, nullid import localrepo, bundlerepo, unionrepo, httppeer, sshpeer, statichttprepo import bookmarks, lock, util, extensions, error, node, scmutil, phases, url -import cmdutil, discovery +import cmdutil, discovery, repoview import merge as mergemod import verify as verifymod import errno, os, shutil @@ -366,13 +366,20 @@ # Recomputing branch cache might be slow on big repos, # so just copy it + def copybranchcache(fname): + srcbranchcache = srcrepo.join('cache/%s' % fname) + dstbranchcache = os.path.join(dstcachedir, fname) + if os.path.exists(srcbranchcache): + if not os.path.exists(dstcachedir): + os.mkdir(dstcachedir) + util.copyfile(srcbranchcache, dstbranchcache) + dstcachedir = os.path.join(destpath, 'cache') - srcbranchcache = srcrepo.sjoin('cache/branch2') - dstbranchcache = os.path.join(dstcachedir, 'branch2') - if os.path.exists(srcbranchcache): - if not os.path.exists(dstcachedir): - os.mkdir(dstcachedir) - util.copyfile(srcbranchcache, dstbranchcache) + # In local clones we're copying all nodes, not just served + # ones. Therefore copy all branchcaches over. + copybranchcache('branch2') + for cachename in repoview.filtertable: + copybranchcache('branch2-%s' % cachename) # we need to re-init the repo after manually copying the data # into it @@ -425,12 +432,23 @@ destpeer.pushkey('bookmarks', k, '', hex(n)) if destrepo: + template = ( + '# You may want to set your username here if it is not set\n' + "# globally, or this repository requires a different\n" + '# username from your usual configuration. If you want to\n' + '# set something for all of your repositories on this\n' + '# computer, try running the command\n' + "# 'hg config --edit --global'\n" + '# [ui]\n' + '# username = Jane Doe <jdoe@example.com>\n' + '[paths]\n' + 'default = %s\n' + ) fp = destrepo.opener("hgrc", "w", text=True) - fp.write("[paths]\n") u = util.url(abspath) u.passwd = None defaulturl = str(u) - fp.write("default = %s\n" % defaulturl) + fp.write(template % defaulturl) fp.close() destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
--- a/mercurial/hgweb/hgweb_mod.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/hgweb/hgweb_mod.py Sat Sep 27 14:47:52 2014 -0500 @@ -110,7 +110,7 @@ # compare changelog size in addition to mtime to catch # rollbacks made less than a second ago if st.st_mtime != self.mtime or st.st_size != self.size: - r = hg.repository(self.repo.baseui, self.repo.root) + r = hg.repository(self.repo.baseui, self.repo.url()) self.repo = self._getview(r) self.maxchanges = int(self.config("web", "maxchanges", 10)) self.stripecount = int(self.config("web", "stripes", 1)) @@ -390,5 +390,5 @@ } def check_perm(self, req, op): - for hook in permhooks: - hook(self, req, op) + for permhook in permhooks: + permhook(self, req, op)
--- a/mercurial/hgweb/webcommands.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/hgweb/webcommands.py Sat Sep 27 14:47:52 2014 -0500 @@ -1069,7 +1069,7 @@ topicname = req.form.get('node', [None])[0] if not topicname: def topics(**map): - for entries, summary, _ in helpmod.helptable: + for entries, summary, _doc in helpmod.helptable: yield {'topic': entries[0], 'summary': summary} early, other = [], []
--- a/mercurial/i18n.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/i18n.py Sat Sep 27 14:47:52 2014 -0500 @@ -6,7 +6,7 @@ # GNU General Public License version 2 or any later version. import encoding -import gettext, sys, os +import gettext, sys, os, locale # modelled after templater.templatepath: if getattr(sys, 'frozen', None) is not None: @@ -20,7 +20,25 @@ if os.path.isdir(localedir): break -t = gettext.translation('hg', localedir, fallback=True) +_languages = None +if (os.name == 'nt' + and 'LANGUAGE' not in os.environ + and 'LC_ALL' not in os.environ + and 'LC_MESSAGES' not in os.environ + and 'LANG' not in os.environ): + # Try to detect UI language by "User Interface Language Management" API + # if no locale variables are set. Note that locale.getdefaultlocale() + # uses GetLocaleInfo(), which may be different from UI language. + # (See http://msdn.microsoft.com/en-us/library/dd374098(v=VS.85).aspx ) + try: + import ctypes + langid = ctypes.windll.kernel32.GetUserDefaultUILanguage() + _languages = [locale.windows_locale[langid]] + except (ImportError, AttributeError, KeyError): + # ctypes not found or unknown langid + pass + +t = gettext.translation('hg', localedir, _languages, fallback=True) def gettext(message): """Translate message.
--- a/mercurial/localrepo.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/localrepo.py Sat Sep 27 14:47:52 2014 -0500 @@ -180,10 +180,6 @@ requirements = ['revlogv1'] filtername = None - bundle2caps = {'HG2X': (), - 'b2x:listkeys': (), - 'b2x:pushkey': ()} - # a list of (ui, featureset) functions. # only functions defined in module of enabled extensions are invoked featuresetupfuncs = set() @@ -309,7 +305,7 @@ # required by the tests (or some brave tester) if self.ui.configbool('experimental', 'bundle2-exp', False): caps = set(caps) - capsblob = bundle2.encodecaps(self.bundle2caps) + capsblob = bundle2.encodecaps(bundle2.getrepocaps(self)) caps.add('bundle2-exp=' + urllib.quote(capsblob)) return caps @@ -674,8 +670,7 @@ if not self._tagscache.tagslist: l = [] for t, n in self.tags().iteritems(): - r = self.changelog.rev(n) - l.append((r, t, n)) + l.append((self.changelog.rev(n), t, n)) self._tagscache.tagslist = [(t, n) for r, t, n in sorted(l)] return self._tagscache.tagslist @@ -744,11 +739,11 @@ # if publishing we can't copy if there is filtered content return not self.filtered('visible').changelog.filteredrevs - def join(self, f): - return os.path.join(self.path, f) + def join(self, f, *insidef): + return os.path.join(self.path, f, *insidef) - def wjoin(self, f): - return os.path.join(self.root, f) + def wjoin(self, f, *insidef): + return os.path.join(self.root, f, *insidef) def file(self, f): if f[0] == '/': @@ -763,6 +758,7 @@ return self[changeid].parents() def setparents(self, p1, p2=nullid): + self.dirstate.beginparentchange() copies = self.dirstate.setparents(p1, p2) pctx = self[p1] if copies: @@ -776,6 +772,7 @@ for f, s in sorted(self.dirstate.copies().items()): if f not in pctx and s not in pctx: self.dirstate.copy(None, f) + self.dirstate.endparentchange() def filectx(self, path, changeid=None, fileid=None): """changeid can be a changeset revision, node, or tag. @@ -1087,8 +1084,6 @@ return l def unlock(): - if hasunfilteredcache(self, '_phasecache'): - self._phasecache.write() for k, ce in self._filecache.items(): if k == 'dirstate' or k not in self.__dict__: continue @@ -1109,7 +1104,11 @@ return l def unlock(): - self.dirstate.write() + if self.dirstate.pendingparentchange(): + self.dirstate.invalidate() + else: + self.dirstate.write() + self._filecache['dirstate'].refresh() l = self._lock(self.vfs, "wlock", wait, unlock, @@ -1394,9 +1393,12 @@ self.ui.note(f + "\n") try: fctx = ctx[f] - new[f] = self._filecommit(fctx, m1, m2, linkrev, trp, - changed) - m1.set(f, fctx.flags()) + if fctx is None: + removed.append(f) + else: + new[f] = self._filecommit(fctx, m1, m2, linkrev, + trp, changed) + m1.set(f, fctx.flags()) except OSError, inst: self.ui.warn(_("trouble committing %s!\n") % f) raise @@ -1404,9 +1406,7 @@ errcode = getattr(inst, 'errno', errno.ENOENT) if error or errcode and errcode != errno.ENOENT: self.ui.warn(_("trouble committing %s!\n") % f) - raise - else: - removed.append(f) + raise # update manifest m1.update(new) @@ -1439,7 +1439,7 @@ # be compliant anyway # # if minimal phase was 0 we don't need to retract anything - phases.retractboundary(self, targetphase, [n]) + phases.retractboundary(self, tr, targetphase, [n]) tr.close() branchmap.updatecache(self.filtered('served')) return n
--- a/mercurial/manifest.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/manifest.py Sat Sep 27 14:47:52 2014 -0500 @@ -40,6 +40,37 @@ def flagsdiff(self, d2): return dicthelpers.diff(self._flags, d2._flags, "") + +def _checkforbidden(l): + """Check filenames for illegal characters.""" + for f in l: + if '\n' in f or '\r' in f: + raise error.RevlogError( + _("'\\n' and '\\r' disallowed in filenames: %r") % f) + + +# apply the changes collected during the bisect loop to our addlist +# return a delta suitable for addrevision +def _addlistdelta(addlist, x): + # for large addlist arrays, building a new array is cheaper + # than repeatedly modifying the existing one + currentposition = 0 + newaddlist = array.array('c') + + for start, end, content in x: + newaddlist += addlist[currentposition:start] + if content: + newaddlist += array.array('c', content) + + currentposition = end + + newaddlist += addlist[currentposition:] + + deltatext = "".join(struct.pack(">lll", start, end, len(content)) + + content for start, end, content in x) + return deltatext, newaddlist + + class manifest(revlog.revlog): def __init__(self, opener): # we expect to deal with not more than four revs at a time, @@ -131,38 +162,11 @@ def add(self, map, transaction, link, p1=None, p2=None, changed=None): - # apply the changes collected during the bisect loop to our addlist - # return a delta suitable for addrevision - def addlistdelta(addlist, x): - # for large addlist arrays, building a new array is cheaper - # than repeatedly modifying the existing one - currentposition = 0 - newaddlist = array.array('c') - - for start, end, content in x: - newaddlist += addlist[currentposition:start] - if content: - newaddlist += array.array('c', content) - - currentposition = end - - newaddlist += addlist[currentposition:] - - deltatext = "".join(struct.pack(">lll", start, end, len(content)) - + content for start, end, content in x) - return deltatext, newaddlist - - def checkforbidden(l): - for f in l: - if '\n' in f or '\r' in f: - raise error.RevlogError( - _("'\\n' and '\\r' disallowed in filenames: %r") % f) - # if we're using the cache, make sure it is valid and # parented by the same node we're diffing against if not (changed and p1 and (p1 in self._mancache)): files = sorted(map) - checkforbidden(files) + _checkforbidden(files) # if this is changed to support newlines in filenames, # be sure to check the templates/ dir again (especially *-raw.tmpl) @@ -175,7 +179,7 @@ added, removed = changed addlist = self._mancache[p1][1] - checkforbidden(added) + _checkforbidden(added) # combine the changed lists into one list for sorting work = [(x, False) for x in added] work.extend((x, True) for x in removed) @@ -219,7 +223,7 @@ if dstart is not None: delta.append([dstart, dend, "".join(dline)]) # apply the delta to the addlist, and get a delta for addrevision - deltatext, addlist = addlistdelta(addlist, delta) + deltatext, addlist = _addlistdelta(addlist, delta) cachedelta = (self.rev(p1), deltatext) arraytext = addlist text = util.buffer(arraytext)
--- a/mercurial/match.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/match.py Sat Sep 27 14:47:52 2014 -0500 @@ -66,47 +66,39 @@ self._ctx = ctx self._always = False + matchfns = [] if include: kindpats = _normalize(include, 'glob', root, cwd, auditor) self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)') + matchfns.append(im) if exclude: kindpats = _normalize(exclude, 'glob', root, cwd, auditor) self.excludepat, em = _buildmatch(ctx, kindpats, '(?:/|$)') + matchfns.append(lambda f: not em(f)) if exact: if isinstance(patterns, list): self._files = patterns else: self._files = list(patterns) - pm = self.exact + matchfns.append(self.exact) elif patterns: kindpats = _normalize(patterns, default, root, cwd, auditor) self._files = _roots(kindpats) self._anypats = self._anypats or _anypats(kindpats) self.patternspat, pm = _buildmatch(ctx, kindpats, '$') + matchfns.append(pm) - if patterns or exact: - if include: - if exclude: - m = lambda f: im(f) and not em(f) and pm(f) - else: - m = lambda f: im(f) and pm(f) - else: - if exclude: - m = lambda f: not em(f) and pm(f) - else: - m = pm + if not matchfns: + m = util.always + self._always = True + elif len(matchfns) == 1: + m = matchfns[0] else: - if include: - if exclude: - m = lambda f: im(f) and not em(f) - else: - m = im - else: - if exclude: - m = lambda f: not em(f) - else: - m = lambda f: True - self._always = True + def m(f): + for matchfn in matchfns: + if not matchfn(f): + return False + return True self.matchfn = m self._fmap = set(self._files)
--- a/mercurial/merge.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/merge.py Sat Sep 27 14:47:52 2014 -0500 @@ -10,7 +10,7 @@ from node import nullid, nullrev, hex, bin from i18n import _ from mercurial import obsolete -import error, util, filemerge, copies, subrepo, worker, dicthelpers +import error as errormod, util, filemerge, copies, subrepo, worker, dicthelpers import errno, os, shutil _pack = struct.pack @@ -1011,7 +1011,7 @@ # but currently we are only checking the branch tips. try: node = repo.branchtip(wc.branch()) - except error.RepoLookupError: + except errormod.RepoLookupError: if wc.branch() == "default": # no default branch! node = repo.lookup("tip") # update to tip else: @@ -1134,6 +1134,7 @@ stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels) if not partial: + repo.dirstate.beginparentchange() repo.setparents(fp1, fp2) recordupdates(repo, actions, branchmerge) # update completed, clear state @@ -1141,6 +1142,7 @@ if not branchmerge: repo.dirstate.setbranch(p2.branch()) + repo.dirstate.endparentchange() finally: wlock.release()
--- a/mercurial/obsolete.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/obsolete.py Sat Sep 27 14:47:52 2014 -0500 @@ -99,11 +99,11 @@ _enabled = False # data used for parsing and writing -_fmversion = 0 -_fmfixed = '>BIB20s' -_fmnode = '20s' -_fmfsize = struct.calcsize(_fmfixed) -_fnodesize = struct.calcsize(_fmnode) +_fm0version = 0 +_fm0fixed = '>BIB20s' +_fm0node = '20s' +_fm0fsize = struct.calcsize(_fm0fixed) +_fm0fnodesize = struct.calcsize(_fm0node) ### obsolescence marker flag @@ -142,23 +142,34 @@ off = 0 diskversion = _unpack('>B', data[off:off + 1])[0] off += 1 - if diskversion != _fmversion: + if diskversion not in formats: raise util.Abort(_('parsing obsolete marker: unknown version %r') % diskversion) + return diskversion, formats[diskversion][0](data, off) +def encodemarkers(markers, addheader=False, version=_fm0version): + # Kept separate from flushmarkers(), it will be reused for + # markers exchange. + encodeone = formats[version][1] + if addheader: + yield _pack('>B', _fm0version) + for marker in markers: + yield encodeone(marker) + +def _fm0readmarkers(data, off=0): # Loop on markers l = len(data) - while off + _fmfsize <= l: + while off + _fm0fsize <= l: # read fixed part - cur = data[off:off + _fmfsize] - off += _fmfsize - nbsuc, mdsize, flags, pre = _unpack(_fmfixed, cur) + cur = data[off:off + _fm0fsize] + off += _fm0fsize + nbsuc, mdsize, flags, pre = _unpack(_fm0fixed, cur) # read replacement sucs = () if nbsuc: - s = (_fnodesize * nbsuc) + s = (_fm0fnodesize * nbsuc) cur = data[off:off + s] - sucs = _unpack(_fmnode * nbsuc, cur) + sucs = _unpack(_fm0node * nbsuc, cur) off += s # read metadata # (metadata will be decoded on demand) @@ -168,7 +179,55 @@ 'short, %d bytes expected, got %d') % (mdsize, len(metadata))) off += mdsize - yield (pre, sucs, flags, metadata) + meta = decodemeta(metadata) + try: + when, offset = meta.pop('date', '0 0').split(' ') + date = float(when), int(offset) + except ValueError: + date = (0., 0) + parents = None + if 'p2' in meta: + parents = (meta.pop('p1', None), meta.pop('p2', None)) + elif 'p1' in meta: + parents = (meta.pop('p1', None),) + elif 'p0' in meta: + parents = () + if parents is not None: + try: + parents = tuple(node.bin(p) for p in parents) + # if parent content is not a nodeid, drop the data + for p in parents: + if len(p) != 20: + parents = None + break + except TypeError: + # if content cannot be translated to nodeid drop the data. + parents = None + + metadata = encodemeta(meta) + + yield (pre, sucs, flags, metadata, date, parents) + +def _fm0encodeonemarker(marker): + pre, sucs, flags, metadata, date, parents = marker + metadata = decodemeta(metadata) + metadata['date'] = '%d %i' % date + if parents is not None: + if not parents: + # mark that we explicitly recorded no parents + metadata['p0'] = '' + for i, p in enumerate(parents): + metadata['p%i' % (i + 1)] = node.hex(p) + metadata = encodemeta(metadata) + nbsuc = len(sucs) + format = _fm0fixed + (_fm0node * nbsuc) + data = [nbsuc, len(metadata), flags, pre] + data.extend(sucs) + return _pack(format, *data) + metadata + +# mapping to read/write various marker formats +# <version> -> (decoder, encoder) +formats = {0: (_fm0readmarkers, _fm0encodeonemarker)} def encodemeta(meta): """Return encoded metadata string to string mapping. @@ -215,6 +274,10 @@ """List of successor changesets node identifiers""" return self._data[1] + def parentnodes(self): + """Parents of the precursors (None if not recorded)""" + return self._data[5] + def metadata(self): """Decoded metadata dictionary""" if self._decodedmeta is None: @@ -223,8 +286,11 @@ def date(self): """Creation date as (unixtime, offset)""" - parts = self.metadata()['date'].split(' ') - return (float(parts[0]), int(parts[1])) + return self._data[4] + + def flags(self): + """The flags field of the marker""" + return self._data[2] class obsstore(object): """Store obsolete markers @@ -232,19 +298,31 @@ Markers can be accessed with two mappings: - precursors[x] -> set(markers on precursors edges of x) - successors[x] -> set(markers on successors edges of x) + - children[x] -> set(markers on precursors edges of children(x) """ + fields = ('prec', 'succs', 'flag', 'meta', 'date', 'parents') + # prec: nodeid, precursor changesets + # succs: tuple of nodeid, successor changesets (0-N length) + # flag: integer, flag field carrying modifier for the markers (see doc) + # meta: binary blob, encoded metadata dictionary + # date: (float, int) tuple, date of marker creation + # parents: (tuple of nodeid) or None, parents of precursors + # None is used when no data has been recorded + def __init__(self, sopener): # caches for various obsolescence related cache self.caches = {} self._all = [] - # new markers to serialize self.precursors = {} self.successors = {} + self.children = {} self.sopener = sopener data = sopener.tryread('obsstore') + self._version = _fm0version if data: - self._load(_readmarkers(data)) + self._version, markers = _readmarkers(data) + self._load(markers) def __iter__(self): return iter(self._all) @@ -255,7 +333,8 @@ def __nonzero__(self): return bool(self._all) - def create(self, transaction, prec, succs=(), flag=0, metadata=None): + def create(self, transaction, prec, succs=(), flag=0, parents=None, + date=None, metadata=None): """obsolete: add a new obsolete marker * ensuring it is hashable @@ -270,8 +349,12 @@ """ if metadata is None: metadata = {} - if 'date' not in metadata: - metadata['date'] = "%d %d" % util.makedate() + if date is None: + if 'date' in metadata: + # as a courtesy for out-of-tree extensions + date = util.parsedate(metadata.pop('date')) + else: + date = util.makedate() if len(prec) != 20: raise ValueError(prec) for succ in succs: @@ -279,7 +362,8 @@ raise ValueError(succ) if prec in succs: raise ValueError(_('in-marker cycle with %s') % node.hex(prec)) - marker = (str(prec), tuple(succs), int(flag), encodemeta(metadata)) + marker = (str(prec), tuple(succs), int(flag), encodemeta(metadata), + date, parents) return bool(self.add(transaction, [marker])) def add(self, transaction, markers): @@ -307,7 +391,7 @@ offset = f.tell() transaction.add('obsstore', offset) # offset == 0: new file - add the version header - for bytes in _encodemarkers(new, offset == 0): + for bytes in encodemarkers(new, offset == 0, self._version): f.write(bytes) finally: # XXX: f.close() == filecache invalidation == obsstore rebuilt. @@ -316,11 +400,17 @@ self._load(new) # new marker *may* have changed several set. invalidate the cache. self.caches.clear() + # records the number of new markers for the transaction hooks + previous = int(transaction.hookargs.get('new_obsmarkers', '0')) + transaction.hookargs['new_obsmarkers'] = str(previous + len(new)) return len(new) def mergemarkers(self, transaction, data): - markers = _readmarkers(data) - self.add(transaction, markers) + """merge a binary stream of markers inside the obsstore + + Returns the number of new markers added.""" + version, markers = _readmarkers(data) + return self.add(transaction, markers) def _load(self, markers): for mark in markers: @@ -329,26 +419,53 @@ self.successors.setdefault(pre, set()).add(mark) for suc in sucs: self.precursors.setdefault(suc, set()).add(mark) + parents = mark[5] + if parents is not None: + for p in parents: + self.children.setdefault(p, set()).add(mark) if node.nullid in self.precursors: raise util.Abort(_('bad obsolescence marker detected: ' 'invalid successors nullid')) + def relevantmarkers(self, nodes): + """return a set of all obsolescence markers relevant to a set of nodes. -def _encodemarkers(markers, addheader=False): - # Kept separate from flushmarkers(), it will be reused for - # markers exchange. - if addheader: - yield _pack('>B', _fmversion) - for marker in markers: - yield _encodeonemarker(marker) + "relevant" to a set of nodes mean: + + - marker that use this changeset as successor + - prune marker of direct children on this changeset + - recursive application of the two rules on precursors of these markers + + It is a set so you cannot rely on order.""" + pendingnodes = set(nodes) + seenmarkers = set() + seennodes = set(pendingnodes) + precursorsmarkers = self.precursors + children = self.children + while pendingnodes: + direct = set() + for current in pendingnodes: + direct.update(precursorsmarkers.get(current, ())) + pruned = [m for m in children.get(current, ()) if not m[1]] + direct.update(pruned) + direct -= seenmarkers + pendingnodes = set([m[0] for m in direct]) + seenmarkers |= direct + pendingnodes -= seennodes + seennodes |= pendingnodes + return seenmarkers -def _encodeonemarker(marker): - pre, sucs, flags, metadata = marker - nbsuc = len(sucs) - format = _fmfixed + (_fmnode * nbsuc) - data = [nbsuc, len(metadata), flags, pre] - data.extend(sucs) - return _pack(format, *data) + metadata +def commonversion(versions): + """Return the newest version listed in both versions and our local formats. + + Returns None if no common version exists. + """ + versions.sort(reverse=True) + # search for highest version known on both side + for v in versions: + if v in formats: + return v + return None # arbitrary picked to fit into 8K limit from HTTP server # you have to take in account: @@ -365,7 +482,7 @@ parts = [] currentlen = _maxpayload * 2 # ensure we create a new part for marker in markers: - nextdata = _encodeonemarker(marker) + nextdata = _fm0encodeonemarker(marker) if (len(nextdata) + currentlen > _maxpayload): currentpart = [] currentlen = 0 @@ -373,7 +490,7 @@ currentpart.append(nextdata) currentlen += len(nextdata) for idx, part in enumerate(reversed(parts)): - data = ''.join([_pack('>B', _fmversion)] + part) + data = ''.join([_pack('>B', _fm0version)] + part) keys['dump%i' % idx] = base85.b85encode(data) return keys @@ -404,11 +521,25 @@ finally: lock.release() -def allmarkers(repo): - """all obsolete markers known in a repository""" - for markerdata in repo.obsstore: +def getmarkers(repo, nodes=None): + """returns markers known in a repository + + If <nodes> is specified, only markers "relevant" to those nodes are are + returned""" + if nodes is None: + rawmarkers = repo.obsstore + else: + rawmarkers = repo.obsstore.relevantmarkers(nodes) + + for markerdata in rawmarkers: yield marker(repo, markerdata) +def relevantmarkers(repo, node): + """all obsolete markers relevant to some revision""" + for markerdata in repo.obsstore.relevantmarkers(node): + yield marker(repo, markerdata) + + def precursormarkers(ctx): """obsolete marker marking this changeset as a successors""" for data in ctx._repo.obsstore.precursors.get(ctx.node(), ()): @@ -721,7 +852,7 @@ Such access may compute the set and cache it for future use""" repo = repo.unfiltered() if not repo.obsstore: - return () + return frozenset() if name not in repo.obsstore.caches: repo.obsstore.caches[name] = cachefuncs[name](repo) return repo.obsstore.caches[name] @@ -750,8 +881,8 @@ obs = set() getrev = repo.changelog.nodemap.get getphase = repo._phasecache.phase - for node in repo.obsstore.successors: - rev = getrev(node) + for n in repo.obsstore.successors: + rev = getrev(n) if rev is not None and getphase(repo, rev): obs.add(rev) return obs @@ -825,7 +956,7 @@ return divergent -def createmarkers(repo, relations, flag=0, metadata=None): +def createmarkers(repo, relations, flag=0, date=None, metadata=None): """Add obsolete markers between changesets in a repo <relations> must be an iterable of (<old>, (<new>, ...)[,{metadata}]) @@ -844,8 +975,6 @@ # prepare metadata if metadata is None: metadata = {} - if 'date' not in metadata: - metadata['date'] = '%i %i' % util.makedate() if 'user' not in metadata: metadata['user'] = repo.ui.username() tr = repo.transaction('add-obsolescence-marker') @@ -862,9 +991,13 @@ % prec) nprec = prec.node() nsucs = tuple(s.node() for s in sucs) + npare = None + if not nsucs: + npare = tuple(p.node() for p in prec.parents()) if nprec in nsucs: raise util.Abort("changeset %s cannot obsolete itself" % prec) - repo.obsstore.create(tr, nprec, nsucs, flag, localmetadata) + repo.obsstore.create(tr, nprec, nsucs, flag, parents=npare, + date=date, metadata=localmetadata) repo.filteredrevcache.clear() tr.close() finally:
--- a/mercurial/parsers.c Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/parsers.c Sat Sep 27 14:47:52 2014 -0500 @@ -275,15 +275,20 @@ PyObject *fname = NULL, *cname = NULL, *entry = NULL; char state, *cur, *str, *cpos; int mode, size, mtime; - unsigned int flen; - int len, pos = 40; + unsigned int flen, len, pos = 40; + int readlen; if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate", &PyDict_Type, &dmap, &PyDict_Type, &cmap, - &str, &len)) + &str, &readlen)) goto quit; + if (readlen < 0) + goto quit; + + len = readlen; + /* read parents */ if (len < 40) goto quit; @@ -503,6 +508,7 @@ Py_ssize_t length; /* current number of elements */ PyObject *added; /* populated on demand */ PyObject *headrevs; /* cache, invalidated on changes */ + PyObject *filteredrevs;/* filtered revs set */ nodetree *nt; /* base-16 trie */ int ntlength; /* # nodes in use */ int ntcapacity; /* # nodes allocated */ @@ -524,7 +530,7 @@ static PyObject *nullentry; static const char nullid[20]; -static long inline_scan(indexObject *self, const char **offsets); +static Py_ssize_t inline_scan(indexObject *self, const char **offsets); #if LONG_MAX == 0x7fffffffL static char *tuple_format = "Kiiiiiis#"; @@ -681,10 +687,9 @@ { PyObject *obj; char *node; - long offset; - Py_ssize_t len, nodelen; + Py_ssize_t offset, len, nodelen; - if (!PyArg_ParseTuple(args, "lO", &offset, &obj)) + if (!PyArg_ParseTuple(args, "nO", &offset, &obj)) return NULL; if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) { @@ -819,14 +824,59 @@ return newlist; } -static PyObject *index_headrevs(indexObject *self) +static int check_filter(PyObject *filter, Py_ssize_t arg) { + if (filter) { + PyObject *arglist, *result; + int isfiltered; + + arglist = Py_BuildValue("(n)", arg); + if (!arglist) { + return -1; + } + + result = PyEval_CallObject(filter, arglist); + Py_DECREF(arglist); + if (!result) { + return -1; + } + + /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error, + * same as this function, so we can just return it directly.*/ + isfiltered = PyObject_IsTrue(result); + Py_DECREF(result); + return isfiltered; + } else { + return 0; + } +} + +static PyObject *index_headrevs(indexObject *self, PyObject *args) { Py_ssize_t i, len, addlen; char *nothead = NULL; - PyObject *heads; + PyObject *heads = NULL; + PyObject *filter = NULL; + PyObject *filteredrevs = Py_None; + + if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) { + return NULL; + } + + if (self->headrevs && filteredrevs == self->filteredrevs) + return list_copy(self->headrevs); - if (self->headrevs) - return list_copy(self->headrevs); + Py_DECREF(self->filteredrevs); + self->filteredrevs = filteredrevs; + Py_INCREF(filteredrevs); + + if (filteredrevs != Py_None) { + filter = PyObject_GetAttrString(filteredrevs, "__contains__"); + if (!filter) { + PyErr_SetString(PyExc_TypeError, + "filteredrevs has no attribute __contains__"); + goto bail; + } + } len = index_length(self) - 1; heads = PyList_New(0); @@ -846,9 +896,25 @@ goto bail; for (i = 0; i < self->raw_length; i++) { - const char *data = index_deref(self, i); - int parent_1 = getbe32(data + 24); - int parent_2 = getbe32(data + 28); + const char *data; + int parent_1, parent_2, isfiltered; + + isfiltered = check_filter(filter, i); + if (isfiltered == -1) { + PyErr_SetString(PyExc_TypeError, + "unable to check filter"); + goto bail; + } + + if (isfiltered) { + nothead[i] = 1; + 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) @@ -862,12 +928,26 @@ 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; } + + 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) @@ -881,7 +961,7 @@ if (nothead[i]) continue; - head = PyInt_FromLong(i); + head = PyInt_FromSsize_t(i); if (head == NULL || PyList_Append(heads, head) == -1) { Py_XDECREF(head); goto bail; @@ -890,9 +970,11 @@ done: self->headrevs = heads; + Py_XDECREF(filter); free(nothead); return list_copy(self->headrevs); bail: + Py_XDECREF(filter); Py_XDECREF(heads); free(nothead); return NULL; @@ -1304,7 +1386,7 @@ PyObject *gca = PyList_New(0); int i, v, interesting; int maxrev = -1; - long sp; + bitmask sp; bitmask *seen; if (gca == NULL) @@ -1327,7 +1409,7 @@ interesting = revcount; for (v = maxrev; v >= 0 && interesting; v--) { - long sv = seen[v]; + bitmask sv = seen[v]; int parents[2]; if (!sv) @@ -1853,7 +1935,7 @@ * Find all RevlogNG entries in an index that has inline data. Update * the optional "offsets" table with those entries. */ -static long inline_scan(indexObject *self, const char **offsets) +static Py_ssize_t inline_scan(indexObject *self, const char **offsets) { const char *data = PyString_AS_STRING(self->data); Py_ssize_t pos = 0; @@ -1892,6 +1974,8 @@ self->cache = NULL; self->data = NULL; self->headrevs = NULL; + self->filteredrevs = Py_None; + Py_INCREF(Py_None); self->nt = NULL; self->offsets = NULL; @@ -1913,7 +1997,7 @@ Py_INCREF(self->data); if (self->inlined) { - long len = inline_scan(self, NULL); + Py_ssize_t len = inline_scan(self, NULL); if (len == -1) goto bail; self->raw_length = len; @@ -1941,6 +2025,7 @@ static void index_dealloc(indexObject *self) { _index_clearcaches(self); + Py_XDECREF(self->filteredrevs); Py_XDECREF(self->data); Py_XDECREF(self->added); PyObject_Del(self); @@ -1973,7 +2058,7 @@ "clear the index caches"}, {"get", (PyCFunction)index_m_get, METH_VARARGS, "get an index entry"}, - {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS, + {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS, "get head revisions"}, {"insert", (PyCFunction)index_insert, METH_VARARGS, "insert an index entry"},
--- a/mercurial/patch.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/patch.py Sat Sep 27 14:47:52 2014 -0500 @@ -18,6 +18,7 @@ import base85, mdiff, scmutil, util, diffhelpers, copies, encoding, error gitre = re.compile('diff --git a/(.*) b/(.*)') +tabsplitter = re.compile(r'(\t+|[^\t]+)') class PatchError(Exception): pass @@ -382,7 +383,7 @@ def getfile(self, fname): """Return target file data and flags as a (data, (islink, - isexec)) tuple. + isexec)) tuple. Data is None if file is missing/deleted. """ raise NotImplementedError @@ -426,7 +427,12 @@ except OSError, e: if e.errno != errno.ENOENT: raise - return (self.opener.read(fname), (False, isexec)) + try: + return (self.opener.read(fname), (False, isexec)) + except IOError, e: + if e.errno != errno.ENOENT: + raise + return None, None def setfile(self, fname, data, mode, copysource): islink, isexec = mode @@ -528,7 +534,7 @@ if fname in self.data: return self.data[fname] if not self.opener or fname not in self.files: - raise IOError + return None, None, None fn, mode, copied = self.files[fname] return self.opener.read(fn), mode, copied @@ -554,7 +560,7 @@ try: fctx = self.ctx[fname] except error.LookupError: - raise IOError + return None, None flags = fctx.flags() return fctx.data(), ('l' in flags, 'x' in flags) @@ -597,13 +603,12 @@ self.copysource = gp.oldpath self.create = gp.op in ('ADD', 'COPY', 'RENAME') self.remove = gp.op == 'DELETE' - try: - if self.copysource is None: - data, mode = backend.getfile(self.fname) - self.exists = True - else: - data, mode = store.getfile(self.copysource)[:2] - self.exists = backend.exists(self.fname) + if self.copysource is None: + data, mode = backend.getfile(self.fname) + else: + data, mode = store.getfile(self.copysource)[:2] + if data is not None: + self.exists = self.copysource is None or backend.exists(self.fname) self.missing = False if data: self.lines = mdiff.splitnewlines(data) @@ -622,7 +627,7 @@ l = l[:-2] + '\n' nlines.append(l) self.lines = nlines - except IOError: + else: if self.create: self.missing = False if self.mode is None: @@ -1380,6 +1385,8 @@ data, mode = None, None if gp.op in ('RENAME', 'COPY'): data, mode = store.getfile(gp.oldpath)[:2] + # FIXME: failing getfile has never been handled here + assert data is not None if gp.mode: mode = gp.mode if gp.op == 'ADD': @@ -1404,15 +1411,13 @@ elif state == 'git': for gp in values: path = pstrip(gp.oldpath) - try: - data, mode = backend.getfile(path) - except IOError, e: - if e.errno != errno.ENOENT: - raise + data, mode = backend.getfile(path) + if data is None: # The error ignored here will trigger a getfile() # error in a place more appropriate for error # handling, and will not interrupt the patching # process. + pass else: store.setfile(path, data, mode) else: @@ -1669,15 +1674,26 @@ if line and line[0] not in ' +-@\\': head = True stripline = line + diffline = False if not head and line and line[0] in '+-': - # highlight trailing whitespace, but only in changed lines + # highlight tabs and trailing whitespace, but only in + # changed lines stripline = line.rstrip() + diffline = True + prefixes = textprefixes if head: prefixes = headprefixes for prefix, label in prefixes: if stripline.startswith(prefix): - yield (stripline, label) + if diffline: + for token in tabsplitter.findall(stripline): + if '\t' == token[0]: + yield (token, 'diff.tab') + else: + yield (token, label) + else: + yield (stripline, label) break else: yield (line, '')
--- a/mercurial/phases.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/phases.py Sat Sep 27 14:47:52 2014 -0500 @@ -196,19 +196,24 @@ return f = self.opener('phaseroots', 'w', atomictemp=True) try: - for phase, roots in enumerate(self.phaseroots): - for h in roots: - f.write('%i %s\n' % (phase, hex(h))) + self._write(f) finally: f.close() + + def _write(self, fp): + for phase, roots in enumerate(self.phaseroots): + for h in roots: + fp.write('%i %s\n' % (phase, hex(h))) self.dirty = False - def _updateroots(self, phase, newroots): + def _updateroots(self, phase, newroots, tr): self.phaseroots[phase] = newroots self._phaserevs = None self.dirty = True - def advanceboundary(self, repo, targetphase, nodes): + tr.addfilegenerator('phase', ('phaseroots',), self._write) + + def advanceboundary(self, repo, tr, targetphase, nodes): # Be careful to preserve shallow-copied values: do not update # phaseroots values, replace them. @@ -224,15 +229,15 @@ roots = set(ctx.node() for ctx in repo.set( 'roots((%ln::) - (%ln::%ln))', olds, olds, nodes)) if olds != roots: - self._updateroots(phase, roots) + self._updateroots(phase, roots, tr) # some roots may need to be declared for lower phases delroots.extend(olds - roots) # declare deleted root in the target phase if targetphase != 0: - self.retractboundary(repo, targetphase, delroots) + self.retractboundary(repo, tr, targetphase, delroots) repo.invalidatevolatilesets() - def retractboundary(self, repo, targetphase, nodes): + def retractboundary(self, repo, tr, targetphase, nodes): # Be careful to preserve shallow-copied values: do not update # phaseroots values, replace them. @@ -247,7 +252,7 @@ currentroots.update(newroots) ctxs = repo.set('roots(%ln::)', currentroots) currentroots.intersection_update(ctx.node() for ctx in ctxs) - self._updateroots(targetphase, currentroots) + self._updateroots(targetphase, currentroots, tr) repo.invalidatevolatilesets() def filterunknown(self, repo): @@ -278,7 +283,7 @@ # (see branchmap one) self._phaserevs = None -def advanceboundary(repo, targetphase, nodes): +def advanceboundary(repo, tr, targetphase, nodes): """Add nodes to a phase changing other nodes phases if necessary. This function move boundary *forward* this means that all nodes @@ -286,10 +291,10 @@ Simplify boundary to contains phase roots only.""" phcache = repo._phasecache.copy() - phcache.advanceboundary(repo, targetphase, nodes) + phcache.advanceboundary(repo, tr, targetphase, nodes) repo._phasecache.replace(phcache) -def retractboundary(repo, targetphase, nodes): +def retractboundary(repo, tr, targetphase, nodes): """Set nodes back to a phase changing other nodes phases if necessary. @@ -298,7 +303,7 @@ Simplify boundary to contains phase roots only.""" phcache = repo._phasecache.copy() - phcache.retractboundary(repo, targetphase, nodes) + phcache.retractboundary(repo, tr, targetphase, nodes) repo._phasecache.replace(phcache) def listphases(repo): @@ -331,13 +336,16 @@ def pushphase(repo, nhex, oldphasestr, newphasestr): """List phases root for serialization over pushkey""" repo = repo.unfiltered() + tr = None lock = repo.lock() try: currentphase = repo[nhex].phase() newphase = abs(int(newphasestr)) # let's avoid negative index surprise oldphase = abs(int(oldphasestr)) # let's avoid negative index surprise if currentphase == oldphase and newphase < oldphase: - advanceboundary(repo, newphase, [bin(nhex)]) + tr = repo.transaction('pushkey-phase') + advanceboundary(repo, tr, newphase, [bin(nhex)]) + tr.close() return 1 elif currentphase == newphase: # raced, but got correct result @@ -345,6 +353,8 @@ else: return 0 finally: + if tr: + tr.release() lock.release() def analyzeremotephases(repo, subset, roots):
--- a/mercurial/posix.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/posix.py Sat Sep 27 14:47:52 2014 -0500 @@ -8,6 +8,7 @@ from i18n import _ import encoding import os, sys, errno, stat, getpass, pwd, grp, socket, tempfile, unicodedata +import fcntl posixfile = open normpath = os.path.normpath @@ -432,7 +433,7 @@ def termwidth(): try: - import termios, array, fcntl + import termios, array for dev in (sys.stderr, sys.stdout, sys.stdin): try: try: @@ -567,3 +568,27 @@ def statisexec(st): '''check whether a stat result is an executable file''' return st and (st.st_mode & 0100 != 0) + +def readpipe(pipe): + """Read all available data from a pipe.""" + # We can't fstat() a pipe because Linux will always report 0. + # So, we set the pipe to non-blocking mode and read everything + # that's available. + flags = fcntl.fcntl(pipe, fcntl.F_GETFL) + flags |= os.O_NONBLOCK + oldflags = fcntl.fcntl(pipe, fcntl.F_SETFL, flags) + + try: + chunks = [] + while True: + try: + s = pipe.read() + if not s: + break + chunks.append(s) + except IOError: + break + + return ''.join(chunks) + finally: + fcntl.fcntl(pipe, fcntl.F_SETFL, oldflags)
--- a/mercurial/repair.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/repair.py Sat Sep 27 14:47:52 2014 -0500 @@ -47,7 +47,13 @@ return s -def strip(ui, repo, nodelist, backup="all", topic='backup'): +def strip(ui, repo, nodelist, backup=True, topic='backup'): + + # Simple way to maintain backwards compatibility for this + # argument. + if backup in ['none', 'strip']: + backup = False + repo = repo.unfiltered() repo.destroying() @@ -58,8 +64,6 @@ striplist = [cl.rev(node) for node in nodelist] striprev = min(striplist) - keeppartialbundle = backup == 'strip' - # Some revisions with rev > striprev may not be descendants of striprev. # We have to find these revisions and put them in a bundle, so that # we can restore them after the truncations. @@ -109,7 +113,7 @@ # create a changegroup for all the branches we need to keep backupfile = None vfs = repo.vfs - if backup == "all": + if backup: backupfile = _bundle(repo, stripbases, cl.heads(), node, topic) repo.ui.status(_("saved backup bundle to %s\n") % vfs.join(backupfile)) @@ -118,7 +122,7 @@ if saveheads or savebases: # do not compress partial bundle if we remove it from disk later chgrpfile = _bundle(repo, savebases, saveheads, node, 'temp', - compress=keeppartialbundle) + compress=False) mfst = repo.manifest @@ -156,8 +160,6 @@ if not repo.ui.verbose: repo.ui.popbuffer() f.close() - if not keeppartialbundle: - vfs.unlink(chgrpfile) # remove undo files for undovfs, undofile in repo.undofiles(): @@ -179,5 +181,9 @@ ui.warn(_("strip failed, partial bundle stored in '%s'\n") % vfs.join(chgrpfile)) raise + else: + if saveheads or savebases: + # Remove partial backup only if there were no exceptions + vfs.unlink(chgrpfile) repo.destroyed()
--- a/mercurial/repoview.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/repoview.py Sat Sep 27 14:47:52 2014 -0500 @@ -7,11 +7,13 @@ # GNU General Public License version 2 or any later version. import copy +import error import phases import util import obsolete +import struct import tags as tagsmod - +from mercurial.i18n import _ def hideablerevs(repo): """Revisions candidates to be hidden @@ -19,13 +21,14 @@ This is a standalone function to help extensions to wrap it.""" return obsolete.getrevs(repo, 'obsolete') -def _gethiddenblockers(repo): - """Get revisions that will block hidden changesets from being filtered +def _getstaticblockers(repo): + """Cacheable revisions blocking hidden changesets from being filtered. + Additional non-cached hidden blockers are computed in _getdynamicblockers. This is a standalone function to help extensions to wrap it.""" assert not repo.changelog.filteredrevs hideable = hideablerevs(repo) - blockers = [] + blockers = set() if hideable: # We use cl to avoid recursive lookup from repo[xxx] cl = repo.changelog @@ -33,29 +36,124 @@ revs = cl.revs(start=firsthideable) tofilter = repo.revs( '(%ld) and children(%ld)', list(revs), list(hideable)) - blockers = [r for r in tofilter if r not in hideable] - for par in repo[None].parents(): - blockers.append(par.rev()) - for bm in repo._bookmarks.values(): - blockers.append(cl.rev(bm)) - tags = {} - tagsmod.readlocaltags(repo.ui, repo, tags, {}) - if tags: - rev, nodemap = cl.rev, cl.nodemap - blockers.extend(rev(t[0]) for t in tags.values() if t[0] in nodemap) + blockers.update([r for r in tofilter if r not in hideable]) + return blockers + +def _getdynamicblockers(repo): + """Non-cacheable revisions blocking hidden changesets from being filtered. + + Get revisions that will block hidden changesets and are likely to change, + but unlikely to create hidden blockers. They won't be cached, so be careful + with adding additional computation.""" + + cl = repo.changelog + blockers = set() + blockers.update([par.rev() for par in repo[None].parents()]) + blockers.update([cl.rev(bm) for bm in repo._bookmarks.values()]) + + tags = {} + tagsmod.readlocaltags(repo.ui, repo, tags, {}) + if tags: + rev, nodemap = cl.rev, cl.nodemap + blockers.update(rev(t[0]) for t in tags.values() if t[0] in nodemap) return blockers +cacheversion = 1 +cachefile = 'cache/hidden' + +def cachehash(repo, hideable): + """return sha1 hash of repository data to identify a valid cache. + + We calculate a sha1 of repo heads and the content of the obsstore and write + it to the cache. Upon reading we can easily validate by checking the hash + against the stored one and discard the cache in case the hashes don't match. + """ + h = util.sha1() + h.update(''.join(repo.heads())) + h.update(str(hash(frozenset(hideable)))) + return h.digest() + +def trywritehiddencache(repo, hideable, hidden): + """write cache of hidden changesets to disk + + Will not write the cache if a wlock cannot be obtained lazily. + The cache consists of a head of 22byte: + 2 byte version number of the cache + 20 byte sha1 to validate the cache + n*4 byte hidden revs + """ + wlock = fh = None + try: + try: + wlock = repo.wlock(wait=False) + # write cache to file + newhash = cachehash(repo, hideable) + sortedset = sorted(hidden) + data = struct.pack('>%ii' % len(sortedset), *sortedset) + fh = repo.vfs.open(cachefile, 'w+b', atomictemp=True) + fh.write(struct.pack(">H", cacheversion)) + fh.write(newhash) + fh.write(data) + 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() + if wlock: + wlock.release() + +def tryreadcache(repo, hideable): + """read a cache if the cache exists and is valid, otherwise returns None.""" + hidden = fh = None + try: + if repo.vfs.exists(cachefile): + fh = repo.vfs.open(cachefile, 'rb') + version, = struct.unpack(">H", fh.read(2)) + oldhash = fh.read(20) + newhash = cachehash(repo, hideable) + if (cacheversion, oldhash) == (version, newhash): + # cache is valid, so we can start reading the hidden revs + data = fh.read() + count = len(data) / 4 + hidden = frozenset(struct.unpack('>%ii' % count, data)) + return hidden + finally: + if fh: + fh.close() + def computehidden(repo): """compute the set of hidden revision to filter During most operation hidden should be filtered.""" assert not repo.changelog.filteredrevs + + hidden = frozenset() hideable = hideablerevs(repo) if hideable: cl = repo.changelog - blocked = cl.ancestors(_gethiddenblockers(repo), inclusive=True) - return frozenset(r for r in hideable if r not in blocked) - return frozenset() + hidden = tryreadcache(repo, hideable) + if hidden is None: + blocked = cl.ancestors(_getstaticblockers(repo), inclusive=True) + hidden = frozenset(r for r in hideable if r not in blocked) + trywritehiddencache(repo, hideable, hidden) + elif repo.ui.configbool('experimental', 'verifyhiddencache', True): + blocked = cl.ancestors(_getstaticblockers(repo), inclusive=True) + computed = frozenset(r for r in hideable if r not in blocked) + if computed != hidden: + trywritehiddencache(repo, hideable, computed) + repo.ui.warn(_('Cache inconsistency detected. Please ' + + 'open an issue on http://bz.selenic.com.\n')) + hidden = computed + + # check if we have wd parents, bookmarks or tags pointing to hidden + # changesets and remove those. + dynamic = hidden & _getdynamicblockers(repo) + if dynamic: + blocked = cl.ancestors(dynamic, inclusive=True) + hidden = frozenset(r for r in hidden if r not in blocked) + return hidden def computeunserved(repo): """compute the set of revision that should be filtered when used a server
--- a/mercurial/revlog.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/revlog.py Sat Sep 27 14:47:52 2014 -0500 @@ -306,6 +306,8 @@ def rev(self, node): try: return self._nodecache[node] + except TypeError: + raise except RevlogError: # parsers.c radix tree lookup failed raise LookupError(node, self.indexfile, _('no node')) @@ -743,8 +745,15 @@ ancs = ancestor.commonancestorsheads(self.parentrevs, a, b) return map(self.node, ancs) + def isancestor(self, a, b): + """return True if node a is an ancestor of node b + + The implementation of this is trivial but the use of + commonancestorsheads is not.""" + return a in self.commonancestorsheads(a, b) + def ancestor(self, a, b): - """calculate the least common ancestor of nodes a and b""" + """calculate the "best" common ancestor of nodes a and b""" a, b = self.rev(a), self.rev(b) try:
--- a/mercurial/revset.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/revset.py Sat Sep 27 14:47:52 2014 -0500 @@ -78,7 +78,7 @@ if not roots: return baseset([]) parentrevs = repo.changelog.parentrevs - visit = baseset(heads) + visit = list(heads) reachable = set() seen = {} minroot = min(roots) @@ -376,7 +376,7 @@ for i in range(n): r = cl.parentrevs(r)[0] ps.add(r) - return subset.filter(ps.__contains__) + return subset & ps def author(repo, subset, x): """``author(string)`` @@ -426,7 +426,7 @@ # i18n: "bisect" is a keyword status = getstring(x, _("bisect requires a string")).lower() state = set(hbisect.get(repo, status)) - return subset.filter(state.__contains__) + return subset & state # Backward-compatibility # - no help entry so that we do not advertise it any more @@ -448,12 +448,12 @@ # i18n: "bookmark" is a keyword _('the argument to bookmark must be a string')) kind, pattern, matcher = _stringmatcher(bm) + bms = set() if kind == 'literal': bmrev = repo._bookmarks.get(pattern, None) if not bmrev: raise util.Abort(_("bookmark '%s' does not exist") % bm) - bmrev = repo[bmrev].rev() - return subset.filter(lambda r: r == bmrev) + bms.add(repo[bmrev].rev()) else: matchrevs = set() for name, bmrev in repo._bookmarks.iteritems(): @@ -462,14 +462,13 @@ if not matchrevs: raise util.Abort(_("no bookmarks exist that match '%s'") % pattern) - bmrevs = set() for bmrev in matchrevs: - bmrevs.add(repo[bmrev].rev()) - return subset & bmrevs - - bms = set([repo[r].rev() - for r in repo._bookmarks.values()]) - return subset.filter(bms.__contains__) + bms.add(repo[bmrev].rev()) + else: + bms = set([repo[r].rev() + for r in repo._bookmarks.values()]) + bms -= set([node.nullrev]) + return subset & bms def branch(repo, subset, x): """``branch(string or set)`` @@ -666,10 +665,8 @@ # Both sets need to be ascending in order to lazily return the union # in the correct order. args.ascending() - - subsetset = subset.set() - result = (orderedlazyset(s, subsetset.__contains__, ascending=True) + - orderedlazyset(args, subsetset.__contains__, ascending=True)) + result = (orderedlazyset(s, subset.__contains__, ascending=True) + + orderedlazyset(args, subset.__contains__, ascending=True)) # Wrap result in a lazyset since it's an _addset, which doesn't implement # all the necessary functions to be consumed by callers. @@ -737,7 +734,7 @@ # i18n: "divergent" is a keyword getargs(x, 0, 0, _("divergent takes no arguments")) divergent = obsmod.getrevs(repo, 'divergent') - return subset.filter(divergent.__contains__) + return subset & divergent def draft(repo, subset, x): """``draft()`` @@ -814,7 +811,7 @@ for fr in fl: s.add(fl.linkrev(fr)) - return subset.filter(s.__contains__) + return subset & s def first(repo, subset, x): """``first(set, [n])`` @@ -837,7 +834,7 @@ else: s = _revancestors(repo, baseset([c.rev()]), followfirst) - return subset.filter(s.__contains__) + return subset & s def follow(repo, subset, x): """``follow([file])`` @@ -1169,7 +1166,8 @@ src = prev o = set([_firstsrc(r) for r in args]) - return subset.filter(o.__contains__) + o -= set([None]) + return subset & o def outgoing(repo, subset, x): """``outgoing([path])`` @@ -1192,7 +1190,7 @@ repo.ui.popbuffer() cl = repo.changelog o = set([cl.rev(r) for r in outgoing.missing]) - return subset.filter(o.__contains__) + return subset & o def p1(repo, subset, x): """``p1([set])`` @@ -1200,12 +1198,15 @@ """ if x is None: p = repo[x].p1().rev() - return subset.filter(lambda r: r == p) + if p >= 0: + return subset & baseset([p]) + return baseset([]) ps = set() cl = repo.changelog for r in getset(repo, spanset(repo), x): ps.add(cl.parentrevs(r)[0]) + ps -= set([node.nullrev]) return subset & ps def p2(repo, subset, x): @@ -1216,7 +1217,9 @@ ps = repo[x].parents() try: p = ps[1].rev() - return subset.filter(lambda r: r == p) + if p >= 0: + return subset & baseset([p]) + return baseset([]) except IndexError: return baseset([]) @@ -1224,6 +1227,7 @@ cl = repo.changelog for r in getset(repo, spanset(repo), x): ps.add(cl.parentrevs(r)[1]) + ps -= set([node.nullrev]) return subset & ps def parents(repo, subset, x): @@ -1231,14 +1235,14 @@ The set of all parents for all changesets in set, or the working directory. """ if x is None: - ps = tuple(p.rev() for p in repo[x].parents()) - return subset & ps - - ps = set() - cl = repo.changelog - for r in getset(repo, spanset(repo), x): - ps.update(cl.parentrevs(r)) - return subset & ps + ps = set(p.rev() for p in repo[x].parents()) + else: + ps = set() + cl = repo.changelog + for r in getset(repo, spanset(repo), x): + ps.update(cl.parentrevs(r)) + ps -= set([node.nullrev]) + return baseset(ps) & subset def parentspec(repo, subset, x, n): """``set^0`` @@ -1346,7 +1350,7 @@ except (TypeError, ValueError): # i18n: "rev" is a keyword raise error.ParseError(_("rev expects a number")) - return subset.filter(lambda r: r == l) + return subset & baseset([l]) def matching(repo, subset, x): """``matching(revision [, field])`` @@ -1913,7 +1917,7 @@ w = 100 # very slow elif f == "ancestor": w = 1 * smallbonus - elif f in "reverse limit first": + elif f in "reverse limit first _intlist": w = 0 elif f in "sort": w = 10 # assume most sorts look at changelog @@ -2342,7 +2346,8 @@ def __contains__(self, x): c = self._cache if x not in c: - c[x] = x in self._subset and self._condition(x) + v = c[x] = x in self._subset and self._condition(x) + return v return c[x] def __iter__(self): @@ -2654,6 +2659,12 @@ yield x return + # We have to use this complex iteration strategy to allow multiple + # iterations at the same time. We need to be able to catch revision + # removed from `consumegen` and added to genlist in another instance. + # + # Getting rid of it would provide an about 15% speed up on this + # iteration. i = 0 genlist = self._genlist consume = self._consumegen() @@ -2665,9 +2676,11 @@ i += 1 def _consumegen(self): + cache = self._cache + genlist = self._genlist.append for item in self._gen: - self._cache[item] = True - self._genlist.append(item) + cache[item] = True + genlist(item) yield item self._finished = True @@ -2726,7 +2739,18 @@ self._cache[x] = False return False -class spanset(_orderedsetmixin): +def spanset(repo, start=None, end=None): + """factory function to dispatch between fullreposet and actual spanset + + Feel free to update all spanset call sites and kill this function at some + point. + """ + if start is None and end is None: + return fullreposet(repo) + return _spanset(repo, start, end) + + +class _spanset(_orderedsetmixin): """Duck type for baseset class which represents a range of revisions and can work lazily and without having all the range in memory @@ -2753,15 +2777,15 @@ self._hiddenrevs = repo.changelog.filteredrevs def ascending(self): - if self._start > self._end: + if not self.isascending(): self.reverse() def descending(self): - if self._start < self._end: + if not self.isdescending(): self.reverse() def __iter__(self): - if self._start <= self._end: + if self.isascending(): iterrange = xrange(self._start, self._end) else: iterrange = xrange(self._start, self._end, -1) @@ -2776,9 +2800,11 @@ yield r def __contains__(self, rev): - return (((self._end < rev <= self._start) - or (self._start <= rev < self._end)) - and not (self._hiddenrevs and rev in self._hiddenrevs)) + start = self._start + end = self._end + hidden = self._hiddenrevs + return (((end < rev <= start) or (start <= rev and rev < end)) + and not (hidden and rev in hidden)) def __nonzero__(self): for r in self: @@ -2788,18 +2814,14 @@ def __and__(self, x): if isinstance(x, baseset): x = x.set() - if self._start <= self._end: - return orderedlazyset(self, x.__contains__) - else: - return orderedlazyset(self, x.__contains__, ascending=False) + return orderedlazyset(self, x.__contains__, + ascending=self.isascending()) def __sub__(self, x): if isinstance(x, baseset): x = x.set() - if self._start <= self._end: - return orderedlazyset(self, lambda r: r not in x) - else: - return orderedlazyset(self, lambda r: r not in x, ascending=False) + return orderedlazyset(self, lambda r: r not in x, + ascending=self.isascending()) def __add__(self, x): kwargs = {} @@ -2832,7 +2854,7 @@ def reverse(self): # Just switch the _start and _end parameters - if self._start <= self._end: + if self.isascending(): self._start, self._end = self._end - 1, self._start - 1 else: self._start, self._end = self._end + 1, self._start + 1 @@ -2841,16 +2863,53 @@ return self def isascending(self): - return self._start < self._end + return self._start <= self._end def isdescending(self): - return self._start > self._end + return self._start >= self._end def filter(self, l): - if self._start <= self._end: - return orderedlazyset(self, l) + return orderedlazyset(self, l, ascending=self.isascending()) + +class fullreposet(_spanset): + """a set containing all revisions in the repo + + This class exists to host special optimisation. + """ + + def __init__(self, repo): + super(fullreposet, self).__init__(repo) + + def __and__(self, other): + """fullrepo & other -> other + + As self contains the whole repo, all of the other set should also be in + self. Therefor `self & other = other`. + + This boldly assumes the other contains valid revs only. + """ + # other not a smartset, make is so + if not util.safehasattr(other, 'set'): + # filter out hidden revision + # (this boldly assumes all smartset are pure) + # + # `other` was used with "&", let's assume this is a set like + # object. + other = baseset(other - self._hiddenrevs) + elif not util.safehasattr(other, 'ascending'): + # "other" is _generatorset not a real smart set + # we fallback to the old way (sad kitten) + return super(fullreposet, self).__and__(other) + + # preserve order: + # + # this is probably useless and harmful in multiple cases but matches + # the current behavior. + if self.isascending(): + other.ascending() else: - return orderedlazyset(self, l, ascending=False) + other.descending() + return other # tell hggettext to extract docstrings from these functions: i18nfunctions = symbols.values()
--- a/mercurial/simplemerge.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/simplemerge.py Sat Sep 27 14:47:52 2014 -0500 @@ -82,8 +82,7 @@ start_marker='<<<<<<<', mid_marker='=======', end_marker='>>>>>>>', - base_marker=None, - reprocess=False): + base_marker=None): """Return merge in cvs-like form. """ self.conflicts = False @@ -93,8 +92,6 @@ newline = '\r\n' elif self.a[0].endswith('\r'): newline = '\r' - if base_marker and reprocess: - raise CantReprocessAndShowBase if name_a: start_marker = start_marker + ' ' + name_a if name_b: @@ -102,8 +99,6 @@ if name_base and base_marker: base_marker = base_marker + ' ' + name_base merge_regions = self.merge_regions() - if reprocess is True: - merge_regions = self.reprocess_merge_regions(merge_regions) for t in merge_regions: what = t[0] if what == 'unchanged': @@ -131,33 +126,6 @@ else: raise ValueError(what) - def merge_annotated(self): - """Return merge with conflicts, showing origin of lines. - - Most useful for debugging merge. - """ - for t in self.merge_regions(): - what = t[0] - if what == 'unchanged': - for i in range(t[1], t[2]): - yield 'u | ' + self.base[i] - elif what == 'a' or what == 'same': - for i in range(t[1], t[2]): - yield what[0] + ' | ' + self.a[i] - elif what == 'b': - for i in range(t[1], t[2]): - yield 'b | ' + self.b[i] - elif what == 'conflict': - yield '<<<<\n' - for i in range(t[3], t[4]): - yield 'A | ' + self.a[i] - yield '----\n' - for i in range(t[5], t[6]): - yield 'B | ' + self.b[i] - yield '>>>>\n' - else: - raise ValueError(what) - def merge_groups(self): """Yield sequence of line groups. Each one is a tuple: @@ -278,42 +246,6 @@ ia = aend ib = bend - def reprocess_merge_regions(self, merge_regions): - """Where there are conflict regions, remove the agreed lines. - - Lines where both A and B have made the same changes are - eliminated. - """ - for region in merge_regions: - if region[0] != "conflict": - yield region - continue - type, iz, zmatch, ia, amatch, ib, bmatch = region - a_region = self.a[ia:amatch] - b_region = self.b[ib:bmatch] - matches = mdiff.get_matching_blocks(''.join(a_region), - ''.join(b_region)) - next_a = ia - next_b = ib - for region_ia, region_ib, region_len in matches[:-1]: - region_ia += ia - region_ib += ib - reg = self.mismatch_region(next_a, region_ia, next_b, - region_ib) - if reg is not None: - yield reg - yield 'same', region_ia, region_len + region_ia - next_a = region_ia + region_len - next_b = region_ib + region_len - reg = self.mismatch_region(next_a, amatch, next_b, bmatch) - if reg is not None: - yield reg - - def mismatch_region(next_a, region_ia, next_b, region_ib): - if next_a < region_ia or next_b < region_ib: - return 'conflict', None, None, next_a, region_ia, next_b, region_ib - mismatch_region = staticmethod(mismatch_region) - def find_sync_regions(self): """Return a list of sync regions, where both descendants match the base. @@ -415,13 +347,16 @@ name_a = local name_b = other + name_base = None labels = opts.get('label', []) if len(labels) > 0: name_a = labels[0] if len(labels) > 1: name_b = labels[1] if len(labels) > 2: - raise util.Abort(_("can only specify two labels.")) + name_base = labels[2] + if len(labels) > 3: + raise util.Abort(_("can only specify three labels.")) try: localtext = readfile(local) @@ -437,11 +372,12 @@ else: out = sys.stdout - reprocess = not opts.get('no_minimal') - m3 = Merge3Text(basetext, localtext, othertext) - for line in m3.merge_lines(name_a=name_a, name_b=name_b, - reprocess=reprocess): + extrakwargs = {} + if name_base is not None: + extrakwargs['base_marker'] = '|||||||' + extrakwargs['name_base'] = name_base + for line in m3.merge_lines(name_a=name_a, name_b=name_b, **extrakwargs): out.write(line) if not opts.get('print'):
--- a/mercurial/sshpeer.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/sshpeer.py Sat Sep 27 14:47:52 2014 -0500 @@ -103,13 +103,8 @@ return self._caps def readerr(self): - while True: - size = util.fstat(self.pipee).st_size - if size == 0: - break - s = self.pipee.read(size) - if not s: - break + s = util.readpipe(self.pipee) + if s: for l in s.splitlines(): self.ui.status(_("remote: "), l, '\n')
--- a/mercurial/sshserver.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/sshserver.py Sat Sep 27 14:47:52 2014 -0500 @@ -142,7 +142,7 @@ return self.sendresponse("") - cg = changegroup.unbundle10(self.fin, "UN") + cg = changegroup.cg1unpacker(self.fin, "UN") r = changegroup.addchangegroup(self.repo, cg, 'serve', self._client()) self.lock.release() return str(r)
--- a/mercurial/tagmerge.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/tagmerge.py Sat Sep 27 14:47:52 2014 -0500 @@ -71,7 +71,7 @@ # - put blocks whose nodes come all from p2 first # - write the tag blocks in the sorted order -import tags +import tags as tagsmod import util from node import nullid, hex from i18n import _ @@ -85,8 +85,8 @@ with each tag. Rhis is done because only the line numbers of the first parent are useful for merging ''' - filetags = tags._readtaghist(ui, repo, lines, fn=fn, recode=None, - calcnodelines=True)[1] + filetags = tagsmod._readtaghist(ui, repo, lines, fn=fn, recode=None, + calcnodelines=True)[1] for tagname, taginfo in filetags.items(): if not keeplinenums: for el in taginfo:
--- a/mercurial/templatekw.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/templatekw.py Sat Sep 27 14:47:52 2014 -0500 @@ -26,6 +26,8 @@ def __call__(self): for x in self.values: yield x + def __len__(self): + return len(self.values) def showlist(name, values, plural=None, element=None, **args): if not element:
--- a/mercurial/templater.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/templater.py Sat Sep 27 14:47:52 2014 -0500 @@ -8,6 +8,7 @@ from i18n import _ import sys, os, re import util, config, templatefilters, templatekw, parser, error +import revset as revsetmod import types import minirst @@ -224,6 +225,23 @@ return util.datestr(date, fmt) return util.datestr(date) +def diff(context, mapping, args): + if len(args) > 2: + # i18n: "diff" is a keyword + raise error.ParseError(_("diff expects one, two or no arguments")) + + def getpatterns(i): + if i < len(args): + s = args[i][1].strip() + if s: + return [s] + return [] + + ctx = mapping['ctx'] + chunks = ctx.diff(match=ctx.match([], getpatterns(0), getpatterns(1))) + + return ''.join(chunks) + def fill(context, mapping, args): if not (1 <= len(args) <= 4): raise error.ParseError(_("fill expects one to four arguments")) @@ -370,16 +388,20 @@ ctx = mapping['ctx'] repo = ctx._repo + def query(expr): + m = revsetmod.match(repo.ui, expr) + return m(repo, revsetmod.spanset(repo)) + if len(args) > 1: formatargs = list([a[0](context, mapping, a[1]) for a in args[1:]]) - revs = repo.revs(raw, *formatargs) + revs = query(revsetmod.formatspec(raw, *formatargs)) revs = list([str(r) for r in revs]) else: revsetcache = mapping['cache'].setdefault("revsetcache", {}) if raw in revsetcache: revs = revsetcache[raw] else: - revs = repo.revs(raw) + revs = query(raw) revs = list([str(r) for r in revs]) revsetcache[raw] = revs @@ -511,6 +533,7 @@ funcs = { "date": date, + "diff": diff, "fill": fill, "get": get, "if": if_,
--- a/mercurial/transaction.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/transaction.py Sat Sep 27 14:47:52 2014 -0500 @@ -24,7 +24,7 @@ return _active def _playback(journal, report, opener, entries, backupentries, unlink=True): - for f, o, ignore in entries: + for f, o, _ignore in entries: if o or not unlink: try: fp = opener(f, 'a') @@ -41,7 +41,7 @@ raise backupfiles = [] - for f, b, ignore in backupentries: + for f, b, _ignore in backupentries: filepath = opener.join(f) backuppath = opener.join(b) try: @@ -96,6 +96,9 @@ opener.chmod(self.journal, createmode & 0666) opener.chmod(self.backupjournal, createmode & 0666) + # hold file generations to be performed on commit + self._filegenerators = {} + def __del__(self): if self.journal: self._abort() @@ -112,10 +115,10 @@ offsets = [] backups = [] - for f, o, _ in q[0]: + for f, o, _data in q[0]: offsets.append((f, o)) - for f, b, _ in q[1]: + for f, b, _data in q[1]: backups.append((f, b)) d = ''.join(['%s\0%d\n' % (f, o) for f, o in offsets]) @@ -154,7 +157,7 @@ if file in self.map or file in self.backupmap: return - backupfile = "journal.%s" % file + backupfile = "%s.backup.%s" % (self.journal, file) if self.opener.exists(file): filepath = self.opener.join(file) backuppath = self.opener.join(backupfile) @@ -173,6 +176,28 @@ self.backupsfile.flush() @active + def addfilegenerator(self, genid, filenames, genfunc, order=0): + """add a function to generates some files at transaction commit + + The `genfunc` argument is a function capable of generating proper + content of each entry in the `filename` tuple. + + At transaction close time, `genfunc` will be called with one file + object argument per entries in `filenames`. + + The transaction itself is responsible for the backup, creation and + final write of such file. + + The `genid` argument is used to ensure the same set of file is only + generated once. Call to `addfilegenerator` for a `genid` already + present will overwrite the old entry. + + The `order` argument may be used to control the order in which multiple + generator will be executed. + """ + self._filegenerators[genid] = (order, filenames, genfunc) + + @active def find(self, file): if file in self.map: return self.entries[self.map[file]] @@ -213,6 +238,18 @@ @active def close(self): '''commit the transaction''' + # write files registered for generation + for order, filenames, genfunc in sorted(self._filegenerators.values()): + files = [] + try: + for name in filenames: + self.addbackup(name) + files.append(self.opener(name, 'w', atomictemp=True)) + genfunc(*files) + finally: + for f in files: + f.close() + if self.count == 1 and self.onclose is not None: self.onclose() @@ -228,7 +265,7 @@ self.opener.unlink(self.journal) if self.opener.isfile(self.backupjournal): self.opener.unlink(self.backupjournal) - for f, b, _ in self.backupentries: + for _f, b, _ignore in self.backupentries: self.opener.unlink(b) self.backupentries = [] self.journal = None
--- a/mercurial/ui.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/ui.py Sat Sep 27 14:47:52 2014 -0500 @@ -10,6 +10,39 @@ import config, scmutil, util, error, formatter from node import hex +samplehgrcs = { + 'user': +"""# example user config (see "hg help config" for more info) +[ui] +# name and email, e.g. +# username = Jane Doe <jdoe@example.com> +username = + +[extensions] +# uncomment these lines to enable some popular extensions +# (see "hg help extensions" for more info) +# +# pager = +# progress = +# color =""", + + 'local': +"""# example repository config (see "hg help config" for more info) +""", + + 'global': +"""# example system-wide hg config (see "hg help config" for more info) + +[extensions] +# uncomment these lines to enable some popular extensions +# (see "hg help extensions" for more info) +# +# blackbox = +# progress = +# color = +# pager =""", +} + class ui(object): def __init__(self, src=None): # _buffers: used for temporary capture of output @@ -626,6 +659,8 @@ oldout = sys.stdout sys.stdin = self.fin sys.stdout = self.fout + # prompt ' ' must exist; otherwise readline may delete entire line + # - http://bugs.python.org/issue12833 line = raw_input(' ') sys.stdin = oldin sys.stdout = oldout @@ -728,7 +763,7 @@ if self.debugflag: opts['label'] = opts.get('label', '') + ' ui.debug' self.write(*msg, **opts) - def edit(self, text, user, extra={}): + def edit(self, text, user, extra={}, editform=None): (fd, name) = tempfile.mkstemp(prefix="hg-editor-", suffix=".txt", text=True) try: @@ -743,6 +778,8 @@ if label in extra: environ.update({'HGREVISION': extra[label]}) break + if editform: + environ.update({'HGEDITFORM': editform}) editor = self.geteditor()
--- a/mercurial/util.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/util.py Sat Sep 27 14:47:52 2014 -0500 @@ -53,6 +53,7 @@ popen = platform.popen posixfile = platform.posixfile quotecommand = platform.quotecommand +readpipe = platform.readpipe rename = platform.rename samedevice = platform.samedevice samefile = platform.samefile
--- a/mercurial/windows.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/windows.py Sat Sep 27 14:47:52 2014 -0500 @@ -336,3 +336,18 @@ def statisexec(st): '''check whether a stat result is an executable file''' return False + +def readpipe(pipe): + """Read all available data from a pipe.""" + chunks = [] + while True: + size = os.fstat(pipe.fileno()).st_size + if not size: + break + + s = pipe.read(size) + if not s: + break + chunks.append(s) + + return ''.join(chunks)
--- a/mercurial/wireproto.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/wireproto.py Sat Sep 27 14:47:52 2014 -0500 @@ -202,8 +202,10 @@ # :plain: string with no transformation needed. gboptsmap = {'heads': 'nodes', 'common': 'nodes', + 'obsmarkers': 'boolean', 'bundlecaps': 'csv', - 'listkeys': 'csv'} + 'listkeys': 'csv', + 'cg': 'boolean'} # client side @@ -248,7 +250,7 @@ yield {'nodes': encodelist(nodes)}, f d = f.value try: - yield [bool(int(f)) for f in d] + yield [bool(int(b)) for b in d] except ValueError: self._abort(error.ResponseError(_("unexpected response:"), d)) @@ -326,7 +328,7 @@ def changegroup(self, nodes, kind): n = encodelist(nodes) f = self._callcompressable("changegroup", roots=n) - return changegroupmod.unbundle10(f, 'UN') + return changegroupmod.cg1unpacker(f, 'UN') def changegroupsubset(self, bases, heads, kind): self.requirecap('changegroupsubset', _('look up remote changes')) @@ -334,7 +336,7 @@ heads = encodelist(heads) f = self._callcompressable("changegroupsubset", bases=bases, heads=heads) - return changegroupmod.unbundle10(f, 'UN') + return changegroupmod.cg1unpacker(f, 'UN') def getbundle(self, source, **kwargs): self.requirecap('getbundle', _('look up remote changes')) @@ -349,6 +351,8 @@ value = encodelist(value) elif keytype == 'csv': value = ','.join(value) + elif keytype == 'boolean': + value = '%i' % bool(value) elif keytype != 'plain': raise KeyError('unknown getbundle option type %s' % keytype) @@ -358,7 +362,7 @@ if bundlecaps is not None and 'HG2X' in bundlecaps: return bundle2.unbundle20(self.ui, f) else: - return changegroupmod.unbundle10(f, 'UN') + return changegroupmod.cg1unpacker(f, 'UN') def unbundle(self, cg, heads, source): '''Send cg (a readable file-like object representing the @@ -606,7 +610,7 @@ else: caps.append('streamreqs=%s' % ','.join(requiredformats)) if repo.ui.configbool('experimental', 'bundle2-exp', False): - capsblob = bundle2.encodecaps(repo.bundle2caps) + capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo)) caps.append('bundle2-exp=' + urllib.quote(capsblob)) caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority)) caps.append('httpheader=1024') @@ -652,6 +656,8 @@ opts[k] = decodelist(v) elif keytype == 'csv': opts[k] = set(v.split(',')) + elif keytype == 'boolean': + opts[k] = bool(v) elif keytype != 'plain': raise KeyError('unknown getbundle option type %s' % keytype)
--- a/mercurial/worker.py Mon Sep 22 23:46:38 2014 +0900 +++ b/mercurial/worker.py Sat Sep 27 14:47:52 2014 -0500 @@ -105,7 +105,7 @@ if err.errno != errno.ESRCH: raise def waitforworkers(): - for _ in pids: + for _pid in pids: st = _exitstatus(os.wait()[1]) if st and not problem[0]: problem[0] = st
--- a/setup.py Mon Sep 22 23:46:38 2014 +0900 +++ b/setup.py Sat Sep 27 14:47:52 2014 -0500 @@ -33,12 +33,14 @@ except ImportError: try: import sha + sha.sha # silence unused import warning except ImportError: raise SystemExit( "Couldn't import standard hashlib (incomplete Python install).") try: import zlib + zlib.compressobj # silence unused import warning except ImportError: raise SystemExit( "Couldn't import standard zlib (incomplete Python install).") @@ -56,6 +58,7 @@ else: try: import bz2 + bz2.BZ2Compressor # silence unused import warning except ImportError: raise SystemExit( "Couldn't import standard bz2 (incomplete Python install).") @@ -129,6 +132,7 @@ # py2exe needs to be installed to work try: import py2exe + py2exe.Distribution # silence unused import warning py2exeloaded = True # import py2exe's patched Distribution class from distutils.core import Distribution @@ -579,7 +583,7 @@ cmdclass=cmdclass, distclass=hgdist, options={'py2exe': {'packages': ['hgext', 'email']}, - 'bdist_mpkg': {'zipdist': True, + 'bdist_mpkg': {'zipdist': False, 'license': 'COPYING', 'readme': 'contrib/macosx/Readme.html', 'welcome': 'contrib/macosx/Welcome.html',
--- a/tests/hghave.py Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/hghave.py Sat Sep 27 14:47:52 2014 -0500 @@ -5,6 +5,17 @@ tempprefix = 'hg-hghave-' +checks = { + "true": (lambda: True, "yak shaving"), + "false": (lambda: False, "nail clipper"), +} + +def check(name, desc): + def decorator(func): + checks[name] = (func, desc) + return func + return decorator + def matchoutput(cmd, regexp, ignorestatus=False): """Return True if cmd executes successfully and its output is matched by the supplied regular expression. @@ -19,9 +30,11 @@ ret = 1 return (ignorestatus or ret is None) and r.search(s) +@check("baz", "GNU Arch baz client") def has_baz(): return matchoutput('baz --version 2>&1', r'baz Bazaar version') +@check("bzr", "Canonical's Bazaar client") def has_bzr(): try: import bzrlib @@ -29,6 +42,7 @@ except ImportError: return False +@check("bzr114", "Canonical's Bazaar client >= 1.14") def has_bzr114(): try: import bzrlib @@ -37,21 +51,26 @@ except ImportError: return False +@check("cvs", "cvs client/server") def has_cvs(): re = r'Concurrent Versions System.*?server' return matchoutput('cvs --version 2>&1', re) and not has_msys() +@check("cvs112", "cvs client/server >= 1.12") def has_cvs112(): re = r'Concurrent Versions System \(CVS\) 1.12.*?server' return matchoutput('cvs --version 2>&1', re) and not has_msys() +@check("darcs", "darcs client") def has_darcs(): return matchoutput('darcs --version', r'2\.[2-9]', True) +@check("mtn", "monotone client (>= 1.0)") def has_mtn(): return matchoutput('mtn --version', r'monotone', True) and not matchoutput( 'mtn --version', r'monotone 0\.', True) +@check("eol-in-paths", "end-of-lines in paths") def has_eol_in_paths(): try: fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r') @@ -61,6 +80,7 @@ except (IOError, OSError): return False +@check("execbit", "executable bit") def has_executablebit(): try: EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH @@ -78,6 +98,7 @@ return False return not (new_file_has_exec or exec_flags_cannot_flip) +@check("icasefs", "case insensitive file system") def has_icasefs(): # Stolen from mercurial.util fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix) @@ -96,6 +117,7 @@ finally: os.remove(path) +@check("fifo", "named pipes") def has_fifo(): if getattr(os, "mkfifo", None) is None: return False @@ -107,9 +129,11 @@ except OSError: return False +@check("killdaemons", 'killdaemons.py support') def has_killdaemons(): return True +@check("cacheable", "cacheable filesystem") def has_cacheable_fs(): from mercurial import util @@ -120,22 +144,28 @@ finally: os.remove(path) +@check("lsprof", "python lsprof module") def has_lsprof(): try: import _lsprof + _lsprof.Profiler # silence unused import warning return True except ImportError: return False +@check("gettext", "GNU Gettext (msgfmt)") def has_gettext(): return matchoutput('msgfmt --version', 'GNU gettext-tools') +@check("git", "git command line client") def has_git(): return matchoutput('git --version 2>&1', r'^git version') +@check("docutils", "Docutils text processing library") def has_docutils(): try: from docutils.core import publish_cmdline + publish_cmdline # silence unused import return True except ImportError: return False @@ -146,16 +176,20 @@ return (0, 0) return (int(m.group(1)), int(m.group(2))) +@check("svn15", "subversion client and admin tools >= 1.5") def has_svn15(): return getsvnversion() >= (1, 5) +@check("svn13", "subversion client and admin tools >= 1.3") def has_svn13(): return getsvnversion() >= (1, 3) +@check("svn", "subversion client and admin tools") def has_svn(): return matchoutput('svn --version 2>&1', r'^svn, version') and \ matchoutput('svnadmin --version 2>&1', r'^svnadmin, version') +@check("svn-bindings", "subversion python bindings") def has_svn_bindings(): try: import svn.core @@ -166,10 +200,12 @@ except ImportError: return False +@check("p4", "Perforce server and client") def has_p4(): return (matchoutput('p4 -V', r'Rev\. P4/') and matchoutput('p4d -V', r'Rev\. P4D/')) +@check("symlink", "symbolic links") def has_symlink(): if getattr(os, "symlink", None) is None: return False @@ -181,6 +217,7 @@ except (OSError, AttributeError): return False +@check("hardlink", "hardlinks") def has_hardlink(): from mercurial import util fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix) @@ -196,12 +233,15 @@ finally: os.unlink(fn) +@check("tla", "GNU Arch tla client") def has_tla(): return matchoutput('tla --version 2>&1', r'The GNU Arch Revision') +@check("gpg", "gpg client") def has_gpg(): return matchoutput('gpg --version 2>&1', r'GnuPG') +@check("unix-permissions", "unix-style permissions") def has_unix_permissions(): d = tempfile.mkdtemp(dir='.', prefix=tempprefix) try: @@ -218,51 +258,64 @@ finally: os.rmdir(d) +@check("root", "root permissions") def has_root(): return getattr(os, 'geteuid', None) and os.geteuid() == 0 +@check("pyflakes", "Pyflakes python linter") def has_pyflakes(): return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"", r"<stdin>:1: 're' imported but unused", True) +@check("pygments", "Pygments source highlighting library") def has_pygments(): try: import pygments + pygments.highlight # silence unused import warning return True except ImportError: return False +@check("python243", "python >= 2.4.3") def has_python243(): return sys.version_info >= (2, 4, 3) +@check("outer-repo", "outer repo") def has_outer_repo(): # failing for other reasons than 'no repo' imply that there is a repo return not matchoutput('hg root 2>&1', r'abort: no repository found', True) +@check("ssl", "python >= 2.6 ssl module and python OpenSSL") def has_ssl(): try: import ssl + ssl.wrap_socket # silence unused import warning import OpenSSL OpenSSL.SSL.Context return True except ImportError: return False +@check("windows", "Windows") def has_windows(): return os.name == 'nt' +@check("system-sh", "system() uses sh") def has_system_sh(): return os.name != 'nt' +@check("serve", "platform and python can manage 'hg serve -d'") def has_serve(): return os.name != 'nt' # gross approximation +@check("test-repo", "running tests from repository") def has_test_repo(): t = os.environ["TESTDIR"] return os.path.isdir(os.path.join(t, "..", ".hg")) +@check("tic", "terminfo compiler and curses module") def has_tic(): try: import curses @@ -271,63 +324,20 @@ except ImportError: return False +@check("msys", "Windows with MSYS") def has_msys(): return os.getenv('MSYSTEM') +@check("aix", "AIX") def has_aix(): return sys.platform.startswith("aix") +@check("absimport", "absolute_import in __future__") def has_absimport(): import __future__ from mercurial import util return util.safehasattr(__future__, "absolute_import") +@check("py3k", "running with Python 3.x") def has_py3k(): return 3 == sys.version_info[0] - -checks = { - "true": (lambda: True, "yak shaving"), - "false": (lambda: False, "nail clipper"), - "baz": (has_baz, "GNU Arch baz client"), - "bzr": (has_bzr, "Canonical's Bazaar client"), - "bzr114": (has_bzr114, "Canonical's Bazaar client >= 1.14"), - "cacheable": (has_cacheable_fs, "cacheable filesystem"), - "cvs": (has_cvs, "cvs client/server"), - "cvs112": (has_cvs112, "cvs client/server >= 1.12"), - "darcs": (has_darcs, "darcs client"), - "docutils": (has_docutils, "Docutils text processing library"), - "eol-in-paths": (has_eol_in_paths, "end-of-lines in paths"), - "execbit": (has_executablebit, "executable bit"), - "fifo": (has_fifo, "named pipes"), - "gettext": (has_gettext, "GNU Gettext (msgfmt)"), - "git": (has_git, "git command line client"), - "gpg": (has_gpg, "gpg client"), - "hardlink": (has_hardlink, "hardlinks"), - "icasefs": (has_icasefs, "case insensitive file system"), - "killdaemons": (has_killdaemons, 'killdaemons.py support'), - "lsprof": (has_lsprof, "python lsprof module"), - "mtn": (has_mtn, "monotone client (>= 1.0)"), - "outer-repo": (has_outer_repo, "outer repo"), - "p4": (has_p4, "Perforce server and client"), - "pyflakes": (has_pyflakes, "Pyflakes python linter"), - "pygments": (has_pygments, "Pygments source highlighting library"), - "python243": (has_python243, "python >= 2.4.3"), - "root": (has_root, "root permissions"), - "serve": (has_serve, "platform and python can manage 'hg serve -d'"), - "ssl": (has_ssl, "python >= 2.6 ssl module and python OpenSSL"), - "svn": (has_svn, "subversion client and admin tools"), - "svn13": (has_svn13, "subversion client and admin tools >= 1.3"), - "svn15": (has_svn15, "subversion client and admin tools >= 1.5"), - "svn-bindings": (has_svn_bindings, "subversion python bindings"), - "symlink": (has_symlink, "symbolic links"), - "system-sh": (has_system_sh, "system() uses sh"), - "test-repo": (has_test_repo, "running tests from repository"), - "tic": (has_tic, "terminfo compiler and curses module"), - "tla": (has_tla, "GNU Arch tla client"), - "unix-permissions": (has_unix_permissions, "unix-style permissions"), - "windows": (has_windows, "Windows"), - "msys": (has_msys, "Windows with MSYS"), - "aix": (has_aix, "AIX"), - "absimport": (has_absimport, "absolute_import in __future__"), - "py3k": (has_py3k, "running with Python 3.x"), -}
--- a/tests/run-tests.py Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/run-tests.py Sat Sep 27 14:47:52 2014 -0500 @@ -57,8 +57,17 @@ import threading import killdaemons as killmod import Queue as queue +from xml.dom import minidom import unittest +try: + if sys.version_info < (2, 7): + import simplejson as json + else: + import json +except ImportError: + json = None + processlock = threading.Lock() # subprocess._cleanup can race with any Popen.wait or Popen.poll on py24 @@ -185,11 +194,15 @@ " (default: $%s or %d)" % defaults['timeout']) parser.add_option("--time", action="store_true", help="time how long each test takes") + parser.add_option("--json", action="store_true", + help="store test result data in 'report.json' file") parser.add_option("--tmpdir", type="string", help="run tests in the given temporary directory" " (implies --keep-tmpdir)") parser.add_option("-v", "--verbose", action="store_true", help="output verbose messages") + parser.add_option("--xunit", type="string", + help="record xunit results at specified path") parser.add_option("--view", type="string", help="external diff viewer") parser.add_option("--with-hg", type="string", @@ -304,6 +317,20 @@ return log(*msg) +# 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]") + +def cdatasafe(data): + """Make a string safe to include in a CDATA block. + + Certain control characters are illegal in a CDATA block, and + there's no way to include a ]]> in a CDATA either. This function + 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(']]>', '] ]>') + def log(*msg): """Log something to stdout. @@ -460,8 +487,15 @@ raise except SkipTest, 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: 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: result.addWarn(self, str(e)) except self.failureException, e: @@ -522,7 +556,7 @@ missing, failed = TTest.parsehghaveoutput(out) if not missing: - missing = ['irrelevant'] + missing = ['skipped'] if failed: self.fail('hg have failed checking for %s' % failed[-1]) @@ -786,7 +820,15 @@ for n, l in enumerate(lines): if not l.endswith('\n'): l += '\n' - if l.startswith('#if'): + if l.startswith('#require'): + lsplit = l.split() + if len(lsplit) < 2 or lsplit[0] != '#require': + after.setdefault(pos, []).append(' !!! invalid #require\n') + if not self._hghave(lsplit[1:]): + script = ["exit 80\n"] + break + after.setdefault(pos, []).append(l) + elif l.startswith('#if'): lsplit = l.split() if len(lsplit) < 2 or lsplit[0] != '#if': after.setdefault(pos, []).append(' !!! invalid #if\n') @@ -1041,7 +1083,7 @@ output = re.sub(s, r, output) return ret, output.splitlines(True) -iolock = threading.Lock() +iolock = threading.RLock() class SkipTest(Exception): """Raised to indicate that a test is to be skipped.""" @@ -1077,46 +1119,59 @@ self.times = [] self._started = {} + self._stopped = {} + # Data stored for the benefit of generating xunit reports. + self.successes = [] + self.faildata = {} def addFailure(self, test, reason): self.failures.append((test, reason)) - iolock.acquire() if self._options.first: self.stop() else: + iolock.acquire() if not self._options.nodiff: self.stream.write('\nERROR: %s output changed\n' % test) self.stream.write('!') self.stream.flush() - iolock.release() + iolock.release() - def addError(self, *args, **kwargs): - super(TestResult, self).addError(*args, **kwargs) + def addSuccess(self, test): + iolock.acquire() + super(TestResult, self).addSuccess(test) + iolock.release() + self.successes.append(test) + def addError(self, test, err): + super(TestResult, self).addError(test, err) if self._options.first: self.stop() # 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() 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': + if reason != 'not retesting' and reason != "doesn't match keyword": self.stream.write('i') + else: + self.testsRun += 1 self.stream.flush() + iolock.release() def addWarn(self, test, reason): self.warned.append((test, reason)) @@ -1124,16 +1179,20 @@ 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() def addOutputMismatch(self, test, ret, got, expected): """Record a mismatch in test output for a particular test.""" accepted = False + failed = False + lines = [] iolock.acquire() if self._options.nodiff: @@ -1152,17 +1211,18 @@ 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 - + # 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() return accepted @@ -1170,17 +1230,30 @@ def startTest(self, test): super(TestResult, self).startTest(test) - self._started[test.name] = time.time() + # os.times module computes the user time and system time spent by + # child's processes along with real elapsed time taken by a process. + # This module has one limitation. It can only work for Linux user + # and not for Windows. + self._started[test.name] = os.times() def stopTest(self, test, interrupted=False): super(TestResult, self).stopTest(test) - self.times.append((test.name, time.time() - self._started[test.name])) + self._stopped[test.name] = os.times() + + starttime = self._started[test.name] + endtime = self._stopped[test.name] + self.times.append((test.name, endtime[2] - starttime[2], + endtime[3] - starttime[3], endtime[4] - starttime[4])) + del self._started[test.name] + del self._stopped[test.name] if interrupted: + iolock.acquire() self.stream.writeln('INTERRUPTED: %s (after %d seconds)' % ( - test.name, self.times[-1][1])) + test.name, self.times[-1][3])) + iolock.release() class TestSuite(unittest.TestSuite): """Custom unitest TestSuite that knows how to execute Mercurial tests.""" @@ -1314,6 +1387,7 @@ skipped = len(result.skipped) ignored = len(result.ignored) + iolock.acquire() self.stream.writeln('') if not self._runner.options.noskips: @@ -1326,20 +1400,76 @@ for test, msg in result.errors: self.stream.writeln('Errored %s: %s' % (test.name, msg)) + 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]) + cd = doc.createCDATASection(cdatasafe(err)) + t.appendChild(cd) + s.appendChild(t) + xuf.write(doc.toprettyxml(indent=' ', encoding='utf-8')) + finally: + xuf.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 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 + + 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() + self._runner._checkhglib('Tested') - # When '--retest' is enabled, only failure tests run. At this point - # "result.testsRun" holds the count of failure test that has run. But - # as while printing output, we have subtracted the skipped and ignored - # count from "result.testsRun". Therefore, to make the count remain - # the same, we need to add skipped and ignored count in here. - if self._runner.options.retest: - result.testsRun = result.testsRun + skipped + ignored - - # This differs from unittest's default output in that we don't count - # skipped and ignored tests as part of the total test count. self.stream.writeln('# Ran %d tests, %d skipped, %d warned, %d failed.' - % (result.testsRun - skipped - ignored, + % (result.testsRun, skipped + ignored, warned, failed)) if failed: self.stream.writeln('python hash seed: %s' % @@ -1347,15 +1477,19 @@ if self._runner.options.time: self.printtimes(result.times) + iolock.release() + return result def printtimes(self, times): + # iolock held by run self.stream.writeln('# Producing time report') - times.sort(key=lambda t: (t[1], t[0]), reverse=True) - cols = '%7.3f %s' - self.stream.writeln('%-7s %s' % ('Time', 'Test')) - for test, timetaken in times: - self.stream.writeln(cols % (timetaken, test)) + 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)) class TestRunner(object): """Holds context for executing tests.
--- a/tests/test-acl.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-acl.t Sat Sep 27 14:47:52 2014 -0500 @@ -4,7 +4,7 @@ > shift > echo "Pushing as user $user" > echo 'hgrc = """' - > sed -e 1,2d b/.hg/hgrc | grep -v fakegroups.py + > sed -n '/\[[ha]/,$p' b/.hg/hgrc | grep -v fakegroups.py > echo '"""' > if test -f acl.config; then > echo 'acl.config = """' @@ -82,6 +82,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" 3 changesets found list of changesets: @@ -119,8 +122,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 0 (undo push) 0:6675d58eff77 @@ -140,6 +141,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -180,8 +184,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 0 (undo push) 0:6675d58eff77 @@ -202,6 +204,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -252,8 +257,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 0 (undo push) 0:6675d58eff77 @@ -274,6 +277,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -341,6 +347,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -413,6 +422,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -482,6 +494,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -556,6 +571,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -627,6 +645,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -700,6 +721,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -750,8 +774,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 0 (undo push) 0:6675d58eff77 @@ -779,6 +801,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -859,6 +884,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -896,10 +924,10 @@ 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 *] *: '../acl.config' (glob) + error: pretxnchangegroup.acl hook raised an exception: [Errno 2] No such file or directory: '../acl.config' transaction abort! rollback completed - abort: *: ../acl.config (glob) + abort: No such file or directory: ../acl.config no rollback information available 0:6675d58eff77 @@ -934,6 +962,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -1020,6 +1051,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -1070,8 +1104,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 0 (undo push) 0:6675d58eff77 @@ -1090,6 +1122,8 @@ $ do_push fred Pushing as user fred hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1100,6 +1134,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -1150,8 +1187,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 0 (undo push) 0:6675d58eff77 @@ -1164,6 +1199,8 @@ $ do_push fred Pushing as user fred hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1176,6 +1213,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -1242,6 +1282,8 @@ $ do_push fred Pushing as user fred hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1252,6 +1294,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -1303,8 +1348,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 0 (undo push) 0:6675d58eff77 @@ -1317,6 +1360,8 @@ $ do_push fred Pushing as user fred hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1329,6 +1374,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" invalid branchheads cache (served): tip differs listing keys for "bookmarks" 3 changesets found @@ -1436,6 +1484,8 @@ $ do_push astro Pushing as user astro hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1444,6 +1494,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" 4 changesets found list of changesets: @@ -1504,8 +1557,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 2 (undo push) 2:fb35475503ef @@ -1517,6 +1568,8 @@ $ do_push astro Pushing as user astro hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1527,6 +1580,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" 4 changesets found list of changesets: @@ -1597,6 +1653,8 @@ $ do_push astro Pushing as user astro hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1606,6 +1664,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" 4 changesets found list of changesets: @@ -1671,6 +1732,8 @@ $ do_push astro Pushing as user astro hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1681,6 +1744,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" 4 changesets found list of changesets: @@ -1740,6 +1806,8 @@ $ do_push george Pushing as user george hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1750,6 +1818,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" 4 changesets found list of changesets: @@ -1810,8 +1881,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 2 (undo push) 2:fb35475503ef @@ -1827,6 +1896,8 @@ $ do_push george Pushing as user george hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1838,6 +1909,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" 4 changesets found list of changesets: @@ -1898,8 +1972,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 2 (undo push) 2:fb35475503ef @@ -1913,6 +1985,8 @@ $ do_push george Pushing as user george hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1925,6 +1999,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" 4 changesets found list of changesets: @@ -1989,6 +2066,8 @@ $ do_push astro Pushing as user astro hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -1999,6 +2078,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" 4 changesets found list of changesets: @@ -2059,8 +2141,6 @@ updating the branch cache listing keys for "phases" try to push obsolete markers to remote - checking for updated bookmarks - listing keys for "bookmarks" repository tip rolled back to revision 2 (undo push) 2:fb35475503ef @@ -2070,6 +2150,8 @@ $ do_push george Pushing as user george hgrc = """ + [hooks] + pretxnchangegroup.acl = python:hgext.acl.hook [acl] sources = push [extensions] @@ -2080,6 +2162,9 @@ query 1; heads searching for changes all remote heads known locally + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" 4 changesets found list of changesets:
--- a/tests/test-alias.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-alias.t Sat Sep 27 14:47:52 2014 -0500 @@ -10,6 +10,7 @@ > unknown = bargle > ambiguous = s > recursive = recursive + > disabled = email > nodefinition = > noclosingquotation = ' > no--cwd = status --cwd elsewhere @@ -30,6 +31,7 @@ > echo1 = !printf '\$1\n' > echo2 = !printf '\$2\n' > echo13 = !printf '\$1 \$3\n' + > echotokens = !printf "%s\n" "\$@" > count = !hg log -r "\$@" --template=. | wc -c | sed -e 's/ //g' > mcount = !hg log \$@ --template=. | wc -c | sed -e 's/ //g' > rt = root @@ -60,7 +62,7 @@ unknown $ hg unknown - alias 'unknown' resolves to unknown command 'bargle' + abort: alias 'unknown' resolves to unknown command 'bargle' [255] $ hg help unknown alias 'unknown' resolves to unknown command 'bargle' @@ -69,7 +71,7 @@ ambiguous $ hg ambiguous - alias 'ambiguous' resolves to ambiguous command 's' + abort: alias 'ambiguous' resolves to ambiguous command 's' [255] $ hg help ambiguous alias 'ambiguous' resolves to ambiguous command 's' @@ -78,16 +80,32 @@ recursive $ hg recursive - alias 'recursive' resolves to unknown command 'recursive' + abort: alias 'recursive' resolves to unknown command 'recursive' [255] $ hg help recursive alias 'recursive' resolves to unknown command 'recursive' +disabled + + $ hg disabled + abort: alias 'disabled' resolves to unknown command 'email' + ('email' is provided by 'patchbomb' extension) + [255] + $ hg help disabled + alias 'disabled' resolves to unknown command 'email' + + 'email' is provided by the following extension: + + patchbomb command to send changesets as (a series of) patch emails + + (use "hg help extensions" for information on enabling extensions) + + no definition $ hg nodef - no definition for alias 'nodefinition' + abort: no definition for alias 'nodefinition' [255] $ hg help nodef no definition for alias 'nodefinition' @@ -96,7 +114,7 @@ no closing quotation $ hg noclosing - error in definition for alias 'noclosingquotation': No closing quotation + abort: error in definition for alias 'noclosingquotation': No closing quotation [255] $ hg help noclosing error in definition for alias 'noclosingquotation': No closing quotation @@ -105,27 +123,30 @@ invalid options $ hg no--cwd - error in definition for alias 'no--cwd': --cwd may only be given on the command line + abort: error in definition for alias 'no--cwd': --cwd may only be given on the command line [255] $ hg help no--cwd - error in definition for alias 'no--cwd': --cwd may only be given on the command line + error in definition for alias 'no--cwd': --cwd may only be given on the + command line $ hg no-R - error in definition for alias 'no-R': -R may only be given on the command line + abort: error in definition for alias 'no-R': -R may only be given on the command line [255] $ hg help no-R error in definition for alias 'no-R': -R may only be given on the command line $ hg no--repo - error in definition for alias 'no--repo': --repo may only be given on the command line + abort: error in definition for alias 'no--repo': --repo may only be given on the command line [255] $ hg help no--repo - error in definition for alias 'no--repo': --repo may only be given on the command line + error in definition for alias 'no--repo': --repo may only be given on the + command line $ hg no--repository - error in definition for alias 'no--repository': --repository may only be given on the command line + abort: error in definition for alias 'no--repository': --repository may only be given on the command line [255] $ hg help no--repository - error in definition for alias 'no--repository': --repository may only be given on the command line + error in definition for alias 'no--repository': --repository may only be given + on the command line $ hg no--config - error in definition for alias 'no--config': --config may only be given on the command line + abort: error in definition for alias 'no--config': --config may only be given on the command line [255] optional repository @@ -229,6 +250,10 @@ foo $ hg echoall 'test $2' foo test $2 foo + $ hg echoall 'test $@' foo '$@' + test $@ foo $@ + $ hg echoall 'test "$@"' foo '"$@"' + test "$@" foo "$@" $ hg echo1 foo bar baz foo $ hg echo2 foo bar baz @@ -237,6 +262,22 @@ foo baz $ hg echo2 foo + $ hg echotokens + + $ hg echotokens foo 'bar $1 baz' + foo + bar $1 baz + $ hg echotokens 'test $2' foo + test $2 + foo + $ hg echotokens 'test $@' foo '$@' + test $@ + foo + $@ + $ hg echotokens 'test "$@"' foo '"$@"' + test "$@" + foo + "$@" $ echo bar > bar $ hg commit -qA -m bar $ hg count . @@ -372,7 +413,7 @@ alias for: hg root - use "hg help rt" to show the full help text + (use "hg rt -h" to show more help) [255] invalid global arguments for normal commands, aliases, and shell aliases @@ -401,7 +442,7 @@ summary summarize working directory state update update working directory (or switch revisions) - use "hg help" for the full list of commands or "hg -v" for details + (use "hg help" for the full list of commands or "hg -v" for details) [255] $ hg --invalid mylog hg: option --invalid not recognized @@ -427,7 +468,7 @@ summary summarize working directory state update update working directory (or switch revisions) - use "hg help" for the full list of commands or "hg -v" for details + (use "hg help" for the full list of commands or "hg -v" for details) [255] $ hg --invalid blank hg: option --invalid not recognized @@ -453,7 +494,7 @@ summary summarize working directory state update update working directory (or switch revisions) - use "hg help" for the full list of commands or "hg -v" for details + (use "hg help" for the full list of commands or "hg -v" for details) [255] This should show id:
--- a/tests/test-ancestor.py Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-ancestor.py Sat Sep 27 14:47:52 2014 -0500 @@ -91,6 +91,10 @@ s = genlazyancestors([11, 13]) printlazyancestors(s, [11, 13, 7, 9, 8, 3, 6, 4, 1, -1, 0]) + # Standard with ancestry in the initial set (1 is ancestor of 3) + s = genlazyancestors([1, 3]) + printlazyancestors(s, [1, -1, 0]) + # Including revs s = genlazyancestors([11, 13], inclusive=True) printlazyancestors(s, [11, 13, 7, 9, 8, 3, 6, 4, 1, -1, 0])
--- a/tests/test-ancestor.py.out Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-ancestor.py.out Sat Sep 27 14:47:52 2014 -0500 @@ -38,6 +38,8 @@ [] % lazy ancestor set for [11, 13], stoprev = 0, inclusive = False [7, 8, 3, 4, 1, 0] +% lazy ancestor set for [1, 3], stoprev = 0, inclusive = False +[1, 0] % lazy ancestor set for [11, 13], stoprev = 0, inclusive = True [11, 13, 7, 8, 3, 4, 1, 0] % lazy ancestor set for [11, 13], stoprev = 6, inclusive = False
--- a/tests/test-annotate.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-annotate.t Sat Sep 27 14:47:52 2014 -0500 @@ -51,6 +51,29 @@ $ hg annotate -cdnul a nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000:1: a +annotate (JSON) + + $ hg annotate -Tjson a + [ + { + "line": "a\n", + "rev": 0 + } + ] + + $ hg annotate -Tjson -cdfnul a + [ + { + "date": [1.0, 0], + "file": "a", + "line": "a\n", + "line_number": 1, + "node": "8435f90966e442695d2ded29fdade2bac5ad8065", + "rev": 0, + "user": "nobody" + } + ] + $ cat <<EOF >>a > a > a
--- a/tests/test-archive-symlinks.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-archive-symlinks.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" symlink || exit 80 +#require symlink $ origdir=`pwd`
--- a/tests/test-archive.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-archive.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve $ hg init test $ cd test
--- a/tests/test-bad-pull.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-bad-pull.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve #if windows $ hg clone http://localhost:$HGPORT/ copy
--- a/tests/test-bookmarks-pushpull.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-bookmarks-pushpull.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve $ cat << EOF >> $HGRCPATH > [ui]
--- a/tests/test-bundle.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-bundle.t Sat Sep 27 14:47:52 2014 -0500 @@ -422,7 +422,7 @@ $ rm -r full-clone When cloning from a non-copiable repository into '', do not -recurse infinitely (issue 2528) +recurse infinitely (issue2528) $ hg clone full.hg '' abort: empty destination path is not valid
--- a/tests/test-bundle2.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-bundle2.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,3 +1,7 @@ + + $ getmainid() { + > hg -R main log --template '{node}\n' --rev "$1" + > } Create an extension to test bundle2 API @@ -16,6 +20,9 @@ > from mercurial import discovery > from mercurial import changegroup > from mercurial import error + > from mercurial import obsolete + > + > obsolete._enabled = True > > try: > import msvcrt @@ -99,7 +106,7 @@ > headmissing = [c.node() for c in repo.set('heads(%ld)', revs)] > headcommon = [c.node() for c in repo.set('parents(%ld) - %ld', revs, revs)] > outgoing = discovery.outgoing(repo.changelog, headcommon, headmissing) - > cg = changegroup.getlocalbundle(repo, 'test:bundle2', outgoing, None) + > cg = changegroup.getlocalchangegroup(repo, 'test:bundle2', outgoing, None) > bundler.newpart('b2x:changegroup', data=cg.getchunks()) > > if opts['parts']: @@ -191,7 +198,7 @@ > bundle2-exp=True > [ui] > ssh=python "$TESTDIR/dummyssh" - > logtemplate={rev}:{node|short} {phase} {author} {desc|firstline} + > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline} > [web] > push_ssl = false > allow_push = * @@ -668,23 +675,23 @@ (run 'hg heads' to see heads, 'hg merge' to merge) $ hg log -G - o 8:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> H + o 8:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> H | - | o 7:eea13746799a draft Nicolas Dumazet <nicdumz.commits@gmail.com> G + | o 7:eea13746799a draft Nicolas Dumazet <nicdumz.commits@gmail.com> G |/| - o | 6:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F + o | 6:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F | | - | o 5:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E + | o 5:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ - | o 4:32af7686d403 draft Nicolas Dumazet <nicdumz.commits@gmail.com> D + | o 4:32af7686d403 draft Nicolas Dumazet <nicdumz.commits@gmail.com> D | | - | o 3:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> C + | o 3:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> C | | - | o 2:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> B + | o 2:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> B |/ - o 1:cd010b8cd998 draft Nicolas Dumazet <nicdumz.commits@gmail.com> A + o 1:cd010b8cd998 draft Nicolas Dumazet <nicdumz.commits@gmail.com> A - @ 0:3903775176ed draft test a + @ 0:3903775176ed draft test a $ hg bundle2 --debug --rev '8+7+5+4' ../rev.hg2 @@ -758,26 +765,34 @@ added 0 changesets with 0 changes to 3 files \x00\x00\x00\x00\x00\x00 (no-eol) (esc) + $ cd .. + Real world exchange ===================== +Add more obsolescence information + + $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc` + $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c` clone --pull - $ cd .. $ hg -R main phase --public cd010b8cd998 $ hg clone main other --pull --rev 9520eea781bc adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 2 files + 1 new obsolescence markers updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg -R other log -G - @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E + @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E | - o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + $ hg -R other debugobsolete + 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} pull @@ -789,14 +804,18 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) + 1 new obsolescence markers (run 'hg heads' to see heads, 'hg merge' to merge) $ hg -R other log -G - o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F + o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F | - | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E + | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ - o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + $ hg -R other debugobsolete + 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} pull empty (with phase movement) @@ -805,95 +824,155 @@ pulling from $TESTTMP/main (glob) no changes found $ hg -R other log -G - o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F + o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F | - | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E + | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ - o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + $ hg -R other debugobsolete + 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + pull empty $ hg -R other pull -r 24b6387c8c8c pulling from $TESTTMP/main (glob) no changes found $ hg -R other log -G - o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F + o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F | - | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E + | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ - o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + $ hg -R other debugobsolete + 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + +add extra data to test their exchange during push + + $ hg -R main bookmark --rev eea13746799a book_eea1 + $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a` + $ hg -R main bookmark --rev 02de42196ebe book_02de + $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe` + $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc + $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16` + $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd + $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8` + $ hg -R main bookmark --rev 32af7686d403 book_32af + $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403` + + $ hg -R other bookmark --rev cd010b8cd998 book_eea1 + $ hg -R other bookmark --rev cd010b8cd998 book_02de + $ hg -R other bookmark --rev cd010b8cd998 book_42cc + $ hg -R other bookmark --rev cd010b8cd998 book_5fdd + $ hg -R other bookmark --rev cd010b8cd998 book_32af + + $ hg -R main phase --public eea13746799a push - - $ hg -R main phase --public eea13746799a - $ hg -R main push other --rev eea13746799a + $ hg -R main push other --rev eea13746799a --bookmark book_eea1 pushing to other searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 0 changes to 0 files (-1 heads) + remote: 1 new obsolescence markers + updating bookmark book_eea1 + exporting bookmark book_eea1 $ hg -R other log -G - o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> G + o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G |\ - | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F + | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F | | - @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E + @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ - o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A + $ hg -R other debugobsolete + 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} pull over ssh - $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --traceback + $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de pulling from ssh://user@dummy/main searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) + 1 new obsolescence markers + updating bookmark book_02de (run 'hg heads' to see heads, 'hg merge' to merge) + importing bookmark book_02de + $ hg -R other debugobsolete + 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} pull over http $ hg -R main serve -p $HGPORT -d --pid-file=main.pid -E main-error.log $ cat main.pid >> $DAEMON_PIDS - $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 + $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc pulling from http://localhost:$HGPORT/ searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) + 1 new obsolescence markers + updating bookmark book_42cc (run 'hg heads .' to see heads, 'hg merge' to merge) + importing bookmark book_42cc $ cat main-error.log + $ hg -R other debugobsolete + 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} push over ssh - $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 + $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd 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: 1 new obsolescence markers + updating bookmark book_5fdd + exporting bookmark book_5fdd $ hg -R other log -G - o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> C + o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C | - o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> B + o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B | - | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> H + | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H | | - | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> G + | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G | |/| - | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F + | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F |/ / - | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E + | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ - o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A + $ hg -R other debugobsolete + 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} push over http @@ -901,34 +980,45 @@ $ cat other.pid >> $DAEMON_PIDS $ hg -R main phase --public 32af7686d403 - $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 + $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af 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: 1 new obsolescence markers + updating bookmark book_32af + exporting bookmark book_32af $ cat other-error.log Check final content. $ hg -R other log -G - o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> D + o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D | - o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> C + o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C | - o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> B + o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B | - | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> H + | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H | | - | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> G + | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G | |/| - | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F + | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F |/ / - | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E + | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ - o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A + $ hg -R other debugobsolete + 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} Error Handling ============== @@ -964,7 +1054,8 @@ > raise util.Abort('Abandon ship!', hint="don't panic") > > def uisetup(ui): - > exchange.bundle2partsgenerators.insert(0, _pushbundle2failpart) + > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart + > exchange.b2partsgenorder.insert(0, 'failpart') > > EOF
--- a/tests/test-casecollision-merge.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-casecollision-merge.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,4 @@ -run only on case-insensitive filesystems - - $ "$TESTDIR/hghave" icasefs || exit 80 +#require icasefs ################################ test for branch merging
--- a/tests/test-casecollision.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-casecollision.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,4 @@ -run only on case-sensitive filesystems - - $ "$TESTDIR/hghave" no-icasefs || exit 80 +#require no-icasefs test file addition with colliding case
--- a/tests/test-casefolding.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-casefolding.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" icasefs || exit 80 +#require icasefs $ hg debugfs | grep 'case-sensitive:' case-sensitive: no
--- a/tests/test-changelog-exec.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-changelog-exec.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,9 +1,9 @@ +#require execbit + b51a8138292a introduced a regression where we would mention in the changelog executable files added by the second parent of a merge. Test that that doesn't happen anymore - $ "$TESTDIR/hghave" execbit || exit 80 - $ hg init repo $ cd repo $ echo foo > foo
--- a/tests/test-check-code-hg.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-check-code-hg.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ -#if test-repo +#require test-repo $ check_code="$TESTDIR"/../contrib/check-code.py $ cd "$TESTDIR"/.. @@ -13,5 +13,3 @@ Skipping mercurial/httpclient/__init__.py it has no-che?k-code (glob) Skipping mercurial/httpclient/_readers.py it has no-che?k-code (glob) Skipping mercurial/httpclient/socketutil.py it has no-che?k-code (glob) - -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-check-commit-hg.t Sat Sep 27 14:47:52 2014 -0500 @@ -0,0 +1,26 @@ +#require test-repo + +Enable obsolescence to avoid the warning issue when obsmarker are found + + $ cat > obs.py << EOF + > import mercurial.obsolete + > mercurial.obsolete._enabled = True + > EOF + $ echo '[extensions]' >> $HGRCPATH + $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH + +Go back in the hg repo + + $ cd $TESTDIR/.. + + $ for node in `hg log --rev 'draft() and ::.' --template '{node|short}\n'`; do + > hg export $node | contrib/check-commit > ${TESTTMP}/check-commit.out + > if [ $? -ne 0 ]; then + > echo "Revision $node does not comply to commit message rules" + > echo '------------------------------------------------------' + > cat ${TESTTMP}/check-commit.out + > echo + > fi + > done + +
--- a/tests/test-check-pyflakes.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-check-pyflakes.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ -#if test-repo pyflakes +#require test-repo pyflakes $ cd "`dirname "$TESTDIR"`" @@ -7,16 +7,6 @@ $ hg locate 'set:**.py or grep("^!#.*python")' 2>/dev/null \ > | xargs pyflakes 2>/dev/null | "$TESTDIR/filterpyflakes.py" - contrib/win32/hgwebdir_wsgi.py:*: 'win32traceutil' imported but unused (glob) - setup.py:*: 'sha' imported but unused (glob) - setup.py:*: 'zlib' imported but unused (glob) - setup.py:*: 'bz2' imported but unused (glob) - setup.py:*: 'py2exe' imported but unused (glob) - tests/hghave.py:*: '_lsprof' imported but unused (glob) - tests/hghave.py:*: 'publish_cmdline' imported but unused (glob) - tests/hghave.py:*: 'pygments' imported but unused (glob) - tests/hghave.py:*: 'ssl' imported but unused (glob) - contrib/win32/hgwebdir_wsgi.py:93: 'from isapi.install import *' used; unable to detect undefined names (glob) tests/filterpyflakes.py:58: undefined name 'undefinedname' -#endif +
--- a/tests/test-clone-cgi.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-clone-cgi.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" no-msys || exit 80 # MSYS will translate web paths as if they were file paths +#require no-msys # MSYS will translate web paths as if they were file paths This is a test of the wire protocol over CGI-based hgweb. initialize repository
--- a/tests/test-clone.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-clone.t Sat Sep 27 14:47:52 2014 -0500 @@ -25,12 +25,25 @@ .hg/store/data/b.d .hg/store/data/b.i +Trigger branchcache creation: + + $ hg branches + default 10:a7949464abda + $ ls .hg/cache + branch2-served + Default operation: $ hg clone . ../b updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd ../b + +Ensure branchcache got copied over: + + $ ls .hg/cache + branch2-served + $ cat a a $ hg verify @@ -58,6 +71,12 @@ listing keys for "bookmarks" #endif $ cd ../c + +Ensure branchcache got copied over: + + $ ls .hg/cache + branch2-served + $ cat a 2>/dev/null || echo "a not present" a not present $ hg verify
--- a/tests/test-command-template.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-command-template.t Sat Sep 27 14:47:52 2014 -0500 @@ -468,6 +468,350 @@ </log> +Test JSON style: + + $ hg log -k nosuch -Tjson + [] + + $ hg log -qr . -Tjson + [ + { + "rev": 8, + "node": "95c24699272ef57d062b8bccc32c878bf841784a" + } + ] + + $ hg log -vpr . -Tjson --stat + [ + { + "rev": 8, + "node": "95c24699272ef57d062b8bccc32c878bf841784a", + "branch": "default", + "phase": "draft", + "user": "test", + "date": [1577872860, 0], + "desc": "third", + "bookmarks": [], + "tags": ["tip"], + "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"], + "files": ["fourth", "second", "third"], + "diffstat": " fourth | 1 +\n second | 1 -\n third | 1 +\n 3 files changed, 2 insertions(+), 1 deletions(-)\n", + "diff": "diff -r 29114dbae42b -r 95c24699272e fourth\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/fourth\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+second\ndiff -r 29114dbae42b -r 95c24699272e second\n--- a/second\tMon Jan 12 13:46:40 1970 +0000\n+++ /dev/null\tThu Jan 01 00:00:00 1970 +0000\n@@ -1,1 +0,0 @@\n-second\ndiff -r 29114dbae42b -r 95c24699272e third\n--- /dev/null\tThu Jan 01 00:00:00 1970 +0000\n+++ b/third\tWed Jan 01 10:01:00 2020 +0000\n@@ -0,0 +1,1 @@\n+third\n" + } + ] + + $ hg log -T json + [ + { + "rev": 8, + "node": "95c24699272ef57d062b8bccc32c878bf841784a", + "branch": "default", + "phase": "draft", + "user": "test", + "date": [1577872860, 0], + "desc": "third", + "bookmarks": [], + "tags": ["tip"], + "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"] + }, + { + "rev": 7, + "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453", + "branch": "default", + "phase": "draft", + "user": "User Name <user@hostname>", + "date": [1000000, 0], + "desc": "second", + "bookmarks": [], + "tags": [], + "parents": ["0000000000000000000000000000000000000000"] + }, + { + "rev": 6, + "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b", + "branch": "default", + "phase": "draft", + "user": "person", + "date": [1500001, 0], + "desc": "merge", + "bookmarks": [], + "tags": [], + "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"] + }, + { + "rev": 5, + "node": "13207e5a10d9fd28ec424934298e176197f2c67f", + "branch": "default", + "phase": "draft", + "user": "person", + "date": [1500000, 0], + "desc": "new head", + "bookmarks": [], + "tags": [], + "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"] + }, + { + "rev": 4, + "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74", + "branch": "foo", + "phase": "draft", + "user": "person", + "date": [1400000, 0], + "desc": "new branch", + "bookmarks": [], + "tags": [], + "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"] + }, + { + "rev": 3, + "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47", + "branch": "default", + "phase": "draft", + "user": "person", + "date": [1300000, 0], + "desc": "no user, no domain", + "bookmarks": [], + "tags": [], + "parents": ["97054abb4ab824450e9164180baf491ae0078465"] + }, + { + "rev": 2, + "node": "97054abb4ab824450e9164180baf491ae0078465", + "branch": "default", + "phase": "draft", + "user": "other@place", + "date": [1200000, 0], + "desc": "no person", + "bookmarks": [], + "tags": [], + "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"] + }, + { + "rev": 1, + "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965", + "branch": "default", + "phase": "draft", + "user": "A. N. Other <other@place>", + "date": [1100000, 0], + "desc": "other 1\nother 2\n\nother 3", + "bookmarks": [], + "tags": [], + "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"] + }, + { + "rev": 0, + "node": "1e4e1b8f71e05681d422154f5421e385fec3454f", + "branch": "default", + "phase": "draft", + "user": "User Name <user@hostname>", + "date": [1000000, 0], + "desc": "line 1\nline 2", + "bookmarks": [], + "tags": [], + "parents": ["0000000000000000000000000000000000000000"] + } + ] + + $ hg heads -v -Tjson + [ + { + "rev": 8, + "node": "95c24699272ef57d062b8bccc32c878bf841784a", + "branch": "default", + "phase": "draft", + "user": "test", + "date": [1577872860, 0], + "desc": "third", + "bookmarks": [], + "tags": ["tip"], + "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"], + "files": ["fourth", "second", "third"] + }, + { + "rev": 6, + "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b", + "branch": "default", + "phase": "draft", + "user": "person", + "date": [1500001, 0], + "desc": "merge", + "bookmarks": [], + "tags": [], + "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"], + "files": [] + }, + { + "rev": 4, + "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74", + "branch": "foo", + "phase": "draft", + "user": "person", + "date": [1400000, 0], + "desc": "new branch", + "bookmarks": [], + "tags": [], + "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"], + "files": [] + } + ] + + $ hg log --debug -Tjson + [ + { + "rev": 8, + "node": "95c24699272ef57d062b8bccc32c878bf841784a", + "branch": "default", + "phase": "draft", + "user": "test", + "date": [1577872860, 0], + "desc": "third", + "bookmarks": [], + "tags": ["tip"], + "parents": ["29114dbae42b9f078cf2714dbe3a86bba8ec7453"], + "manifest": "94961b75a2da554b4df6fb599e5bfc7d48de0c64", + "extra": {"branch": "default"}, + "modified": [], + "added": ["second"], + "removed": ["fourth", "third"] + }, + { + "rev": 7, + "node": "29114dbae42b9f078cf2714dbe3a86bba8ec7453", + "branch": "default", + "phase": "draft", + "user": "User Name <user@hostname>", + "date": [1000000, 0], + "desc": "second", + "bookmarks": [], + "tags": [], + "parents": ["0000000000000000000000000000000000000000"], + "manifest": "f2dbc354b94e5ec0b4f10680ee0cee816101d0bf", + "extra": {"branch": "default"}, + "modified": [], + "added": [], + "removed": ["second"] + }, + { + "rev": 6, + "node": "d41e714fe50d9e4a5f11b4d595d543481b5f980b", + "branch": "default", + "phase": "draft", + "user": "person", + "date": [1500001, 0], + "desc": "merge", + "bookmarks": [], + "tags": [], + "parents": ["13207e5a10d9fd28ec424934298e176197f2c67f", "bbe44766e73d5f11ed2177f1838de10c53ef3e74"], + "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216", + "extra": {"branch": "default"}, + "modified": [], + "added": [], + "removed": [] + }, + { + "rev": 5, + "node": "13207e5a10d9fd28ec424934298e176197f2c67f", + "branch": "default", + "phase": "draft", + "user": "person", + "date": [1500000, 0], + "desc": "new head", + "bookmarks": [], + "tags": [], + "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"], + "manifest": "4dc3def4f9b4c6e8de820f6ee74737f91e96a216", + "extra": {"branch": "default"}, + "modified": [], + "added": [], + "removed": ["d"] + }, + { + "rev": 4, + "node": "bbe44766e73d5f11ed2177f1838de10c53ef3e74", + "branch": "foo", + "phase": "draft", + "user": "person", + "date": [1400000, 0], + "desc": "new branch", + "bookmarks": [], + "tags": [], + "parents": ["10e46f2dcbf4823578cf180f33ecf0b957964c47"], + "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc", + "extra": {"branch": "foo"}, + "modified": [], + "added": [], + "removed": [] + }, + { + "rev": 3, + "node": "10e46f2dcbf4823578cf180f33ecf0b957964c47", + "branch": "default", + "phase": "draft", + "user": "person", + "date": [1300000, 0], + "desc": "no user, no domain", + "bookmarks": [], + "tags": [], + "parents": ["97054abb4ab824450e9164180baf491ae0078465"], + "manifest": "cb5a1327723bada42f117e4c55a303246eaf9ccc", + "extra": {"branch": "default"}, + "modified": ["c"], + "added": [], + "removed": [] + }, + { + "rev": 2, + "node": "97054abb4ab824450e9164180baf491ae0078465", + "branch": "default", + "phase": "draft", + "user": "other@place", + "date": [1200000, 0], + "desc": "no person", + "bookmarks": [], + "tags": [], + "parents": ["b608e9d1a3f0273ccf70fb85fd6866b3482bf965"], + "manifest": "6e0e82995c35d0d57a52aca8da4e56139e06b4b1", + "extra": {"branch": "default"}, + "modified": [], + "added": [], + "removed": ["c"] + }, + { + "rev": 1, + "node": "b608e9d1a3f0273ccf70fb85fd6866b3482bf965", + "branch": "default", + "phase": "draft", + "user": "A. N. Other <other@place>", + "date": [1100000, 0], + "desc": "other 1\nother 2\n\nother 3", + "bookmarks": [], + "tags": [], + "parents": ["1e4e1b8f71e05681d422154f5421e385fec3454f"], + "manifest": "4e8d705b1e53e3f9375e0e60dc7b525d8211fe55", + "extra": {"branch": "default"}, + "modified": [], + "added": [], + "removed": ["b"] + }, + { + "rev": 0, + "node": "1e4e1b8f71e05681d422154f5421e385fec3454f", + "branch": "default", + "phase": "draft", + "user": "User Name <user@hostname>", + "date": [1000000, 0], + "desc": "line 1\nline 2", + "bookmarks": [], + "tags": [], + "parents": ["0000000000000000000000000000000000000000"], + "manifest": "a0c8bcbbb45c63b90b70ad007bf38961f64f2af0", + "extra": {"branch": "default"}, + "modified": [], + "added": [], + "removed": ["a"] + } + ] + Error if style not readable: #if unix-permissions no-root @@ -1450,6 +1794,61 @@ hg: parse error: unknown function 'foo' [255] +Test diff function: + + $ hg diff -c 8 + diff -r 29114dbae42b -r 95c24699272e fourth + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + +++ b/fourth Wed Jan 01 10:01:00 2020 +0000 + @@ -0,0 +1,1 @@ + +second + diff -r 29114dbae42b -r 95c24699272e second + --- a/second Mon Jan 12 13:46:40 1970 +0000 + +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 + @@ -1,1 +0,0 @@ + -second + diff -r 29114dbae42b -r 95c24699272e third + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + +++ b/third Wed Jan 01 10:01:00 2020 +0000 + @@ -0,0 +1,1 @@ + +third + + $ hg log -r 8 -T "{diff()}" + diff -r 29114dbae42b -r 95c24699272e fourth + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + +++ b/fourth Wed Jan 01 10:01:00 2020 +0000 + @@ -0,0 +1,1 @@ + +second + diff -r 29114dbae42b -r 95c24699272e second + --- a/second Mon Jan 12 13:46:40 1970 +0000 + +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 + @@ -1,1 +0,0 @@ + -second + diff -r 29114dbae42b -r 95c24699272e third + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + +++ b/third Wed Jan 01 10:01:00 2020 +0000 + @@ -0,0 +1,1 @@ + +third + + $ hg log -r 8 -T "{diff('glob:f*')}" + diff -r 29114dbae42b -r 95c24699272e fourth + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + +++ b/fourth Wed Jan 01 10:01:00 2020 +0000 + @@ -0,0 +1,1 @@ + +second + + $ hg log -r 8 -T "{diff('', 'glob:f*')}" + diff -r 29114dbae42b -r 95c24699272e second + --- a/second Mon Jan 12 13:46:40 1970 +0000 + +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 + @@ -1,1 +0,0 @@ + -second + diff -r 29114dbae42b -r 95c24699272e third + --- /dev/null Thu Jan 01 00:00:00 1970 +0000 + +++ b/third Wed Jan 01 10:01:00 2020 +0000 + @@ -0,0 +1,1 @@ + +third + $ cd .. @@ -1834,6 +2233,15 @@ 1 Parents: 0 0 Parents: + $ cat >> .hg/hgrc <<EOF + > [revsetalias] + > myparents(\$1) = parents(\$1) + > EOF + $ hg log --template '{rev} Parents: {revset("myparents(%s)", rev)}\n' + 2 Parents: 1 + 1 Parents: 0 + 0 Parents: + $ hg log --template 'Rev: {rev}\n{revset("::%s", rev) % "Ancestor: {revision}\n"}\n' Rev: 2 Ancestor: 0
--- a/tests/test-commandserver.py.out Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-commandserver.py.out Sat Sep 27 14:47:52 2014 -0500 @@ -34,7 +34,7 @@ summary summarize working directory state update update working directory (or switch revisions) -use "hg help" for the full list of commands or "hg -v" for details +(use "hg help" for the full list of commands or "hg -v" for details) runcommand id --quiet 000000000000 runcommand id
--- a/tests/test-commit-amend.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-commit-amend.t Sat Sep 27 14:47:52 2014 -0500 @@ -145,7 +145,12 @@ Test -u/-d: - $ hg ci --amend -u foo -d '1 0' + $ cat > .hg/checkeditform.sh <<EOF + > env | grep HGEDITFORM + > true + > EOF + $ HGEDITOR="sh .hg/checkeditform.sh" hg ci --amend -u foo -d '1 0' + HGEDITFORM=commit.amend.normal saved backup bundle to $TESTTMP/.hg/strip-backup/1cd866679df8-amend-backup.hg (glob) $ echo a >> a $ hg ci --amend -u foo -d '1 0' @@ -619,7 +624,8 @@ zz renamed from z:69a1b67522704ec122181c0890bd16e9d3e7516a $ hg debugrename cc cc not renamed - $ hg ci --amend -m 'merge bar (amend message)' + $ HGEDITOR="sh .hg/checkeditform.sh" hg ci --amend -m 'merge bar (amend message)' --edit + HGEDITFORM=commit.amend.merge $ hg log --config diff.git=1 -pr . changeset: 24:832b50f2c271 tag: tip
--- a/tests/test-commit.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-commit.t Sat Sep 27 14:47:52 2014 -0500 @@ -4,7 +4,12 @@ $ cd test $ echo foo > foo $ hg add foo - $ HGEDITOR=true hg commit -m "" + $ cat > $TESTTMP/checkeditform.sh <<EOF + > env | grep HGEDITFORM + > true + > EOF + $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg commit -m "" + HGEDITFORM=commit.normal.normal abort: empty commit message [255] $ hg commit -d '0 0' -m commit-1 @@ -277,7 +282,8 @@ should succeed - $ hg ci -mmerge + $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg ci -mmerge --edit + HGEDITFORM=commit.normal.merge $ cd .. @@ -359,6 +365,20 @@ $ cat >> .hg/hgrc <<EOF > [committemplate] + > changeset.commit.normal = HG: this is "commit.normal" template + > HG: {extramsg} + > {if(currentbookmark, + > "HG: bookmark '{currentbookmark}' 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", + > "HG: no bookmark is activated\n")}{subrepos % + > "HG: subrepo '{subrepo}' is changed\n"} + > > changeset = HG: this is customized commit template > HG: {extramsg} > {if(currentbookmark, @@ -373,7 +393,7 @@ $ echo 'sub2 = sub2' >> .hgsub $ HGEDITOR=cat hg commit -S -q - HG: this is customized commit template + HG: this is "commit.normal" template HG: Leave message empty to abort commit. HG: bookmark 'currentbookmark' is activated HG: subrepo 'sub' is changed @@ -381,9 +401,28 @@ abort: empty commit message [255] + $ cat >> .hg/hgrc <<EOF + > [committemplate] + > changeset.commit.normal = + > # now, "changeset.commit" should be chosen for "hg commit" + > EOF + $ hg bookmark --inactive currentbookmark $ hg forget .hgsub $ HGEDITOR=cat hg commit -q + HG: this is "commit" template + HG: Leave message empty to abort commit. + HG: no bookmark is activated + abort: empty commit message + [255] + + $ cat >> .hg/hgrc <<EOF + > [committemplate] + > changeset.commit = + > # now, "changeset" should be chosen for "hg commit" + > EOF + + $ HGEDITOR=cat hg commit -q HG: this is customized commit template HG: Leave message empty to abort commit. HG: no bookmark is activated
--- a/tests/test-completion.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-completion.t Sat Sep 27 14:47:52 2014 -0500 @@ -17,6 +17,7 @@ copy diff export + files forget graft grep @@ -88,6 +89,7 @@ debuginstall debugknown debuglabelcomplete + debuglocks debugobsolete debugpathcomplete debugpushkey @@ -197,7 +199,7 @@ Show all commands + options $ hg debugcommands add: include, exclude, subrepos, dry-run - annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude + annotate: rev, follow, no-follow, text, user, file, date, number, changeset, line-number, ignore-all-space, ignore-space-change, ignore-blank-lines, include, exclude, template clone: noupdate, updaterev, rev, branch, pull, uncompressed, ssh, remotecmd, insecure commit: addremove, close-branch, amend, secret, edit, include, exclude, message, logfile, date, user, subrepos diff: rev, change, text, git, nodates, show-function, reverse, ignore-all-space, ignore-space-change, ignore-blank-lines, unified, stat, include, exclude, subrepos @@ -210,7 +212,7 @@ push: force, rev, bookmark, branch, new-branch, ssh, remotecmd, insecure remove: after, force, include, exclude serve: accesslog, daemon, daemon-pipefds, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate - status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos + status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template summary: remote update: clean, check, date, rev, tool addremove: similarity, include, exclude, dry-run @@ -244,7 +246,8 @@ debuginstall: debugknown: debuglabelcomplete: - debugobsolete: flags, date, user + debuglocks: force-lock, force-wlock + debugobsolete: flags, record-parents, rev, date, user debugpathcomplete: full, normal, added, removed debugpushkey: debugpvec: @@ -257,7 +260,8 @@ debugsuccessorssets: debugwalk: include, exclude debugwireargs: three, four, five, ssh, remotecmd, insecure - graft: rev, continue, edit, log, currentdate, currentuser, date, user, tool, dry-run + files: rev, print0, include, exclude, template + graft: rev, continue, edit, log, force, currentdate, currentuser, date, user, tool, dry-run grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, include, exclude heads: rev, topo, active, closed, style, template help: extension, command, keyword @@ -265,7 +269,7 @@ import: strip, base, edit, force, no-commit, bypass, partial, exact, import-branch, message, logfile, date, user, similarity incoming: force, newest-first, bundle, rev, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos locate: rev, print0, fullpath, include, exclude - manifest: rev, all + manifest: rev, all, template outgoing: force, rev, newest-first, bookmarks, branch, patch, git, limit, no-merges, stat, graph, style, template, ssh, remotecmd, insecure, subrepos parents: rev, style, template paths: @@ -277,7 +281,7 @@ rollback: dry-run, force root: tag: force, local, rev, remove, edit, message, date, user - tags: + tags: template tip: patch, git, style, template unbundle: update verify:
--- a/tests/test-config.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-config.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,47 @@ hide outer repo $ hg init +Invalid syntax: no value + + $ cat > .hg/hgrc << EOF + > novaluekey + > EOF + $ hg showconfig + hg: parse error at $TESTTMP/.hg/hgrc:1: novaluekey + [255] + +Invalid syntax: no key + + $ cat > .hg/hgrc << EOF + > =nokeyvalue + > EOF + $ hg showconfig + hg: parse error at $TESTTMP/.hg/hgrc:1: =nokeyvalue + [255] + +Test hint about invalid syntax from leading white space + + $ cat > .hg/hgrc << EOF + > key=value + > EOF + $ hg showconfig + hg: parse error at $TESTTMP/.hg/hgrc:1: key=value + unexpected leading whitespace + [255] + + $ cat > .hg/hgrc << EOF + > [section] + > key=value + > EOF + $ hg showconfig + hg: parse error at $TESTTMP/.hg/hgrc:1: [section] + unexpected leading whitespace + [255] + +Reset hgrc + + $ echo > .hg/hgrc + Test case sensitive configuration $ echo '[Section]' >> $HGRCPATH
--- a/tests/test-conflict.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-conflict.t Sat Sep 27 14:47:52 2014 -0500 @@ -198,3 +198,37 @@ 5 >>>>>>> other Hop we are done. + +internal:merge3 + + $ hg up -q --clean . + + $ hg merge 1 --tool internal:merge3 + merging a + warning: conflicts during merge. + merging a incomplete! (edit conflicts, then use 'hg resolve --mark') + 0 files updated, 0 files merged, 0 files removed, 1 files unresolved + use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon + [1] + $ cat a + Small Mathematical Series. + <<<<<<< local + 1 + 2 + 3 + 6 + 8 + ||||||| base + One + Two + Three + Four + Five + ======= + 1 + 2 + 3 + 4 + 5 + >>>>>>> other + Hop we are done.
--- a/tests/test-contrib.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-contrib.t Sat Sep 27 14:47:52 2014 -0500 @@ -143,23 +143,11 @@ $ echo not other >> conflict-local $ echo end >> conflict-local $ echo end >> conflict-other + $ python simplemerge -p conflict-local base conflict-other base <<<<<<< conflict-local not other - ======= - other - >>>>>>> conflict-other - end - warning: conflicts during merge. - [1] - ---no-minimal - - $ python simplemerge -p --no-minimal conflict-local base conflict-other - base - <<<<<<< conflict-local - not other end ======= other @@ -174,10 +162,11 @@ base <<<<<<< foo not other + end ======= other + end >>>>>>> conflict-other - end warning: conflicts during merge. [1] @@ -187,17 +176,33 @@ base <<<<<<< foo not other + end ======= other + end >>>>>>> bar + warning: conflicts during merge. + [1] + +3 labels + + $ python simplemerge -p -L foo -L bar -L base conflict-local base conflict-other + base + <<<<<<< foo + not other end + ||||||| base + ======= + other + end + >>>>>>> bar warning: conflicts during merge. [1] too many labels - $ python simplemerge -p -L foo -L bar -L baz conflict-local base conflict-other - abort: can only specify two labels. + $ python simplemerge -p -L foo -L bar -L baz -L buz conflict-local base conflict-other + abort: can only specify three labels. [255] binary file @@ -231,7 +236,7 @@ -L --label labels to use on conflict markers -a --text treat all files as text -p --print print results instead of overwriting LOCAL - --no-minimal do not try to minimize conflict regions + --no-minimal no effect (DEPRECATED) -h --help display help and exit -q --quiet suppress output @@ -251,7 +256,7 @@ -L --label labels to use on conflict markers -a --text treat all files as text -p --print print results instead of overwriting LOCAL - --no-minimal do not try to minimize conflict regions + --no-minimal no effect (DEPRECATED) -h --help display help and exit -q --quiet suppress output [1] @@ -272,7 +277,7 @@ -L --label labels to use on conflict markers -a --text treat all files as text -p --print print results instead of overwriting LOCAL - --no-minimal do not try to minimize conflict regions + --no-minimal no effect (DEPRECATED) -h --help display help and exit -q --quiet suppress output [1]
--- a/tests/test-convert-baz.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-baz.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" baz symlink || exit 80 +#require baz symlink $ baz my-id "mercurial <mercurial@selenic.com>"
--- a/tests/test-convert-bzr-114.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-bzr-114.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,5 @@ +#require bzr114 - $ "$TESTDIR/hghave" bzr114 || exit 80 $ . "$TESTDIR/bzr-definitions" The file/directory replacement can only be reproduced on
--- a/tests/test-convert-cvs-branch.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-cvs-branch.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,7 +1,8 @@ +#require cvs + This is http://mercurial.selenic.com/bts/issue1148 and http://mercurial.selenic.com/bts/issue1447 - $ "$TESTDIR/hghave" cvs || exit 80 $ cvscall() > { > cvs -f "$@" > /dev/null
--- a/tests/test-convert-cvs-detectmerge.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-cvs-detectmerge.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,8 +1,9 @@ +#require cvs + Test config convert.cvsps.mergefrom config setting. (Should test similar mergeto feature, but I don't understand it yet.) Requires builtin cvsps. - $ "$TESTDIR/hghave" cvs || exit 80 $ CVSROOT=`pwd`/cvsrepo $ export CVSROOT
--- a/tests/test-convert-cvs-synthetic.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-cvs-synthetic.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,7 @@ +#require cvs112 + This feature requires use of builtin cvsps! - $ "$TESTDIR/hghave" cvs112 || exit 80 $ echo "[extensions]" >> $HGRCPATH $ echo "convert = " >> $HGRCPATH
--- a/tests/test-convert-cvs.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-cvs.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,5 @@ +#require cvs - $ "$TESTDIR/hghave" cvs || exit 80 $ cvscall() > { > cvs -f "$@"
--- a/tests/test-convert-cvsnt-mergepoints.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-cvsnt-mergepoints.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,5 @@ +#require cvs - $ "$TESTDIR/hghave" cvs || exit 80 $ filterpath() > { > eval "$@" | sed "s:$CVSROOT:*REPO*:g"
--- a/tests/test-convert-darcs.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-darcs.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,5 @@ +#require darcs - $ "$TESTDIR/hghave" darcs || exit 80 $ echo "[extensions]" >> $HGRCPATH $ echo "convert=" >> $HGRCPATH $ DARCS_EMAIL='test@example.org'; export DARCS_EMAIL
--- a/tests/test-convert-git.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-git.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,5 @@ +#require git - $ "$TESTDIR/hghave" git || exit 80 $ echo "[core]" >> $HOME/.gitconfig $ echo "autocrlf = false" >> $HOME/.gitconfig $ echo "[core]" >> $HOME/.gitconfig @@ -33,8 +33,7 @@ $ git add a d $ commit -a -m t1 -Remove the directory, then try to replace it with a file -(issue 754) +Remove the directory, then try to replace it with a file (issue754) $ git rm -f d/b rm 'd/b' @@ -52,7 +51,43 @@ $ git pull --no-commit . other > /dev/null 2>/dev/null $ commit -m 'Merge branch other' $ cd .. - $ hg convert --datesort git-repo + $ hg convert --config extensions.progress= --config progress.assume-tty=1 \ + > --config progress.delay=0 --config progress.changedelay=0 \ + > --config progress.refresh=0 --config progress.width=60 \ + > --datesort git-repo + \r (no-eol) (esc) + scanning [======> ] 1/6\r (no-eol) (esc) + scanning [=============> ] 2/6\r (no-eol) (esc) + scanning [=====================> ] 3/6\r (no-eol) (esc) + scanning [============================> ] 4/6\r (no-eol) (esc) + scanning [===================================> ] 5/6\r (no-eol) (esc) + scanning [===========================================>] 6/6\r (no-eol) (esc) + \r (no-eol) (esc) + \r (no-eol) (esc) + converting [ ] 0/6\r (no-eol) (esc) + getting files [==================> ] 1/2\r (no-eol) (esc) + getting files [======================================>] 2/2\r (no-eol) (esc) + \r (no-eol) (esc) + \r (no-eol) (esc) + converting [======> ] 1/6\r (no-eol) (esc) + getting files [======================================>] 1/1\r (no-eol) (esc) + \r (no-eol) (esc) + \r (no-eol) (esc) + converting [=============> ] 2/6\r (no-eol) (esc) + getting files [======================================>] 1/1\r (no-eol) (esc) + \r (no-eol) (esc) + \r (no-eol) (esc) + converting [====================> ] 3/6\r (no-eol) (esc) + getting files [======================================>] 1/1\r (no-eol) (esc) + \r (no-eol) (esc) + \r (no-eol) (esc) + converting [===========================> ] 4/6\r (no-eol) (esc) + getting files [======================================>] 1/1\r (no-eol) (esc) + \r (no-eol) (esc) + \r (no-eol) (esc) + converting [==================================> ] 5/6\r (no-eol) (esc) + getting files [======================================>] 1/1\r (no-eol) (esc) + \r (no-eol) (esc) assuming destination git-repo-hg initializing destination git-repo-hg repository scanning source... @@ -206,8 +241,59 @@ 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux -test binary conversion (issue 1359) +test importing git renames and copies + + $ cd git-repo2 + $ git mv foo foo-renamed +since bar is not touched in this commit, this copy will not be detected + $ cp bar bar-copied + $ cp baz baz-copied + $ cp baz baz-copied2 + $ echo baz2 >> baz + $ git add bar-copied baz-copied baz-copied2 + $ commit -a -m 'rename and copy' + $ cd .. + +input validation + $ hg convert --config convert.git.similarity=foo --datesort git-repo2 fullrepo + abort: convert.git.similarity is not an integer ('foo') + [255] + $ hg convert --config convert.git.similarity=-1 --datesort git-repo2 fullrepo + abort: similarity must be between 0 and 100 + [255] + $ hg convert --config convert.git.similarity=101 --datesort git-repo2 fullrepo + abort: similarity must be between 0 and 100 + [255] + $ hg -q convert --config convert.git.similarity=100 --datesort git-repo2 fullrepo + $ hg -R fullrepo status -C --change master + M baz + A bar-copied + A baz-copied + baz + A baz-copied2 + baz + A foo-renamed + foo + R foo + + $ cd git-repo2 + $ echo bar2 >> bar + $ commit -a -m 'change bar' + $ cp bar bar-copied2 + $ git add bar-copied2 + $ commit -a -m 'copy with no changes' + $ cd .. + + $ hg -q convert --config convert.git.similarity=100 \ + > --config convert.git.findcopiesharder=1 --datesort git-repo2 fullrepo + $ hg -R fullrepo status -C --change master + A bar-copied2 + bar + +test binary conversion (issue1359) + + $ count=19 $ mkdir git-repo3 $ cd git-repo3 $ git init-db >/dev/null 2>/dev/null @@ -363,6 +449,29 @@ $ cd ../.. +make sure rename detection doesn't break removing and adding gitmodules + + $ cd git-repo6 + $ git mv .gitmodules .gitmodules-renamed + $ commit -a -m 'rename .gitmodules' + $ git mv .gitmodules-renamed .gitmodules + $ commit -a -m 'rename .gitmodules back' + $ cd .. + + $ hg --config convert.git.similarity=100 convert -q git-repo6 git-repo6-hg + $ hg -R git-repo6-hg log -r 'tip^' -T "{desc|firstline}\n" + rename .gitmodules + $ hg -R git-repo6-hg status -C --change 'tip^' + A .gitmodules-renamed + R .hgsub + R .hgsubstate + $ hg -R git-repo6-hg log -r tip -T "{desc|firstline}\n" + rename .gitmodules back + $ hg -R git-repo6-hg status -C --change tip + A .hgsub + A .hgsubstate + R .gitmodules-renamed + convert the revision removing '.gitmodules' itself (and related submodules)
--- a/tests/test-convert-hg-sink.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-hg-sink.t Sat Sep 27 14:47:52 2014 -0500 @@ -537,3 +537,16 @@ | o 0 0 (a-only f) +Convert with --full adds and removes files that didn't change + + $ echo f >> 0/f + $ hg -R 0 ci -m "f" + $ hg convert --filemap filemap-b --full 0 a --config convert.hg.revs=1:: + scanning source... + sorting... + converting... + 0 f + $ hg -R a status --change tip + M f + A b-only + R a-only
--- a/tests/test-convert-hg-svn.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-hg-svn.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,5 @@ +#require svn svn-bindings - $ "$TESTDIR/hghave" svn svn-bindings || exit 80 $ echo "[extensions]" >> $HGRCPATH $ echo "convert = " >> $HGRCPATH $ echo "mq = " >> $HGRCPATH
--- a/tests/test-convert-mtn.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-mtn.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,4 @@ - - $ "$TESTDIR/hghave" mtn || exit 80 +#require mtn Monotone directory is called .monotone on *nix and monotone on Windows.
--- a/tests/test-convert-p4-filetypes.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-p4-filetypes.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" p4 execbit symlink || exit 80 +#require p4 execbit symlink $ echo "[extensions]" >> $HGRCPATH $ echo "convert = " >> $HGRCPATH @@ -8,7 +8,7 @@ $ P4AUDIT=$P4ROOT/audit; export P4AUDIT $ P4JOURNAL=$P4ROOT/journal; export P4JOURNAL $ P4LOG=$P4ROOT/log; export P4LOG - $ P4PORT=localhost:16661; export P4PORT + $ P4PORT=localhost:$HGPORT; export P4PORT $ P4DEBUG=1; export P4DEBUG $ P4CHARSET=utf8; export P4CHARSET
--- a/tests/test-convert-p4.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-p4.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" p4 || exit 80 +#require p4 $ echo "[extensions]" >> $HGRCPATH $ echo "convert = " >> $HGRCPATH @@ -8,7 +8,7 @@ $ P4AUDIT=$P4ROOT/audit; export P4AUDIT $ P4JOURNAL=$P4ROOT/journal; export P4JOURNAL $ P4LOG=$P4ROOT/log; export P4LOG - $ P4PORT=localhost:16661; export P4PORT + $ P4PORT=localhost:$HGPORT; export P4PORT $ P4DEBUG=1; export P4DEBUG start the p4 server
--- a/tests/test-convert-svn-branches.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-svn-branches.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,4 @@ - - $ "$TESTDIR/hghave" svn svn-bindings || exit 80 +#require svn svn-bindings $ cat >> $HGRCPATH <<EOF > [extensions]
--- a/tests/test-convert-svn-encoding.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-svn-encoding.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,4 @@ - - $ "$TESTDIR/hghave" svn svn-bindings || exit 80 +#require svn svn-bindings $ cat >> $HGRCPATH <<EOF > [extensions] @@ -21,7 +20,7 @@ found branches at 'branches' found branch branch\xc3\xa9 at 5 (esc) found branch branch\xc3\xa9e at 6 (esc) - scanning: 1 revisions + scanning: 1/4 revisions (25.00%) reparent to file://*/svn-repo/trunk (glob) fetching revision log for "/trunk" from 4 to 0 parsing revision 4 (2 changes) @@ -31,23 +30,23 @@ no copyfrom path, don't know what to do. '/branches' is not under '/trunk', ignoring '/tags' is not under '/trunk', ignoring - scanning: 2 revisions + scanning: 2/4 revisions (50.00%) reparent to file://*/svn-repo/branches/branch%C3%A9 (glob) fetching revision log for "/branches/branch\xc3\xa9" from 5 to 0 (esc) parsing revision 5 (1 changes) reparent to file://*/svn-repo (glob) reparent to file://*/svn-repo/branches/branch%C3%A9 (glob) found parent of branch /branches/branch\xc3\xa9 at 4: /trunk (esc) - scanning: 3 revisions + scanning: 3/4 revisions (75.00%) reparent to file://*/svn-repo/branches/branch%C3%A9e (glob) fetching revision log for "/branches/branch\xc3\xa9e" from 6 to 0 (esc) parsing revision 6 (1 changes) reparent to file://*/svn-repo (glob) reparent to file://*/svn-repo/branches/branch%C3%A9e (glob) found parent of branch /branches/branch\xc3\xa9e at 5: /branches/branch\xc3\xa9 (esc) - scanning: 4 revisions - scanning: 5 revisions - scanning: 6 revisions + scanning: 4/4 revisions (100.00%) + scanning: 5/4 revisions (125.00%) + scanning: 6/4 revisions (150.00%) sorting... converting... 5 init projA
--- a/tests/test-convert-svn-move.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-svn-move.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,4 @@ - - $ "$TESTDIR/hghave" svn svn-bindings || exit 80 +#require svn svn-bindings $ cat >> $HGRCPATH <<EOF > [extensions] @@ -150,7 +149,7 @@ $ hg up -qC default $ cd .. -Test convert progress bar' +Test convert progress bar $ cat >> $HGRCPATH <<EOF > [extensions] @@ -166,13 +165,13 @@ $ hg convert svn-repo hg-progress \r (no-eol) (esc) - scanning [ <=> ] 1\r (no-eol) (esc) - scanning [ <=> ] 2\r (no-eol) (esc) - scanning [ <=> ] 3\r (no-eol) (esc) - scanning [ <=> ] 4\r (no-eol) (esc) - scanning [ <=> ] 5\r (no-eol) (esc) - scanning [ <=> ] 6\r (no-eol) (esc) - scanning [ <=> ] 7\r (no-eol) (esc) + scanning [=====> ] 1/7\r (no-eol) (esc) + scanning [===========> ] 2/7\r (no-eol) (esc) + scanning [=================> ] 3/7\r (no-eol) (esc) + scanning [========================> ] 4/7\r (no-eol) (esc) + scanning [==============================> ] 5/7\r (no-eol) (esc) + scanning [====================================> ] 6/7\r (no-eol) (esc) + scanning [===========================================>] 7/7\r (no-eol) (esc) \r (no-eol) (esc) \r (no-eol) (esc) converting [ ] 0/7\r (no-eol) (esc)
--- a/tests/test-convert-svn-sink.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-svn-sink.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" svn13 || exit 80 +#require svn13 $ svnupanddisplay() > { @@ -247,6 +247,31 @@ #endif +Convert with --full adds and removes files that didn't change + + $ touch a/f + $ hg -R a ci -Aqmf + $ echo "rename c d" > filemap + $ hg convert -d svn a --filemap filemap --full + assuming destination a-hg + initializing svn working copy 'a-hg-wc' + scanning source... + sorting... + converting... + 0 f + $ svnupanddisplay a-hg-wc 1 + 9 9 test . + 9 9 test d + 9 9 test f + revision: 9 + author: test + msg: f + D /c + A /d + D /d1 + A /f + D /newlink + $ rm -rf a a-hg a-hg-wc
--- a/tests/test-convert-svn-source.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-svn-source.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,4 @@ - - $ "$TESTDIR/hghave" svn svn-bindings || exit 80 +#require svn svn-bindings $ cat >> $HGRCPATH <<EOF > [extensions] @@ -169,6 +168,27 @@ | o 0 second letter files: letter2.txt +Convert with --full adds and removes files that didn't change + + $ cd B + $ echo >> "letter .txt" + $ svn ci -m 'nothing' + Sending letter .txt + Transmitting file data . + Committed revision 9. + $ cd .. + + $ echo 'rename letter2.txt letter3.txt' > filemap + $ hg convert --filemap filemap --full "$SVNREPOURL/proj%20B/mytrunk" fmap + scanning source... + sorting... + converting... + 0 nothing + $ hg -R fmap st --change tip + A letter .txt + A letter3.txt + R letter2.txt + test invalid splicemap1 $ cat > splicemap <<EOF
--- a/tests/test-convert-svn-startrev.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-svn-startrev.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,4 @@ - - $ "$TESTDIR/hghave" svn svn-bindings || exit 80 +#require svn svn-bindings $ cat >> $HGRCPATH <<EOF > [extensions]
--- a/tests/test-convert-svn-tags.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-svn-tags.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,4 @@ - - $ "$TESTDIR/hghave" svn svn-bindings || exit 80 +#require svn svn-bindings $ cat >> $HGRCPATH <<EOF > [extensions]
--- a/tests/test-convert-tagsbranch-topology.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-tagsbranch-topology.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,5 @@ +#require git - $ "$TESTDIR/hghave" git || exit 80 $ echo "[core]" >> $HOME/.gitconfig $ echo "autocrlf = false" >> $HOME/.gitconfig $ echo "[core]" >> $HOME/.gitconfig
--- a/tests/test-convert-tla.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert-tla.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,5 @@ +#require tla symlink - $ "$TESTDIR/hghave" tla symlink || exit 80 $ tla my-id "mercurial <mercurial@selenic.com>" $ echo "[extensions]" >> $HGRCPATH $ echo "convert=" >> $HGRCPATH
--- a/tests/test-convert.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-convert.t Sat Sep 27 14:47:52 2014 -0500 @@ -91,6 +91,13 @@ directory if it is converted. To rename from a subdirectory into the root of the repository, use "." as the path to rename to. + "--full" will make sure the converted changesets contain exactly the right + files with the right content. It will make a full conversion of all files, + not just the ones that have changed. Files that already are correct will + not be changed. This can be used to apply filemap changes when converting + incrementally. This is currently only supported for Mercurial and + Subversion. + The splicemap is a file that allows insertion of synthetic history, letting you specify the parents of a revision. This is useful if you want to e.g. give a Subversion merge two parents, or graft two disconnected @@ -229,6 +236,30 @@ convert.svn.startrev specify start Subversion revision number. The default is 0. + Git Source + ########## + + The Git importer converts commits from all reachable branches (refs in + refs/heads) and remotes (refs in refs/remotes) to Mercurial. Branches are + converted to bookmarks with the same name, with the leading 'refs/heads' + stripped. Git submodules are converted to Git subrepos in Mercurial. + + The following options can be set with "--config": + + convert.git.similarity + specify how similar files modified in a commit must be to be + imported as renames or copies, as a percentage between "0" + (disabled) and "100" (files must be identical). For example, + "90" means that a delete/add pair will be imported as a + rename if more than 90% of the file hasn't changed. The + default is "50". + convert.git.findcopiesharder + while detecting copies, look at all files in the working + copy instead of just changed ones. This is very expensive + for large projects, and is only effective when + "convert.git.similarity" is greater than 0. The default is + False. + Perforce Source ############### @@ -265,6 +296,7 @@ -r --rev REV import up to source revision REV -A --authormap FILE remap usernames using this file --filemap FILE remap file names using contents of file + --full apply filemap changes by converting all files again --splicemap FILE splice synthesized history into place --branchmap FILE change branch names while converting --branchsort try to sort changesets by branches @@ -272,7 +304,7 @@ --sourcesort preserve source changesets order --closesort try to reorder closed revisions - use "hg -v help convert" to show the global options + (some details hidden, use --verbose to show complete help) $ hg init a $ cd a $ echo a > a
--- a/tests/test-diff-color.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-diff-color.t Sat Sep 27 14:47:52 2014 -0500 @@ -159,4 +159,44 @@ b \x1b[0;32m+bb\x1b[0m (esc) +test tabs + + $ cat >> a <<EOF + > one tab + > two tabs + > end tab + > mid tab + > all tabs + > EOF + $ hg diff --nodates --color=always + \x1b[0;1mdiff --git a/a b/a\x1b[0m (esc) + \x1b[0;31;1m--- a/a\x1b[0m (esc) + \x1b[0;32;1m+++ b/a\x1b[0m (esc) + \x1b[0;35m@@ -7,3 +7,9 @@\x1b[0m (esc) + a + c + c + \x1b[0;32m+aa\x1b[0m (esc) + \x1b[0;32m+\x1b[0m \x1b[0;32mone tab\x1b[0m (esc) + \x1b[0;32m+\x1b[0m \x1b[0;32mtwo tabs\x1b[0m (esc) + \x1b[0;32m+end tab\x1b[0m\x1b[0;1;41m \x1b[0m (esc) + \x1b[0;32m+mid\x1b[0m \x1b[0;32mtab\x1b[0m (esc) + \x1b[0;32m+\x1b[0m \x1b[0;32mall\x1b[0m \x1b[0;32mtabs\x1b[0m\x1b[0;1;41m \x1b[0m (esc) + $ echo "[color]" >> $HGRCPATH + $ echo "diff.tab = bold magenta" >> $HGRCPATH + $ hg diff --nodates --color=always + \x1b[0;1mdiff --git a/a b/a\x1b[0m (esc) + \x1b[0;31;1m--- a/a\x1b[0m (esc) + \x1b[0;32;1m+++ b/a\x1b[0m (esc) + \x1b[0;35m@@ -7,3 +7,9 @@\x1b[0m (esc) + a + c + c + \x1b[0;32m+aa\x1b[0m (esc) + \x1b[0;32m+\x1b[0m\x1b[0;1;35m \x1b[0m\x1b[0;32mone tab\x1b[0m (esc) + \x1b[0;32m+\x1b[0m\x1b[0;1;35m \x1b[0m\x1b[0;32mtwo tabs\x1b[0m (esc) + \x1b[0;32m+end tab\x1b[0m\x1b[0;1;41m \x1b[0m (esc) + \x1b[0;32m+mid\x1b[0m\x1b[0;1;35m \x1b[0m\x1b[0;32mtab\x1b[0m (esc) + \x1b[0;32m+\x1b[0m\x1b[0;1;35m \x1b[0m\x1b[0;32mall\x1b[0m\x1b[0;1;35m \x1b[0m\x1b[0;32mtabs\x1b[0m\x1b[0;1;41m \x1b[0m (esc) + $ cd ..
--- a/tests/test-diff-upgrade.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-diff-upgrade.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" execbit || exit 80 +#require execbit $ echo "[extensions]" >> $HGRCPATH $ echo "autodiff=$TESTDIR/autodiff.py" >> $HGRCPATH
--- a/tests/test-dirstate.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-dirstate.t Sat Sep 27 14:47:52 2014 -0500 @@ -61,3 +61,28 @@ $ hg debugstate n 644 2 2018-01-19 15:14:08 a #endif + +Verify that exceptions during a dirstate change leave the dirstate +coherent (issue4353) + + $ cat > ../dirstateexception.py <<EOF + > from mercurial import merge, extensions, util + > + > def wraprecordupdates(orig, repo, actions, branchmerge): + > raise util.Abort("simulated error while recording dirstateupdates") + > + > def reposetup(ui, repo): + > extensions.wrapfunction(merge, 'recordupdates', wraprecordupdates) + > EOF + + $ hg rm a + $ hg commit -m 'rm a' + $ echo "[extensions]" >> .hg/hgrc + $ echo "dirstateex=../dirstateexception.py" >> .hg/hgrc + $ hg up 0 + abort: simulated error while recording dirstateupdates + [255] + $ hg log -r . -T '{rev}\n' + 1 + $ hg status + ? a
--- a/tests/test-dispatch.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-dispatch.t Sat Sep 27 14:47:52 2014 -0500 @@ -19,7 +19,7 @@ output the current or given revision of files - options: + options ([+] can be repeated): -o --output FORMAT print output to file with formatted name -r --rev REV print the given revision @@ -27,9 +27,7 @@ -I --include PATTERN [+] include names matching the given patterns -X --exclude PATTERN [+] exclude names matching the given patterns - [+] marked option can be specified multiple times - - use "hg help cat" to show the full help text + (use "hg cat -h" to show more help) [255] [defaults]
--- a/tests/test-doctest.py Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-doctest.py Sat Sep 27 14:47:52 2014 -0500 @@ -31,3 +31,4 @@ testmod('hgext.convert.cvsps') testmod('hgext.convert.filemap') testmod('hgext.convert.subversion') +testmod('hgext.mq')
--- a/tests/test-encoding-align.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-encoding-align.t Sat Sep 27 14:47:52 2014 -0500 @@ -58,7 +58,7 @@ \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d (esc) \xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d (esc) - use "hg -v help showoptlist" to show the global options + (some details hidden, use --verbose to show complete help) $ rm -f s; touch s
--- a/tests/test-encoding-textwrap.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-encoding-textwrap.t Sat Sep 27 14:47:52 2014 -0500 @@ -69,7 +69,7 @@ \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf\x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf\x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf (esc) \x82\xa0\x82\xa2\x82\xa4\x82\xa6\x82\xa8\x82\xa9\x82\xab\x82\xad\x82\xaf (esc) - use "hg -v help show_full_ja" to show the global options + (some details hidden, use --verbose to show complete help) (1-2) display Japanese full-width characters in utf-8 @@ -84,7 +84,7 @@ \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 (esc) \xe3\x81\x82\xe3\x81\x84\xe3\x81\x86\xe3\x81\x88\xe3\x81\x8a\xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91 (esc) - use "hg -v help show_full_ja" to show the global options + (some details hidden, use --verbose to show complete help) (1-3) display Japanese half-width characters in cp932 @@ -100,7 +100,7 @@ \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 (esc) \xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9 (esc) - use "hg -v help show_half_ja" to show the global options + (some details hidden, use --verbose to show complete help) (1-4) display Japanese half-width characters in utf-8 @@ -115,7 +115,7 @@ \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 (esc) \xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9\xef\xbd\xb1\xef\xbd\xb2\xef\xbd\xb3\xef\xbd\xb4\xef\xbd\xb5\xef\xbd\xb6\xef\xbd\xb7\xef\xbd\xb8\xef\xbd\xb9 (esc) - use "hg -v help show_half_ja" to show the global options + (some details hidden, use --verbose to show complete help) @@ -136,7 +136,7 @@ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc) \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc) - use "hg -v help show_ambig_ja" to show the global options + (some details hidden, use --verbose to show complete help) (2-1-2) display Japanese ambiguous-width characters in utf-8 @@ -151,7 +151,7 @@ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc) \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc) - use "hg -v help show_ambig_ja" to show the global options + (some details hidden, use --verbose to show complete help) (2-1-3) display Russian ambiguous-width characters in cp1251 @@ -166,7 +166,7 @@ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc) \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc) - use "hg -v help show_ambig_ru" to show the global options + (some details hidden, use --verbose to show complete help) (2-1-4) display Russian ambiguous-width characters in utf-8 @@ -181,7 +181,7 @@ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc) \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc) - use "hg -v help show_ambig_ru" to show the global options + (some details hidden, use --verbose to show complete help) (2-2) treat width of ambiguous characters as wide @@ -202,7 +202,7 @@ \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b\x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc) \x83\xbf\x83\xc0\x83\xc1\x83\xc2\x83\xd2\x83\xc4\x83\xc5\x83\xc6\x81\x9b (esc) - use "hg -v help show_ambig_ja" to show the global options + (some details hidden, use --verbose to show complete help) (2-2-2) display Japanese ambiguous-width characters in utf-8 @@ -220,7 +220,7 @@ \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b\xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc) \xce\xb1\xce\xb2\xce\xb3\xce\xb4\xcf\x85\xce\xb6\xce\xb7\xce\xb8\xe2\x97\x8b (esc) - use "hg -v help show_ambig_ja" to show the global options + (some details hidden, use --verbose to show complete help) (2-2-3) display Russian ambiguous-width characters in cp1251 @@ -238,7 +238,7 @@ \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8\xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc) \xcd\xe0\xf1\xf2\xf0\xee\xe9\xea\xe8 (esc) - use "hg -v help show_ambig_ru" to show the global options + (some details hidden, use --verbose to show complete help) (2-2-4) display Russian ambiguous-width characters in utf-8 @@ -256,6 +256,6 @@ \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8\xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc) \xd0\x9d\xd0\xb0\xd1\x81\xd1\x82\xd1\x80\xd0\xbe\xd0\xb9\xd0\xba\xd0\xb8 (esc) - use "hg -v help show_ambig_ru" to show the global options + (some details hidden, use --verbose to show complete help) $ cd ..
--- a/tests/test-encoding.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-encoding.t Sat Sep 27 14:47:52 2014 -0500 @@ -179,6 +179,24 @@ tip 5:a52c0692f24a \xc3\xa9 3:ca661e7520de (esc) +hg tags (JSON) + + $ hg tags -Tjson + [ + { + "node": "a52c0692f24ad921c0a31e1736e7635a8b23b670", + "rev": 5, + "tag": "tip", + "type": "" + }, + { + "node": "ca661e7520dec3f5438a63590c350bebadb04989", + "rev": 3, + "tag": "\xc3\xa9", (esc) + "type": "" + } + ] + hg branches (ascii) $ HGENCODING=ascii hg branches
--- a/tests/test-eolfilename.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-eolfilename.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,6 @@ -http://mercurial.selenic.com/bts/issue352 +#require eol-in-paths - $ "$TESTDIR/hghave" eol-in-paths || exit 80 +http://mercurial.selenic.com/bts/issue352 test issue352
--- a/tests/test-execute-bit.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-execute-bit.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" execbit || exit 80 +#require execbit $ hg init $ echo a > a
--- a/tests/test-extdiff.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-extdiff.t Sat Sep 27 14:47:52 2014 -0500 @@ -37,7 +37,7 @@ compared to the working directory, and, when no revisions are specified, the working directory files are compared to its parent. - options: + options ([+] can be repeated): -o --option OPT [+] pass option to comparison program -r --rev REV [+] revision @@ -45,9 +45,7 @@ -I --include PATTERN [+] include names matching the given patterns -X --exclude PATTERN [+] exclude names matching the given patterns - [+] marked option can be specified multiple times - - use "hg -v help falabala" to show the global options + (some details hidden, use --verbose to show complete help) $ hg ci -d '0 0' -mtest1
--- a/tests/test-extension.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-extension.t Sat Sep 27 14:47:52 2014 -0500 @@ -301,7 +301,7 @@ foo yet another foo command - global options: + global options ([+] can be repeated): -R --repository REPO repository root directory or name of overlay bundle file @@ -321,8 +321,6 @@ --version output version information and exit -h --help display help and exit --hidden consider hidden changesets - - [+] marked option can be specified multiple times @@ -337,7 +335,7 @@ debugfoobar yet another debug command foo yet another foo command - global options: + global options ([+] can be repeated): -R --repository REPO repository root directory or name of overlay bundle file @@ -357,8 +355,6 @@ --version output version information and exit -h --help display help and exit --hidden consider hidden changesets - - [+] marked option can be specified multiple times @@ -388,9 +384,9 @@ compared to the working directory, and, when no revisions are specified, the working directory files are compared to its parent. - use "hg help -e extdiff" to show help for the extdiff extension + (use "hg help -e extdiff" to show help for the extdiff extension) - options: + options ([+] can be repeated): -p --program CMD comparison program to run -o --option OPT [+] pass option to comparison program @@ -399,9 +395,7 @@ -I --include PATTERN [+] include names matching the given patterns -X --exclude PATTERN [+] exclude names matching the given patterns - [+] marked option can be specified multiple times - - use "hg -v help extdiff" to show the global options + (some details hidden, use --verbose to show complete help) @@ -469,7 +463,7 @@ extdiff use external program to diff repository (or selected files) - use "hg -v help extdiff" to show builtin aliases and global options + (use "hg help -v extdiff" to show built-in aliases and global options) @@ -533,7 +527,7 @@ multirevs command - use "hg -v help multirevs" to show the global options + (some details hidden, use --verbose to show complete help) @@ -543,7 +537,7 @@ multirevs command - use "hg help multirevs" to show the full help text + (use "hg multirevs -h" to show more help) [255] @@ -588,7 +582,7 @@ patchbomb command to send changesets as (a series of) patch emails - use "hg help extensions" for information on enabling extensions + (use "hg help extensions" for information on enabling extensions) $ hg qdel @@ -597,7 +591,7 @@ mq manage a stack of patches - use "hg help extensions" for information on enabling extensions + (use "hg help extensions" for information on enabling extensions) [255] @@ -607,7 +601,7 @@ churn command to display statistics about repository history - use "hg help extensions" for information on enabling extensions + (use "hg help extensions" for information on enabling extensions) [255] @@ -617,12 +611,12 @@ $ hg help churn churn extension - command to display statistics about repository history - use "hg help extensions" for information on enabling extensions + (use "hg help extensions" for information on enabling extensions) $ hg help patchbomb patchbomb extension - command to send changesets as (a series of) patch emails - use "hg help extensions" for information on enabling extensions + (use "hg help extensions" for information on enabling extensions) Broken disabled extension and command: @@ -642,7 +636,7 @@ $ hg --config extensions.path=./path.py help broken broken extension - (no help text available) - use "hg help extensions" for information on enabling extensions + (use "hg help extensions" for information on enabling extensions) $ cat > hgext/forest.py <<EOF
--- a/tests/test-fetch.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-fetch.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve $ echo "[extensions]" >> $HGRCPATH $ echo "fetch=" >> $HGRCPATH
--- a/tests/test-flags.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-flags.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" execbit || exit 80 +#require execbit $ umask 027
--- a/tests/test-gendoc.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-gendoc.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,7 @@ +#require docutils + Test document extraction - $ "$TESTDIR/hghave" docutils || exit 80 $ HGENCODING=UTF-8 $ export HGENCODING $ { echo C; ls "$TESTDIR/../i18n"/*.po | sort; } | while read PO; do
--- a/tests/test-getbundle.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-getbundle.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve = Test the getbundle() protocol function =
--- a/tests/test-globalopts.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-globalopts.t Sat Sep 27 14:47:52 2014 -0500 @@ -301,6 +301,7 @@ copy mark files as copied for the next commit diff diff repository (or selected files) export dump the header and diffs for one or more changesets + files list tracked files forget forget the specified files on the next commit graft copy changes from other branches onto the current branch grep search for a pattern in specified files and revisions @@ -310,12 +311,10 @@ import import an ordered set of patches incoming show new changesets found in source init create a new repository in the given directory - locate locate files matching specific patterns log show revision history of entire repository or files manifest output the current or given revision of the project manifest merge merge working directory with another revision outgoing show changesets not found in the destination - parents show the parents of the working directory or revision paths show aliases for remote repositories phase set or show the current phase name pull pull changes from the specified source @@ -357,7 +356,7 @@ templating Template Usage urls URL Paths - use "hg -v help" to show builtin aliases and global options + (use "hg help -v" to show built-in aliases and global options) @@ -383,6 +382,7 @@ copy mark files as copied for the next commit diff diff repository (or selected files) export dump the header and diffs for one or more changesets + files list tracked files forget forget the specified files on the next commit graft copy changes from other branches onto the current branch grep search for a pattern in specified files and revisions @@ -392,12 +392,10 @@ import import an ordered set of patches incoming show new changesets found in source init create a new repository in the given directory - locate locate files matching specific patterns log show revision history of entire repository or files manifest output the current or given revision of the project manifest merge merge working directory with another revision outgoing show changesets not found in the destination - parents show the parents of the working directory or revision paths show aliases for remote repositories phase set or show the current phase name pull pull changes from the specified source @@ -439,7 +437,7 @@ templating Template Usage urls URL Paths - use "hg -v help" to show builtin aliases and global options + (use "hg help -v" to show built-in aliases and global options) Not tested: --debugger
--- a/tests/test-glog.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-glog.t Sat Sep 27 14:47:52 2014 -0500 @@ -1645,13 +1645,28 @@ ('symbol', 'filelog') ('string', 'aa')))) -Test --follow on a directory +Test --follow on a non-existent directory $ testlog -f dir abort: cannot follow file not in parent revision: "dir" abort: cannot follow file not in parent revision: "dir" abort: cannot follow file not in parent revision: "dir" +Test --follow on a directory + + $ hg up -q '.^' + $ testlog -f dir + [] + (group + (func + ('symbol', '_matchfiles') + (list + (list + ('string', 'r:') + ('string', 'd:relpath')) + ('string', 'p:dir')))) + $ hg up -q tip + Test --follow on file not in parent revision $ testlog -f a @@ -1662,9 +1677,15 @@ Test --follow and patterns $ testlog -f 'glob:*' - abort: can only follow copies/renames for explicit filenames - abort: can only follow copies/renames for explicit filenames - abort: can only follow copies/renames for explicit filenames + [] + (group + (func + ('symbol', '_matchfiles') + (list + (list + ('string', 'r:') + ('string', 'd:relpath')) + ('string', 'p:glob:*')))) Test --follow on a single rename @@ -1829,9 +1850,15 @@ ('string', 'd:relpath')) ('string', 'p:a')))) $ testlog --removed --follow a - abort: can only follow copies/renames for explicit filenames - abort: can only follow copies/renames for explicit filenames - abort: can only follow copies/renames for explicit filenames + [] + (group + (func + ('symbol', '_matchfiles') + (list + (list + ('string', 'r:') + ('string', 'd:relpath')) + ('string', 'p:a')))) Test --patch and --stat with --follow and --follow-first
--- a/tests/test-gpg.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-gpg.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,7 @@ +#require gpg + Test the GPG extension - $ "$TESTDIR/hghave" gpg || exit 80 $ cat <<EOF >> $HGRCPATH > [extensions] > gpg=
--- a/tests/test-graft.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-graft.t Sat Sep 27 14:47:52 2014 -0500 @@ -632,6 +632,52 @@ grafting revision 19 merging b +graft with --force (still doesn't graft merges) + + $ hg graft 19 0 6 + skipping ungraftable merge revision 6 + skipping ancestor revision 0 + skipping already grafted revision 19 (22 also has origin 2) + [255] + $ hg graft 19 0 6 --force + skipping ungraftable merge revision 6 + grafting revision 19 + merging b + grafting revision 0 + +graft --force after backout + + $ echo abc > a + $ hg ci -m 28 + $ hg backout 28 + reverting a + changeset 29:484c03b8dfa4 backs out changeset 28:6c56f0f7f033 + $ hg graft 28 + skipping ancestor revision 28 + [255] + $ hg graft 28 --force + grafting revision 28 + merging a + $ cat a + abc + +graft --continue after --force + + $ hg backout 30 + reverting a + changeset 31:3b96c18b7a1b backs out changeset 30:8f539994be33 + $ hg graft 28 --force --tool internal:fail + grafting revision 28 + abort: unresolved conflicts, can't continue + (use hg resolve and hg graft --continue) + [255] + $ hg resolve --all + merging a + (no more unresolved files) + $ hg graft -c + grafting revision 28 + $ cat a + abc Continue testing same origin policy, using revision numbers from test above but do some destructive editing of the repo:
--- a/tests/test-hardlinks.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hardlinks.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" hardlink || exit 80 +#require hardlink $ cat > nlinks.py <<EOF > import sys
--- a/tests/test-help.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-help.t Sat Sep 27 14:47:52 2014 -0500 @@ -23,7 +23,7 @@ summary summarize working directory state update update working directory (or switch revisions) - use "hg help" for the full list of commands or "hg -v" for details + (use "hg help" for the full list of commands or "hg -v" for details) $ hg -q add add the specified files on the next commit @@ -66,6 +66,7 @@ copy mark files as copied for the next commit diff diff repository (or selected files) export dump the header and diffs for one or more changesets + files list tracked files forget forget the specified files on the next commit graft copy changes from other branches onto the current branch grep search for a pattern in specified files and revisions @@ -75,12 +76,10 @@ import import an ordered set of patches incoming show new changesets found in source init create a new repository in the given directory - locate locate files matching specific patterns log show revision history of entire repository or files manifest output the current or given revision of the project manifest merge merge working directory with another revision outgoing show changesets not found in the destination - parents show the parents of the working directory or revision paths show aliases for remote repositories phase set or show the current phase name pull pull changes from the specified source @@ -122,7 +121,7 @@ templating Template Usage urls URL Paths - use "hg -v help" to show builtin aliases and global options + (use "hg help -v" to show built-in aliases and global options) $ hg -q help add add the specified files on the next commit @@ -142,6 +141,7 @@ copy mark files as copied for the next commit diff diff repository (or selected files) export dump the header and diffs for one or more changesets + files list tracked files forget forget the specified files on the next commit graft copy changes from other branches onto the current branch grep search for a pattern in specified files and revisions @@ -151,12 +151,10 @@ import import an ordered set of patches incoming show new changesets found in source init create a new repository in the given directory - locate locate files matching specific patterns log show revision history of entire repository or files manifest output the current or given revision of the project manifest merge merge working directory with another revision outgoing show changesets not found in the destination - parents show the parents of the working directory or revision paths show aliases for remote repositories phase set or show the current phase name pull pull changes from the specified source @@ -305,7 +303,7 @@ update, up, checkout, co update working directory (or switch revisions) - global options: + global options ([+] can be repeated): -R --repository REPO repository root directory or name of overlay bundle file @@ -326,9 +324,7 @@ -h --help display help and exit --hidden consider hidden changesets - [+] marked option can be specified multiple times - - use "hg help" for the full list of commands + (use "hg help" for the full list of commands) $ hg add -h hg add [OPTION]... [FILE]... @@ -344,16 +340,14 @@ Returns 0 if all files are successfully added. - options: + options ([+] can be repeated): -I --include PATTERN [+] include names matching the given patterns -X --exclude PATTERN [+] exclude names matching the given patterns -S --subrepos recurse into subrepositories -n --dry-run do not perform actions, just print output - [+] marked option can be specified multiple times - - use "hg -v help add" to show more complete help and the global options + (some details hidden, use --verbose to show complete help) Verbose help for add @@ -383,16 +377,14 @@ Returns 0 if all files are successfully added. - options: + options ([+] can be repeated): -I --include PATTERN [+] include names matching the given patterns -X --exclude PATTERN [+] exclude names matching the given patterns -S --subrepos recurse into subrepositories -n --dry-run do not perform actions, just print output - [+] marked option can be specified multiple times - - global options: + global options ([+] can be repeated): -R --repository REPO repository root directory or name of overlay bundle file @@ -412,8 +404,6 @@ --version output version information and exit -h --help display help and exit --hidden consider hidden changesets - - [+] marked option can be specified multiple times Test help option with version option @@ -431,16 +421,14 @@ add the specified files on the next commit - options: + options ([+] can be repeated): -I --include PATTERN [+] include names matching the given patterns -X --exclude PATTERN [+] exclude names matching the given patterns -S --subrepos recurse into subrepositories -n --dry-run do not perform actions, just print output - [+] marked option can be specified multiple times - - use "hg help add" to show the full help text + (use "hg add -h" to show more help) [255] Test ambiguous command help @@ -451,7 +439,7 @@ add add the specified files on the next commit addremove add all new files, delete all missing files - use "hg -v help ad" to show builtin aliases and global options + (use "hg help -v ad" to show built-in aliases and global options) Test command without options @@ -472,7 +460,7 @@ Returns 0 on success, 1 if errors are encountered. - use "hg -v help verify" to show the global options + (some details hidden, use --verbose to show complete help) $ hg help diff hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]... @@ -505,7 +493,7 @@ Returns 0 on success. - options: + options ([+] can be repeated): -r --rev REV [+] revision -c --change REV change made by revision @@ -523,9 +511,7 @@ -X --exclude PATTERN [+] exclude names matching the given patterns -S --subrepos recurse into subrepositories - [+] marked option can be specified multiple times - - use "hg -v help diff" to show more complete help and the global options + (some details hidden, use --verbose to show complete help) $ hg help status hg status [OPTION]... [FILE]... @@ -567,7 +553,7 @@ Returns 0 on success. - options: + options ([+] can be repeated): -A --all show status of all files -m --modified show only modified files @@ -586,9 +572,7 @@ -X --exclude PATTERN [+] exclude names matching the given patterns -S --subrepos recurse into subrepositories - [+] marked option can be specified multiple times - - use "hg -v help status" to show more complete help and the global options + (some details hidden, use --verbose to show complete help) $ hg -q help status hg status [OPTION]... [FILE]... @@ -624,7 +608,7 @@ summary summarize working directory state update update working directory (or switch revisions) - use "hg help" for the full list of commands or "hg -v" for details + (use "hg help" for the full list of commands or "hg -v" for details) [255] @@ -663,7 +647,7 @@ -n -- normal desc --newline VALUE line1 line2 - use "hg -v help nohelp" to show the global options + (some details hidden, use --verbose to show complete help) $ hg help -k nohelp Commands: @@ -698,6 +682,7 @@ copy mark files as copied for the next commit diff diff repository (or selected files) export dump the header and diffs for one or more changesets + files list tracked files forget forget the specified files on the next commit graft copy changes from other branches onto the current branch grep search for a pattern in specified files and revisions @@ -707,12 +692,10 @@ import import an ordered set of patches incoming show new changesets found in source init create a new repository in the given directory - locate locate files matching specific patterns log show revision history of entire repository or files manifest output the current or given revision of the project manifest merge merge working directory with another revision outgoing show changesets not found in the destination - parents show the parents of the working directory or revision paths show aliases for remote repositories phase set or show the current phase name pull pull changes from the specified source @@ -758,7 +741,7 @@ templating Template Usage urls URL Paths - use "hg -v help" to show builtin aliases and global options + (use "hg help -v" to show built-in aliases and global options) Test list of internal help commands @@ -798,6 +781,7 @@ debugknown test whether node ids are known to a repo debuglabelcomplete complete "labels" - tags, open branch names, bookmark names + debuglocks show or modify state of locks debugobsolete create arbitrary obsolete marker debugoptDEP (no help text available) @@ -820,7 +804,7 @@ debugwireargs (no help text available) - use "hg -v help debug" to show builtin aliases and global options + (use "hg help -v debug" to show built-in aliases and global options) Test list of commands with command with no help text @@ -832,7 +816,7 @@ nohelp (no help text available) - use "hg -v help helpext" to show builtin aliases and global options + (use "hg help -v helpext" to show built-in aliases and global options) test deprecated option is hidden in command help @@ -843,7 +827,7 @@ options: - use "hg -v help debugoptDEP" to show the global options + (some details hidden, use --verbose to show complete help) test deprecated option is shown with -v $ hg help -v debugoptDEP | grep dopt @@ -857,9 +841,9 @@ (*) (glob) - flaggor: + options: - *"hg -v help debugoptDEP"* (glob) + (some details hidden, use --verbose to show complete help) #endif Test commands that collide with topics (issue4240) @@ -1030,7 +1014,7 @@ This paragraph is never omitted, too (for extension) - use "hg help -v addverboseitems" to show more complete help + (some details hidden, use --verbose to show complete help) no commands defined $ hg help -v addverboseitems @@ -1051,7 +1035,7 @@ This paragraph is never omitted, too (for topic) - use "hg help -v topic-containing-verbose" to show more complete help + (some details hidden, use --verbose to show complete help) $ hg help -v topic-containing-verbose This is the topic to test omit indicating. """""""""""""""""""""""""""""""""""""""""" @@ -1458,6 +1442,13 @@ mark files as copied for the next commit </td></tr> <tr><td> + <a href="/help/files"> + files + </a> + </td><td> + list tracked files + </td></tr> + <tr><td> <a href="/help/graft"> graft </a> @@ -1507,13 +1498,6 @@ show new changesets found in source </td></tr> <tr><td> - <a href="/help/locate"> - locate - </a> - </td><td> - locate files matching specific patterns - </td></tr> - <tr><td> <a href="/help/manifest"> manifest </a> @@ -1535,13 +1519,6 @@ show changesets not found in the destination </td></tr> <tr><td> - <a href="/help/parents"> - parents - </a> - </td><td> - show the parents of the working directory or revision - </td></tr> - <tr><td> <a href="/help/paths"> paths </a> @@ -1715,7 +1692,7 @@ Returns 0 if all files are successfully added. </p> <p> - options: + options ([+] can be repeated): </p> <table> <tr><td>-I</td> @@ -1732,10 +1709,7 @@ <td>do not perform actions, just print output</td></tr> </table> <p> - [+] marked option can be specified multiple times - </p> - <p> - global options: + global options ([+] can be repeated): </p> <table> <tr><td>-R</td> @@ -1787,9 +1761,6 @@ <td>--hidden</td> <td>consider hidden changesets</td></tr> </table> - <p> - [+] marked option can be specified multiple times - </p> </div> </div> @@ -1911,7 +1882,7 @@ Returns 0 on success, 1 if any warnings encountered. </p> <p> - options: + options ([+] can be repeated): </p> <table> <tr><td>-A</td> @@ -1928,10 +1899,7 @@ <td>exclude names matching the given patterns</td></tr> </table> <p> - [+] marked option can be specified multiple times - </p> - <p> - global options: + global options ([+] can be repeated): </p> <table> <tr><td>-R</td> @@ -1983,9 +1951,6 @@ <td>--hidden</td> <td>consider hidden changesets</td></tr> </table> - <p> - [+] marked option can be specified multiple times - </p> </div> </div>
--- a/tests/test-hgrc.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgrc.t Sat Sep 27 14:47:52 2014 -0500 @@ -28,6 +28,14 @@ 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd foobar $ cat .hg/hgrc + # You may want to set your username here if it is not set + # globally, or this repository requires a different + # username from your usual configuration. If you want to + # set something for all of your repositories on this + # computer, try running the command + # 'hg config --edit --global' + # [ui] + # username = Jane Doe <jdoe@example.com> [paths] default = $TESTTMP/foo%bar (glob) $ hg paths @@ -43,6 +51,7 @@ $ echo ' x = y' >> $HGRC $ hg version hg: parse error at $TESTTMP/hgrc:2: x = y + unexpected leading whitespace [255] $ python -c "print '[foo]\nbar = a\n b\n c \n de\n fg \nbaz = bif cb \n'" \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test-hgweb-bundle.t Sat Sep 27 14:47:52 2014 -0500 @@ -0,0 +1,37 @@ +#require serve + + $ hg init server + $ cd server + $ cat >> .hg/hgrc << EOF + > [extensions] + > strip= + > EOF + + $ echo 1 > foo + $ hg commit -A -m 'first' + adding foo + $ echo 2 > bar + $ hg commit -A -m 'second' + adding bar + +Produce a bundle to use + + $ hg strip -r 1 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + saved backup bundle to $TESTTMP/server/.hg/strip-backup/ed602e697e0f-backup.hg (glob) + +Serve from a bundle file + + $ hg serve -R .hg/strip-backup/ed602e697e0f-backup.hg -d -p $HGPORT --pid-file=hg.pid + $ cat hg.pid >> $DAEMON_PIDS + +Ensure we're serving from the bundle + + $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT 'file/tip/?style=raw') + 200 Script output follows + + + -rw-r--r-- 2 bar + -rw-r--r-- 2 foo + +
--- a/tests/test-hgweb-commands.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgweb-commands.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve An attempt at more fully testing the hgweb web interface. The following things are tested elsewhere and are therefore omitted:
--- a/tests/test-hgweb-descend-empties.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgweb-descend-empties.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve Test chains of near empty directories, terminating 3 different ways: - a1: file at level 4 (deepest)
--- a/tests/test-hgweb-diffs.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgweb-diffs.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve setting up repo
--- a/tests/test-hgweb-empty.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgweb-empty.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve Some tests for hgweb in an empty repository
--- a/tests/test-hgweb-filelog.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgweb-filelog.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve $ hg init test $ cd test
--- a/tests/test-hgweb-raw.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgweb-raw.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve Test raw style of hgweb
--- a/tests/test-hgweb-removed.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgweb-removed.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve setting up repo
--- a/tests/test-hgweb.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgweb.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve Some tests for hgweb. Tests static files, plain files and different 404's.
--- a/tests/test-hgwebdir.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgwebdir.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve hide outer repo and work in dir without '.hg' $ hg init
--- a/tests/test-hgwebdirsym.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hgwebdirsym.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,6 @@ -Tests whether or not hgwebdir properly handles various symlink topologies. +#require serve symlink - $ "$TESTDIR/hghave" serve symlink || exit 80 +Tests whether or not hgwebdir properly handles various symlink topologies. hide outer repo $ hg init
--- a/tests/test-highlight.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-highlight.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,5 @@ +#require pygments serve - $ "$TESTDIR/hghave" pygments serve || exit 80 $ cat <<EOF >> $HGRCPATH > [extensions] > highlight =
--- a/tests/test-histedit-arguments.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-histedit-arguments.t Sat Sep 27 14:47:52 2014 -0500 @@ -67,6 +67,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content # @@ -265,6 +266,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content #
--- a/tests/test-histedit-bookmark-motion.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-histedit-bookmark-motion.t Sat Sep 27 14:47:52 2014 -0500 @@ -73,6 +73,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content # @@ -133,6 +134,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content #
--- a/tests/test-histedit-commute.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-histedit-commute.t Sat Sep 27 14:47:52 2014 -0500 @@ -67,6 +67,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content # @@ -344,6 +345,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content #
--- a/tests/test-histedit-fold-non-commute.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-histedit-fold-non-commute.t Sat Sep 27 14:47:52 2014 -0500 @@ -183,3 +183,165 @@ f $ cd .. + +Repeat test using "roll", not "fold". "roll" folds in changes but drops message + + $ initrepo r2 + $ cd r2 + +Initial generation of the command files + + $ EDITED="$TESTTMP/editedhistory.2" + $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 3 >> $EDITED + $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 4 >> $EDITED + $ hg log --template 'roll {node|short} {rev} {desc}\n' -r 7 >> $EDITED + $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 5 >> $EDITED + $ hg log --template 'pick {node|short} {rev} {desc}\n' -r 6 >> $EDITED + $ cat $EDITED + pick 65a9a84f33fd 3 c + pick 00f1c5383965 4 d + roll 39522b764e3d 7 does not commute with e + pick 7b4e2f4b7bcd 5 e + pick 500cac37a696 6 f + +log before edit + $ hg log --graph + @ changeset: 7:39522b764e3d + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: does not commute with e + | + o changeset: 6:500cac37a696 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: f + | + o changeset: 5:7b4e2f4b7bcd + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: e + | + o changeset: 4:00f1c5383965 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: d + | + o changeset: 3:65a9a84f33fd + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: c + | + o changeset: 2:da6535b52e45 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 1:c1f09da44841 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: a + | + o changeset: 0:1715188a53c7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: Initial commit + + +edit the history + $ hg histedit 3 --commands $EDITED 2>&1 | fixbundle + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + merging e + warning: conflicts during merge. + merging e incomplete! (edit conflicts, then use 'hg resolve --mark') + Fix up the change and run hg histedit --continue + +fix up + $ echo 'I can haz no commute' > e + $ hg resolve --mark e + (no more unresolved files) + $ hg histedit --continue 2>&1 | fixbundle | grep -v '2 files removed' + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + merging e + warning: conflicts during merge. + merging e incomplete! (edit conflicts, then use 'hg resolve --mark') + Fix up the change and run hg histedit --continue + +just continue this time + $ hg revert -r 'p1()' e + $ hg resolve --mark e + (no more unresolved files) + $ hg histedit --continue 2>&1 | fixbundle + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + +log after edit + $ hg log --graph + @ changeset: 5:e7c4f5d4eb75 + | tag: tip + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: f + | + o changeset: 4:803d1bb561fc + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: d + | + o changeset: 3:65a9a84f33fd + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: c + | + o changeset: 2:da6535b52e45 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: b + | + o changeset: 1:c1f09da44841 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: a + | + o changeset: 0:1715188a53c7 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: Initial commit + + +contents of e + $ hg cat e + I can haz no commute + +manifest + $ hg manifest + a + b + c + d + e + f + +description is taken from rollup target commit + + $ hg log --debug --rev 4 + changeset: 4:803d1bb561fceac3129ec778db9da249a3106fc3 + phase: draft + parent: 3:65a9a84f33fdeb1ad5679b3941ec885d2b24027b + parent: -1:0000000000000000000000000000000000000000 + manifest: 4:b068a323d969f22af1296ec6a5ea9384cef437ac + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + files: d e + extra: branch=default + extra: histedit_source=00f1c53839651fa5c76d423606811ea5455a79d0,39522b764e3d26103f08bd1fa2ccd3e3d7dbcf4e + description: + d + + + +done with repo r2 + + $ cd ..
--- a/tests/test-histedit-fold.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-histedit-fold.t Sat Sep 27 14:47:52 2014 -0500 @@ -105,6 +105,50 @@ +rollup will fold without preserving the folded commit's message + + $ hg histedit d2ae7f538514 --commands - 2>&1 <<EOF | fixbundle + > pick d2ae7f538514 b + > roll ee283cb5f2d5 e + > pick 6de59d13424a f + > pick 9c277da72c9b d + > EOF + 0 files updated, 0 files merged, 4 files removed, 0 files unresolved + 0 files updated, 0 files merged, 2 files removed, 0 files unresolved + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + +log after edit + $ hg logt --graph + @ 3:c4a9eb7989fc d + | + o 2:8e03a72b6f83 f + | + o 1:391ee782c689 b + | + o 0:cb9a9f314b8b a + + +description is taken from rollup target commit + + $ hg log --debug --rev 1 + changeset: 1:391ee782c68930be438ccf4c6a403daedbfbffa5 + phase: draft + parent: 0:cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b + parent: -1:0000000000000000000000000000000000000000 + manifest: 1:b5e112a3a8354e269b1524729f0918662d847c38 + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + files+: b e + extra: branch=default + extra: histedit_source=d2ae7f538514cd87c17547b0de4cea71fe1af9fb,ee283cb5f2d5955443f23a27b697a04339e9a39a + description: + b + + + check saving last-message.txt $ cat > $TESTTMP/abortfolding.py <<EOF @@ -128,9 +172,9 @@ > EOF $ rm -f .hg/last-message.txt - $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit 6de59d13424a --commands - 2>&1 <<EOF | fixbundle - > pick 6de59d13424a f - > fold 9c277da72c9b d + $ HGEDITOR="sh $TESTTMP/editor.sh" hg histedit 8e03a72b6f83 --commands - 2>&1 <<EOF | fixbundle + > pick 8e03a72b6f83 f + > fold c4a9eb7989fc d > EOF 0 files updated, 0 files merged, 1 files removed, 0 files unresolved allow non-folding commit
--- a/tests/test-histedit-obsolete.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-histedit-obsolete.t Sat Sep 27 14:47:52 2014 -0500 @@ -12,7 +12,7 @@ > logtemplate= {rev}:{node|short} {desc|firstline} > [phases] > publish=False - > [extensions]' + > [extensions] > histedit= > rebase= > @@ -57,6 +57,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content # @@ -89,11 +90,11 @@ o 0:cb9a9f314b8b a $ hg debugobsolete - d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {'date': '* *', 'user': 'test'} (glob) - 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 {'date': '* *', 'user': 'test'} (glob) - 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 {'date': '* *', 'user': 'test'} (glob) - e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 {'date': '* *', 'user': 'test'} (glob) - 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 {'date': '* *', 'user': 'test'} (glob) + d2ae7f538514cd87c17547b0de4cea71fe1af9fb 0 {cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b} (*) {'user': 'test'} (glob) + 177f92b773850b59254aa5e923436f921b55483b b346ab9a313db8537ecf96fca3ca3ca984ef3bd7 0 (*) {'user': 'test'} (glob) + 055a42cdd88768532f9cf79daa407fc8d138de9b 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob) + e860deea161a2f77de56603b340ebbb4536308ae 59d9f330561fd6c88b1a6b32f0e45034d88db784 0 (*) {'user': 'test'} (glob) + 652413bf663ef2a641cab26574e46d5f5a64a55a cacdfd884a9321ec4e1de275ef3949fa953a1f83 0 (*) {'user': 'test'} (glob) Ensure hidden revision does not prevent histedit
--- a/tests/test-histedit-outgoing.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-histedit-outgoing.t Sat Sep 27 14:47:52 2014 -0500 @@ -49,6 +49,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content # @@ -80,6 +81,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content # @@ -103,6 +105,7 @@ # p, pick = use commit # e, edit = use commit, but stop for amending # f, fold = use commit, but combine it with the one above + # r, roll = like fold, but discard this commit's description # d, drop = remove commit from history # m, mess = edit message without changing commit content #
--- a/tests/test-hook.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hook.t Sat Sep 27 14:47:52 2014 -0500 @@ -210,10 +210,11 @@ $ hg push -B baz ../a pushing to ../a searching for changes + 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'} listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'} - listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'} exporting bookmark baz prepushkey.forbid hook: HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 abort: prepushkey hook exited with status 1
--- a/tests/test-http-branchmap.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-http-branchmap.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons $ hgserve() { > hg serve -a localhost -p $HGPORT1 -d --pid-file=hg.pid \
--- a/tests/test-http-clone-r.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-http-clone-r.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve creating 'remote
--- a/tests/test-http-proxy.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-http-proxy.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve $ hg init a $ cd a
--- a/tests/test-http.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-http.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve $ hg init test $ cd test @@ -261,13 +261,14 @@ "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" 401 - x-hgarg-1:namespace=bookmarks "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 - "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks #endif $ cd ..
--- a/tests/test-https.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-https.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,6 @@ -Proper https client requires the built-in ssl from Python 2.6. +#require serve ssl - $ "$TESTDIR/hghave" serve ssl || exit 80 +Proper https client requires the built-in ssl from Python 2.6. Certificates created with: printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
--- a/tests/test-hup.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-hup.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,7 @@ +#require serve fifo + Test hangup signal in the middle of transaction - $ "$TESTDIR/hghave" serve fifo || exit 80 $ hg init $ mkfifo p $ hg serve --stdio < p 1>out 2>&1 &
--- a/tests/test-i18n.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-i18n.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,6 @@ -Translations are optional: +#require gettext - $ "$TESTDIR/hghave" gettext || exit 80 +(Translations are optional) #if no-outer-repo
--- a/tests/test-identify.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-identify.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve #if no-outer-repo
--- a/tests/test-impexp-branch.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-impexp-branch.t Sat Sep 27 14:47:52 2014 -0500 @@ -54,6 +54,14 @@ $ hg init c $ cd c + $ hg import --exact --no-commit ../r0.patch + applying ../r0.patch + warning: can't check exact import with --no-commit + $ hg st + A rev + $ hg revert -a + forgetting rev + $ rm rev $ hg import --exact ../r0.patch applying ../r0.patch $ hg import --exact ../r1.patch
--- a/tests/test-import-bypass.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-import-bypass.t Sat Sep 27 14:47:52 2014 -0500 @@ -22,10 +22,13 @@ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved Test importing an existing revision -(this also tests that editor is not invoked for '--bypass', if the -patch contains the commit message, regardless of '--edit') +(this also tests that "hg import" disallows combination of '--exact' +and '--edit') - $ HGEDITOR=cat hg import --bypass --exact --edit ../test.diff + $ hg import --bypass --exact --edit ../test.diff + abort: cannot use --exact with --edit + [255] + $ hg import --bypass --exact ../test.diff applying ../test.diff $ shortlog o 1:4e322f7ce8e3 test 0 0 - foo - changea @@ -66,8 +69,10 @@ repository tip rolled back to revision 1 (undo import) Test --import-branch +(this also tests that editor is not invoked for '--bypass', if the +patch contains the commit message, regardless of '--edit') - $ hg import --bypass --import-branch ../test.diff + $ HGEDITOR=cat hg import --bypass --import-branch --edit ../test.diff applying ../test.diff $ shortlog o 1:4e322f7ce8e3 test 0 0 - foo - changea @@ -221,6 +226,25 @@ $ cd .. +Test avoiding editor invocation at applying the patch with --exact +even if commit message is empty + + $ cd repo-options + + $ echo a >> a + $ hg commit -m ' ' + $ hg tip -T "{node}\n" + 1b77bc7d1db9f0e7f1716d515b630516ab386c89 + $ hg export -o ../empty-log.diff . + $ hg update -q -C ".^1" + $ hg --config extensions.strip= strip -q tip + $ HGEDITOR=cat hg import --exact --bypass ../empty-log.diff + applying ../empty-log.diff + $ hg tip -T "{node}\n" + 1b77bc7d1db9f0e7f1716d515b630516ab386c89 + + $ cd .. + #if symlink execbit Test complicated patch with --exact
--- a/tests/test-import-merge.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-import-merge.t Sat Sep 27 14:47:52 2014 -0500 @@ -30,6 +30,7 @@ (branch merge, don't forget to commit) $ hg ci -m merge $ hg export . > ../merge.diff + $ grep -v '^merge$' ../merge.diff > ../merge.nomsg.diff $ cd .. $ hg clone -r2 repo repo2 adding changesets @@ -52,8 +53,13 @@ $ hg up 1 0 files updated, 0 files merged, 1 files removed, 0 files unresolved - $ hg import ../merge.diff - applying ../merge.diff + $ cat > $TESTTMP/editor.sh <<EOF + > env | grep HGEDITFORM + > echo merge > \$1 + > EOF + $ HGEDITOR="sh $TESTTMP/editor.sh" hg import --edit ../merge.nomsg.diff + applying ../merge.nomsg.diff + HGEDITFORM=import.normal.merge $ tipparents 1:540395c44225 changea 3:102a90ea7b4a addb
--- a/tests/test-import.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-import.t Sat Sep 27 14:47:52 2014 -0500 @@ -90,8 +90,13 @@ added 1 changesets with 2 changes to 2 files updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved - $ HGEDITOR=cat hg --cwd b import ../diffed-tip.patch + $ cat > $TESTTMP/editor.sh <<EOF + > env | grep HGEDITFORM + > cat \$1 + > EOF + $ HGEDITOR="sh $TESTTMP/editor.sh" hg --cwd b import ../diffed-tip.patch applying ../diffed-tip.patch + HGEDITFORM=import.normal.normal HG: Enter commit message. Lines beginning with 'HG:' are removed. @@ -102,6 +107,22 @@ HG: changed a abort: empty commit message [255] + +Test avoiding editor invocation at applying the patch with --exact, +even if commit message is empty + + $ echo a >> b/a + $ hg --cwd b commit -m ' ' + $ hg --cwd b tip -T "{node}\n" + d8804f3f5396d800812f579c8452796a5993bdb2 + $ hg --cwd b export -o ../empty-log.diff . + $ hg --cwd b update -q -C ".^1" + $ hg --cwd b --config extensions.strip= strip -q tip + $ HGEDITOR=cat hg --cwd b import --exact ../empty-log.diff + applying ../empty-log.diff + $ hg --cwd b tip -T "{node}\n" + d8804f3f5396d800812f579c8452796a5993bdb2 + $ rm -r b
--- a/tests/test-incoming-outgoing.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-incoming-outgoing.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve $ hg init test $ cd test
--- a/tests/test-inherit-mode.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-inherit-mode.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,7 +1,6 @@ -test that new files created in .hg inherit the permissions from .hg/store +#require unix-permissions - - $ "$TESTDIR/hghave" unix-permissions || exit 80 +test that new files created in .hg inherit the permissions from .hg/store $ mkdir dir @@ -121,7 +120,6 @@ 00660 ../push/.hg/store/data/dir/bar.i 00660 ../push/.hg/store/data/foo.i 00660 ../push/.hg/store/fncache - 00660 ../push/.hg/store/phaseroots 00660 ../push/.hg/store/undo 00660 ../push/.hg/store/undo.phaseroots 00660 ../push/.hg/undo.bookmarks
--- a/tests/test-issue1438.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-issue1438.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,6 +1,6 @@ -http://mercurial.selenic.com/bts/issue1438 +#require symlink - $ "$TESTDIR/hghave" symlink || exit 80 +http://mercurial.selenic.com/bts/issue1438 $ hg init
--- a/tests/test-issue1802.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-issue1802.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" execbit || exit 80 +#require execbit Create extension that can disable exec checks:
--- a/tests/test-issue3084.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-issue3084.t Sat Sep 27 14:47:52 2014 -0500 @@ -29,10 +29,10 @@ $ echo "n" | hg merge --config ui.interactive=Yes remote turned local normal file foo into a largefile - use (l)argefile or keep (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + use (l)argefile or keep (n)ormal file? getting changed largefiles + 0 largefiles updated, 0 removed + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 0 largefiles updated, 0 removed $ hg status $ cat foo @@ -43,10 +43,10 @@ $ hg update -q -C $ echo "l" | hg merge --config ui.interactive=Yes remote turned local normal file foo into a largefile - use (l)argefile or keep (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + use (l)argefile or keep (n)ormal file? getting changed largefiles + 1 largefiles updated, 0 removed + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ hg status M foo @@ -71,10 +71,10 @@ $ hg update -q -C -r 1 $ echo "n" | hg merge --config ui.interactive=Yes remote turned local largefile foo into a normal file - keep (l)argefile or use (n)ormal file? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + keep (l)argefile or use (n)ormal file? getting changed largefiles + 0 largefiles updated, 0 removed + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 0 largefiles updated, 0 removed $ hg status M foo @@ -99,10 +99,10 @@ $ hg update -q -C -r 1 $ echo "l" | hg merge --config ui.interactive=Yes remote turned local largefile foo into a normal file - keep (l)argefile or use (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + keep (l)argefile or use (n)ormal file? getting changed largefiles + 1 largefiles updated, 0 removed + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ hg status @@ -206,10 +206,10 @@ $ hg up -Cqr normal= $ hg merge -r large + getting changed largefiles + 1 largefiles updated, 0 removed 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ cat f large @@ -217,10 +217,10 @@ $ hg up -Cqr large $ hg merge -r normal= + getting changed largefiles + 0 largefiles updated, 0 removed 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 0 largefiles updated, 0 removed $ cat f large @@ -233,10 +233,10 @@ use (c)hanged version or (d)elete? c remote turned local normal file f into a largefile use (l)argefile or keep (n)ormal file? l + getting changed largefiles + 1 largefiles updated, 0 removed 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ cat f large @@ -244,20 +244,20 @@ $ ( echo c; echo n ) | hg merge -r large --config ui.interactive=Yes local changed f which remote deleted use (c)hanged version or (d)elete? remote turned local normal file f into a largefile - use (l)argefile or keep (n)ormal file? 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + use (l)argefile or keep (n)ormal file? getting changed largefiles + 0 largefiles updated, 0 removed + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 0 largefiles updated, 0 removed $ cat f normal2 $ hg up -Cqr normal2 $ echo d | hg merge -r large --config ui.interactive=Yes local changed f which remote deleted - use (c)hanged version or (d)elete? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + use (c)hanged version or (d)elete? getting changed largefiles + 1 largefiles updated, 0 removed + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ cat f large @@ -269,10 +269,10 @@ use (c)hanged version or leave (d)eleted? c remote turned local largefile f into a normal file keep (l)argefile or use (n)ormal file? l + getting changed largefiles + 1 largefiles updated, 0 removed 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ cat f large @@ -280,20 +280,20 @@ $ ( echo c; echo n ) | hg merge -r normal2 --config ui.interactive=Yes remote changed f which local deleted use (c)hanged version or leave (d)eleted? remote turned local largefile f into a normal file - keep (l)argefile or use (n)ormal file? 2 files updated, 0 files merged, 1 files removed, 0 files unresolved + keep (l)argefile or use (n)ormal file? getting changed largefiles + 0 largefiles updated, 0 removed + 2 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 0 largefiles updated, 0 removed $ cat f normal2 $ hg up -Cqr large $ echo d | hg merge -r normal2 --config ui.interactive=Yes remote changed f which local deleted - use (c)hanged version or leave (d)eleted? 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + use (c)hanged version or leave (d)eleted? getting changed largefiles + 0 largefiles updated, 0 removed + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 0 largefiles updated, 0 removed $ cat f large @@ -301,10 +301,10 @@ $ hg up -Cqr large= $ hg merge -r normal + getting changed largefiles + 0 largefiles updated, 0 removed 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 0 largefiles updated, 0 removed $ cat f normal @@ -326,20 +326,20 @@ use (c)hanged version or (d)elete? c remote turned local largefile f into a normal file keep (l)argefile or use (n)ormal file? l + getting changed largefiles + 1 largefiles updated, 0 removed 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ cat f large2 $ hg up -Cqr large2 $ echo d | hg merge -r normal --config ui.interactive=Yes local changed .hglf/f which remote deleted - use (c)hanged version or (d)elete? 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + use (c)hanged version or (d)elete? getting changed largefiles + 0 largefiles updated, 0 removed + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 0 largefiles updated, 0 removed $ cat f normal @@ -351,10 +351,10 @@ use (c)hanged version or leave (d)eleted? c remote turned local normal file f into a largefile use (l)argefile or keep (n)ormal file? l + getting changed largefiles + 1 largefiles updated, 0 removed 2 files updated, 0 files merged, 1 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ cat f large2
--- a/tests/test-known.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-known.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons = Test the known() protocol function =
--- a/tests/test-largefiles-misc.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-largefiles-misc.t Sat Sep 27 14:47:52 2014 -0500 @@ -659,10 +659,10 @@ R d1/f $ hg merge merging d2/f and d1/f to d2/f + getting changed largefiles + 0 largefiles updated, 0 removed 1 files updated, 1 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 0 largefiles updated, 0 removed $ cd .. @@ -725,10 +725,10 @@ ancestor was 09d2af8dd22201dd8d48e5dcfcaed281ff9422c7 keep (l)ocal e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e or take (o)ther 7448d8798a4380162d4b56f9b452e2f6f9e24e7a? l + getting changed largefiles + 1 largefiles updated, 0 removed 0 files updated, 4 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ cat f-different 1 $ cat f-same
--- a/tests/test-largefiles-update.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-largefiles-update.t Sat Sep 27 14:47:52 2014 -0500 @@ -36,10 +36,10 @@ $ cat .hglf/large1 4669e532d5b2c093a78eca010077e708a071bb64 $ hg merge --config debug.dirstate.delaywrite=2 + getting changed largefiles + 1 largefiles updated, 0 removed 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ hg status -A large1 M large1 $ cat large1 @@ -67,10 +67,10 @@ take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? merging normal1 warning: conflicts during merge. merging normal1 incomplete! (edit conflicts, then use 'hg resolve --mark') + getting changed largefiles + 1 largefiles updated, 0 removed 0 files updated, 1 files merged, 0 files removed, 1 files unresolved use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon - getting changed largefiles - 1 largefiles updated, 0 removed [1] $ hg status -A large1 M large1 @@ -99,4 +99,421 @@ $ cat .hglf/large1 58e24f733a964da346e2407a2bee99d9001184f5 +Test that "hg rollback" restores status of largefiles correctly + + $ hg update -C -q + $ hg remove large1 + $ test -f .hglf/large1 + [1] + $ hg forget large2 + $ test -f .hglf/large2 + [1] + $ echo largeX > largeX + $ hg add --large largeX + $ cat .hglf/largeX + + $ hg commit -m 'will be rollback-ed soon' + $ echo largeY > largeY + $ hg add --large largeY + $ hg status -A large1 + large1: No such file or directory + $ hg status -A large2 + ? large2 + $ hg status -A largeX + C largeX + $ hg status -A largeY + A largeY + $ hg rollback + repository tip rolled back to revision 3 (undo commit) + working directory now based on revision 3 + $ hg status -A large1 + R large1 + $ test -f .hglf/large1 + [1] + $ hg status -A large2 + R large2 + $ test -f .hglf/large2 + [1] + $ hg status -A largeX + A largeX + $ cat .hglf/largeX + + $ hg status -A largeY + ? largeY + $ test -f .hglf/largeY + [1] + +Test that "hg rollback" restores standins correctly + + $ hg commit -m 'will be rollback-ed soon' + $ hg update -q -C 2 + $ cat large1 + large1 + $ cat .hglf/large1 + 4669e532d5b2c093a78eca010077e708a071bb64 + $ cat large2 + large2 in #2 + $ cat .hglf/large2 + 3cfce6277e7668985707b6887ce56f9f62f6ccd9 + + $ hg rollback -q -f + $ cat large1 + large1 + $ cat .hglf/large1 + 4669e532d5b2c093a78eca010077e708a071bb64 + $ cat large2 + large2 in #2 + $ cat .hglf/large2 + 3cfce6277e7668985707b6887ce56f9f62f6ccd9 + +(rollback the parent of the working directory, when the parent of it +is not branch-tip) + + $ hg update -q -C 1 + $ cat .hglf/large1 + 58e24f733a964da346e2407a2bee99d9001184f5 + $ cat .hglf/large2 + 1deebade43c8c498a3c8daddac0244dc55d1331d + + $ echo normalX > normalX + $ hg add normalX + $ hg commit -m 'will be rollback-ed soon' + $ hg rollback -q + + $ cat .hglf/large1 + 58e24f733a964da346e2407a2bee99d9001184f5 + $ cat .hglf/large2 + 1deebade43c8c498a3c8daddac0244dc55d1331d + +Test that "hg status" shows status of largefiles correctly just after +automated commit like rebase/transplant + + $ cat >> .hg/hgrc <<EOF + > [extensions] + > rebase = + > strip = + > transplant = + > EOF + $ hg update -q -C 1 + $ hg remove large1 + $ echo largeX > largeX + $ hg add --large largeX + $ hg commit -m '#4' + + $ hg rebase -s 1 -d 2 --keep + $ hg status -A large1 + large1: No such file or directory + $ hg status -A largeX + C largeX + $ hg strip -q 5 + + $ hg update -q -C 2 + $ hg transplant -q 1 4 + $ hg status -A large1 + large1: No such file or directory + $ hg status -A largeX + C largeX + $ hg strip -q 5 + + $ hg update -q -C 2 + $ hg transplant -q --merge 1 --merge 4 + $ hg status -A large1 + large1: No such file or directory + $ hg status -A largeX + C largeX + $ hg strip -q 5 + +Test that linear merge can detect modification (and conflict) correctly + +(linear merge without conflict) + + $ echo 'large2 for linear merge (no conflict)' > large2 + $ hg update 3 --config debug.dirstate.delaywrite=2 + getting changed largefiles + 1 largefiles updated, 0 removed + 2 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ hg status -A large2 + M large2 + $ cat large2 + large2 for linear merge (no conflict) + $ cat .hglf/large2 + 9c4bf8f1b33536d6e5f89447e10620cfe52ea710 + +(linear merge with conflict, choosing "other") + + $ hg update -q -C 2 + $ echo 'large1 for linear merge (conflict)' > large1 + $ hg update 3 --config ui.interactive=True <<EOF + > o + > EOF + largefile large1 has a merge conflict + ancestor was 4669e532d5b2c093a78eca010077e708a071bb64 + keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or + take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? getting changed largefiles + 1 largefiles updated, 0 removed + 1 files updated, 1 files merged, 0 files removed, 0 files unresolved + $ hg status -A large1 + C large1 + $ cat large1 + large1 in #3 + $ cat .hglf/large1 + e5bb990443d6a92aaf7223813720f7566c9dd05b + +(linear merge with conflict, choosing "local") + + $ hg update -q -C 2 + $ echo 'large1 for linear merge (conflict)' > large1 + $ hg update 3 --config debug.dirstate.delaywrite=2 + largefile large1 has a merge conflict + ancestor was 4669e532d5b2c093a78eca010077e708a071bb64 + keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or + take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l + 1 files updated, 1 files merged, 0 files removed, 0 files unresolved + $ hg status -A large1 + M large1 + $ cat large1 + large1 for linear merge (conflict) + $ cat .hglf/large1 + ba94c2efe5b7c5e0af8d189295ce00553b0612b7 + +Test a linear merge to a revision containing same-name normal file + + $ hg update -q -C 3 + $ hg remove large2 + $ echo 'large2 as normal file' > large2 + $ hg add large2 + $ echo 'large3 as normal file' > large3 + $ hg add large3 + $ hg commit -m '#5' + $ hg manifest + .hglf/large1 + large2 + large3 + normal1 + +(modified largefile is already switched to normal) + + $ hg update -q -C 2 + $ echo 'modified large2 for linear merge' > large2 + $ hg update -q 5 + local changed .hglf/large2 which remote deleted + use (c)hanged version or (d)elete? c + remote turned local largefile large2 into a normal file + keep (l)argefile or use (n)ormal file? l + $ hg debugdirstate --nodates | grep large2 + a 0 -1 .hglf/large2 + r 0 0 large2 + $ hg status -A large2 + A large2 + $ cat large2 + modified large2 for linear merge + +(added largefile is already committed as normal) + + $ hg update -q -C 2 + $ echo 'large3 as large file for linear merge' > large3 + $ hg add --large large3 + $ hg update -q 5 + remote turned local largefile large3 into a normal file + keep (l)argefile or use (n)ormal file? l + $ hg debugdirstate --nodates | grep large3 + a 0 -1 .hglf/large3 + r 0 0 large3 + $ hg status -A large3 + A large3 + $ cat large3 + large3 as large file for linear merge + $ rm -f large3 .hglf/large3 + +Test that the internal linear merging works correctly +(both heads are stripped to keep pairing of revision number and commit log) + + $ hg update -q -C 2 + $ hg strip 3 4 + saved backup bundle to $TESTTMP/repo/.hg/strip-backup/9530e27857f7-backup.hg (glob) + $ mv .hg/strip-backup/9530e27857f7-backup.hg $TESTTMP + +(internal linear merging at "hg pull --update") + + $ echo 'large1 for linear merge (conflict)' > large1 + $ echo 'large2 for linear merge (conflict with normal file)' > large2 + $ hg pull --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-backup.hg + pulling from $TESTTMP/9530e27857f7-backup.hg (glob) + searching for changes + adding changesets + adding manifests + adding file changes + added 3 changesets with 5 changes to 5 files + local changed .hglf/large2 which remote deleted + use (c)hanged version or (d)elete? c + remote turned local largefile large2 into a normal file + keep (l)argefile or use (n)ormal file? l + largefile large1 has a merge conflict + ancestor was 4669e532d5b2c093a78eca010077e708a071bb64 + keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or + take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l + 2 files updated, 1 files merged, 0 files removed, 0 files unresolved + + $ hg status -A large1 + M large1 + $ cat large1 + large1 for linear merge (conflict) + $ cat .hglf/large1 + ba94c2efe5b7c5e0af8d189295ce00553b0612b7 + $ hg status -A large2 + A large2 + $ cat large2 + large2 for linear merge (conflict with normal file) + $ cat .hglf/large2 + d7591fe9be0f6227d90bddf3e4f52ff41fc1f544 + +(internal linear merging at "hg unbundle --update") + + $ hg update -q -C 2 + $ hg rollback -q + + $ echo 'large1 for linear merge (conflict)' > large1 + $ echo 'large2 for linear merge (conflict with normal file)' > large2 + $ hg unbundle --update --config debug.dirstate.delaywrite=2 $TESTTMP/9530e27857f7-backup.hg + adding changesets + adding manifests + adding file changes + added 3 changesets with 5 changes to 5 files + local changed .hglf/large2 which remote deleted + use (c)hanged version or (d)elete? c + remote turned local largefile large2 into a normal file + keep (l)argefile or use (n)ormal file? l + largefile large1 has a merge conflict + ancestor was 4669e532d5b2c093a78eca010077e708a071bb64 + keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or + take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? l + 2 files updated, 1 files merged, 0 files removed, 0 files unresolved + + $ hg status -A large1 + M large1 + $ cat large1 + large1 for linear merge (conflict) + $ cat .hglf/large1 + ba94c2efe5b7c5e0af8d189295ce00553b0612b7 + $ hg status -A large2 + A large2 + $ cat large2 + large2 for linear merge (conflict with normal file) + $ cat .hglf/large2 + d7591fe9be0f6227d90bddf3e4f52ff41fc1f544 + +(internal linear merging in subrepo at "hg update") + $ cd .. + $ hg init subparent + $ cd subparent + + $ hg clone -q -u 2 ../repo sub + $ cat > .hgsub <<EOF + > sub = sub + > EOF + $ hg add .hgsub + $ hg commit -m '#0@parent' + $ cat .hgsubstate + f74e50bd9e5594b7cf1e6c5cbab86ddd25f3ca2f sub + $ hg -R sub update -q + $ hg commit -m '#1@parent' + $ cat .hgsubstate + d65e59e952a9638e2ce863b41a420ca723dd3e8d sub + $ hg update -q 0 + + $ echo 'large1 for linear merge (conflict)' > sub/large1 + $ echo 'large2 for linear merge (conflict with normal file)' > sub/large2 + $ hg update --config ui.interactive=True --config debug.dirstate.delaywrite=2 <<EOF + > m + > r + > c + > l + > l + > EOF + subrepository sub diverged (local revision: f74e50bd9e55, remote revision: d65e59e952a9) + (M)erge, keep (l)ocal or keep (r)emote? subrepository sources for sub differ (in checked out version) + use (l)ocal source (f74e50bd9e55) or (r)emote source (d65e59e952a9)? + local changed .hglf/large2 which remote deleted + use (c)hanged version or (d)elete? remote turned local largefile large2 into a normal file + keep (l)argefile or use (n)ormal file? largefile large1 has a merge conflict + ancestor was 4669e532d5b2c093a78eca010077e708a071bb64 + keep (l)ocal ba94c2efe5b7c5e0af8d189295ce00553b0612b7 or + take (o)ther e5bb990443d6a92aaf7223813720f7566c9dd05b? 2 files updated, 1 files merged, 0 files removed, 0 files unresolved + 0 files updated, 0 files merged, 0 files removed, 0 files unresolved + + $ hg -R sub status -A sub/large1 + M sub/large1 + $ cat sub/large1 + large1 for linear merge (conflict) + $ cat sub/.hglf/large1 + ba94c2efe5b7c5e0af8d189295ce00553b0612b7 + $ hg -R sub status -A sub/large2 + A sub/large2 + $ cat sub/large2 + large2 for linear merge (conflict with normal file) + $ cat sub/.hglf/large2 + d7591fe9be0f6227d90bddf3e4f52ff41fc1f544 + + $ cd .. + $ cd repo + +Test that rebase updates largefiles in the working directory even if +it is aborted by conflict. + + $ hg update -q -C 3 + $ cat .hglf/large1 + e5bb990443d6a92aaf7223813720f7566c9dd05b + $ cat large1 + large1 in #3 + $ hg rebase -s 1 -d 3 --keep --config ui.interactive=True <<EOF + > o + > EOF + largefile large1 has a merge conflict + ancestor was 4669e532d5b2c093a78eca010077e708a071bb64 + keep (l)ocal e5bb990443d6a92aaf7223813720f7566c9dd05b or + take (o)ther 58e24f733a964da346e2407a2bee99d9001184f5? merging normal1 + warning: conflicts during merge. + merging normal1 incomplete! (edit conflicts, then use 'hg resolve --mark') + unresolved conflicts (see hg resolve, then hg rebase --continue) + [1] + $ cat .hglf/large1 + 58e24f733a964da346e2407a2bee99d9001184f5 + $ cat large1 + large1 in #1 + + $ hg rebase -q --abort + rebase aborted + +Test that transplant updates largefiles, of which standins are safely +changed, even if it is aborted by conflict of other. + + $ hg update -q -C 5 + $ cat .hglf/large1 + e5bb990443d6a92aaf7223813720f7566c9dd05b + $ cat large1 + large1 in #3 + $ hg diff -c 4 .hglf/largeX | grep '^[+-][0-9a-z]' + +fa44618ea25181aff4f48b70428294790cec9f61 + $ hg transplant 4 + applying 07d6153b5c04 + patching file .hglf/large1 + Hunk #1 FAILED at 0 + 1 out of 1 hunks FAILED -- saving rejects to file .hglf/large1.rej + patch failed to apply + abort: fix up the merge and run hg transplant --continue + [255] + $ hg status -A large1 + C large1 + $ cat .hglf/large1 + e5bb990443d6a92aaf7223813720f7566c9dd05b + $ cat large1 + large1 in #3 + $ hg status -A largeX + A largeX + $ cat .hglf/largeX + fa44618ea25181aff4f48b70428294790cec9f61 + $ cat largeX + largeX + + $ cd ..
--- a/tests/test-largefiles.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-largefiles.t Sat Sep 27 14:47:52 2014 -0500 @@ -598,7 +598,7 @@ C sub2/large6 C sub2/large7 -Test commit -A (issue 3542) +Test commit -A (issue3542) $ echo large8 > large8 $ hg add --large large8 $ hg ci -Am 'this used to add large8 as normal and commit both' @@ -1496,7 +1496,6 @@ $ cat sub2/large6 large6 $ hg revert --no-backup -C -r '.^' sub2 - reverting .hglf/sub2/large6 (glob) $ hg revert --no-backup sub2 reverting .hglf/sub2/large6 (glob) $ hg status @@ -1604,11 +1603,11 @@ A f created new head $ hg merge -r 6 - 4 files updated, 0 files merged, 0 files removed, 0 files unresolved - (branch merge, don't forget to commit) getting changed largefiles large3: largefile 7838695e10da2bb75ac1156565f40a2595fa2fa0 not available from file:/*/$TESTTMP/d (glob) 1 largefiles updated, 0 removed + 4 files updated, 0 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) $ hg rollback -q $ hg up -Cq @@ -1662,10 +1661,10 @@ ancestor was 971fb41e78fea4f8e0ba5244784239371cb00591 keep (l)ocal d846f26643bfa8ec210be40cc93cc6b7ff1128ea or take (o)ther e166e74c7303192238d60af5a9c4ce9bef0b7928? l + getting changed largefiles + 1 largefiles updated, 0 removed 3 files updated, 1 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ hg commit -m "Merge repos e and f" Invoking status precommit hook M normal3 @@ -1696,10 +1695,10 @@ M normal3 created new head $ hg merge + getting changed largefiles + 1 largefiles updated, 0 removed 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) - getting changed largefiles - 1 largefiles updated, 0 removed $ hg status M large @@ -1743,7 +1742,7 @@ adding file changes added 1 changesets with 2 changes to 2 files getting changed largefiles - 1 largefiles updated, 0 removed + 0 largefiles updated, 0 removed $ hg log --template '{rev}:{node|short} {desc|firstline}\n' 9:598410d3eb9a modify normal file largefile in repo d 8:a381d2c8c80e modify normal file and largefile in repo b
--- a/tests/test-locate.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-locate.t Sat Sep 27 14:47:52 2014 -0500 @@ -92,6 +92,16 @@ t/e.h (glob) t/x (glob) + $ hg files + b + dir.h/foo + t.h + t/b + t/e.h + t/x + $ hg files b + b + $ mkdir otherdir $ cd otherdir @@ -118,4 +128,14 @@ ../t.h (glob) ../t/e.h (glob) + $ hg files + ../b + ../dir.h/foo + ../t.h + ../t/b + ../t/e.h + ../t/x + $ hg files . + [1] + $ cd ../..
--- a/tests/test-lock-badness.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-lock-badness.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ -#if unix-permissions no-root no-windows +#require unix-permissions no-root no-windows Prepare @@ -39,4 +39,3 @@ [255] $ chmod 700 a/.hg/store -#endif
--- a/tests/test-log.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-log.t Sat Sep 27 14:47:52 2014 -0500 @@ -78,12 +78,52 @@ summary: c --f, directory +-f, non-existent directory $ hg log -f dir abort: cannot follow file not in parent revision: "dir" [255] +-f, directory + + $ hg up -q 3 + $ hg log -f dir + changeset: 2:f8954cd4dc1f + user: test + date: Thu Jan 01 00:00:03 1970 +0000 + summary: c + +-f, directory with --patch + + $ hg log -f dir -p + changeset: 2:f8954cd4dc1f + user: test + date: Thu Jan 01 00:00:03 1970 +0000 + summary: c + + diff -r d89b0a12d229 -r f8954cd4dc1f dir/b + --- /dev/null* (glob) + +++ b/dir/b* (glob) + @@ -0,0 +1,1 @@ + +a + + +-f, pattern + + $ hg log -f -I 'dir**' -p + changeset: 2:f8954cd4dc1f + user: test + date: Thu Jan 01 00:00:03 1970 +0000 + summary: c + + diff -r d89b0a12d229 -r f8954cd4dc1f dir/b + --- /dev/null* (glob) + +++ b/dir/b* (glob) + @@ -0,0 +1,1 @@ + +a + + $ hg up -q 4 + -f, a wrong style $ hg log -f -l1 --style something
--- a/tests/test-manifest.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-manifest.t Sat Sep 27 14:47:52 2014 -0500 @@ -24,6 +24,14 @@ b/a l + $ hg files -vr . + 2 a + 2 x b/a + 1 l l + $ hg files -r . -X b + a + l + $ hg manifest -v 644 a 755 * b/a
--- a/tests/test-merge-default.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-merge-default.t Sat Sep 27 14:47:52 2014 -0500 @@ -97,8 +97,7 @@ Test for issue2043: ensure that 'merge -P' shows ancestors of 6 that -are not ancestors of 7, regardless of where their least common -ancestor is. +are not ancestors of 7, regardless of where their common ancestors are. Merge preview not affected by common ancestor:
--- a/tests/test-merge-tools.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-merge-tools.t Sat Sep 27 14:47:52 2014 -0500 @@ -30,6 +30,14 @@ $ echo "revision 3" >> f $ hg commit -Am "revision 3" created new head + +revision 4 - hard to merge + + $ hg update 0 > /dev/null + $ echo "revision 4" > f + $ hg commit -Am "revision 4" + created new head + $ echo "[merge-tools]" > .hg/hgrc $ beforemerge() { @@ -701,6 +709,77 @@ # hg stat M f +premerge=keep keeps conflict markers in: + + $ beforemerge + [merge-tools] + false.whatever= + true.priority=1 + true.executable=cat + # hg update -C 1 + $ hg merge -r 4 --config merge-tools.true.premerge=keep + merging f + <<<<<<< local: ef83787e2614 - test: revision 1 + revision 1 + space + ======= + revision 4 + >>>>>>> other: 81448d39c9a0 - test: revision 4 + revision 0 + space + revision 4 + 0 files updated, 1 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + $ aftermerge + # cat f + <<<<<<< local: ef83787e2614 - test: revision 1 + revision 1 + space + ======= + revision 4 + >>>>>>> other: 81448d39c9a0 - test: revision 4 + # hg stat + M f + +premerge=keep-merge3 keeps conflict markers with base content: + + $ beforemerge + [merge-tools] + false.whatever= + true.priority=1 + true.executable=cat + # hg update -C 1 + $ hg merge -r 4 --config merge-tools.true.premerge=keep-merge3 + merging f + <<<<<<< local: ef83787e2614 - test: revision 1 + revision 1 + space + ||||||| base + revision 0 + space + ======= + revision 4 + >>>>>>> other: 81448d39c9a0 - test: revision 4 + revision 0 + space + revision 4 + 0 files updated, 1 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + $ aftermerge + # cat f + <<<<<<< local: ef83787e2614 - test: revision 1 + revision 1 + space + ||||||| base + revision 0 + space + ======= + revision 4 + >>>>>>> other: 81448d39c9a0 - test: revision 4 + # hg stat + M f + + Tool execution set tools.args explicit to include $base $local $other $output: @@ -832,17 +911,17 @@ true.priority=1 true.executable=cat # hg update -C 1 - $ echo "revision 4" > '"; exit 1; echo "' - $ hg commit -Am "revision 4" - adding "; exit 1; echo " - warning: filename contains '"', which is reserved on Windows: '"; exit 1; echo "' - $ hg update -C 1 > /dev/null $ echo "revision 5" > '"; exit 1; echo "' $ hg commit -Am "revision 5" adding "; exit 1; echo " warning: filename contains '"', which is reserved on Windows: '"; exit 1; echo "' + $ hg update -C 1 > /dev/null + $ echo "revision 6" > '"; exit 1; echo "' + $ hg commit -Am "revision 6" + adding "; exit 1; echo " + warning: filename contains '"', which is reserved on Windows: '"; exit 1; echo "' created new head - $ hg merge --config merge-tools.true.executable="true" -r 4 + $ hg merge --config merge-tools.true.executable="true" -r 5 merging "; exit 1; echo " 0 files updated, 1 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit)
--- a/tests/test-merge-types.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-merge-types.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" symlink execbit || exit 80 +#require symlink execbit $ tellmeabout() { > if [ -h $1 ]; then
--- a/tests/test-mq-eol.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-eol.t Sat Sep 27 14:47:52 2014 -0500 @@ -84,6 +84,8 @@ now at: eol.diff $ hg qrefresh $ python ../cateol.py .hg/patches/eol.diff + # HG changeset patch<LF> + # Parent 0d0bf99a8b7a3842c6f8ef09e34f69156c4bd9d0<LF> test message<LF> <LF> diff -r 0d0bf99a8b7a a<LF>
--- a/tests/test-mq-git.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-git.t Sat Sep 27 14:47:52 2014 -0500 @@ -17,8 +17,8 @@ $ cat .hg/patches/adda # HG changeset patch - # Parent 0000000000000000000000000000000000000000 # Date 0 0 + # Parent 0000000000000000000000000000000000000000 diff -r 000000000000 -r ef8dafc9fa4c a --- /dev/null @@ -33,8 +33,8 @@ $ cat .hg/patches/copy # HG changeset patch - # Parent ef8dafc9fa4caff80f6e243eb0171bcd60c455b4 # Date 0 0 + # Parent ef8dafc9fa4caff80f6e243eb0171bcd60c455b4 diff --git a/a b/b copy from a @@ -48,8 +48,8 @@ $ cat .hg/patches/git # HG changeset patch - # Parent 99586d5f048c399e20f81cee41fbb3809c0e735d # Date 0 0 + # Parent 99586d5f048c399e20f81cee41fbb3809c0e735d diff --git a/regular b/regular new file mode 100644 @@ -64,8 +64,8 @@ $ cat .hg/patches/git # HG changeset patch - # Parent 99586d5f048c399e20f81cee41fbb3809c0e735d # Date 0 0 + # Parent 99586d5f048c399e20f81cee41fbb3809c0e735d diff -r 99586d5f048c regular --- /dev/null @@ -88,8 +88,8 @@ $ cat .hg/patches/git # HG changeset patch - # Parent 0000000000000000000000000000000000000000 # Date 0 0 + # Parent 0000000000000000000000000000000000000000 diff --git a/a b/a new file mode 100644 @@ -105,8 +105,8 @@ $ cat .hg/patches/git # HG changeset patch - # Parent 0000000000000000000000000000000000000000 # Date 0 0 + # Parent 0000000000000000000000000000000000000000 diff --git a/a b/a new file mode 100644 @@ -130,8 +130,8 @@ $ cat .hg/patches/git # HG changeset patch - # Parent 0000000000000000000000000000000000000000 # Date 0 0 + # Parent 0000000000000000000000000000000000000000 diff --git a/a b/a new file mode 100644 @@ -147,8 +147,8 @@ $ cat .hg/patches/git # HG changeset patch - # Parent 0000000000000000000000000000000000000000 # Date 0 0 + # Parent 0000000000000000000000000000000000000000 diff --git a/a b/a new file mode 100644 @@ -176,8 +176,8 @@ $ cat .hg/patches/regular # HG changeset patch - # Parent ef8dafc9fa4caff80f6e243eb0171bcd60c455b4 # Date 0 0 + # Parent ef8dafc9fa4caff80f6e243eb0171bcd60c455b4 diff -r ef8dafc9fa4c -r a70404f79ba3 b --- /dev/null @@ -192,8 +192,8 @@ $ cat .hg/patches/regular # HG changeset patch - # Parent ef8dafc9fa4caff80f6e243eb0171bcd60c455b4 # Date 0 0 + # Parent ef8dafc9fa4caff80f6e243eb0171bcd60c455b4 diff -r ef8dafc9fa4c b --- /dev/null
--- a/tests/test-mq-header-date.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-header-date.t Sat Sep 27 14:47:52 2014 -0500 @@ -243,7 +243,6 @@ now at: 1.patch ==== qnew -d -m Date: 6 0 - Three 1: Three - test - 6.00 @@ -251,7 +250,6 @@ ==== qref adding 3 Date: 6 0 - Three diff -r ... 3 @@ -263,7 +261,6 @@ 0: [mq]: 1.patch - test - 4.00 ==== qref -m Date: 6 0 - Drei diff -r ... 3 @@ -275,7 +272,6 @@ 0: [mq]: 1.patch - test - 4.00 ==== qref -d Date: 7 0 - Drei diff -r ... 3 @@ -287,7 +283,6 @@ 0: [mq]: 1.patch - test - 4.00 ==== qref -d -m Date: 8 0 - Three (again) diff -r ... 3 @@ -334,8 +329,8 @@ ==== hg qref adding 5 # HG changeset patch + # Date 10 0 # Parent - # Date 10 0 diff -r ... 5 --- /dev/null @@ -347,8 +342,8 @@ 0: [mq]: 1.patch - test - 4.00 ==== hg qref -d # HG changeset patch + # Date 11 0 # Parent - # Date 11 0 diff -r ... 5 --- /dev/null @@ -533,15 +528,15 @@ ==== init ==== qnew -d # HG changeset patch + # Date 3 0 # Parent - # Date 3 0 0: [mq]: 1.patch - test - 3.00 ==== qref adding 1 # HG changeset patch + # Date 3 0 # Parent - # Date 3 0 diff -r ... 1 --- /dev/null @@ -551,8 +546,8 @@ 0: [mq]: 1.patch - test - 3.00 ==== qref -d # HG changeset patch + # Date 4 0 # Parent - # Date 4 0 diff -r ... 1 --- /dev/null @@ -588,9 +583,8 @@ now at: 1.patch ==== qnew -d -m # HG changeset patch + # Date 6 0 # Parent - # Date 6 0 - Three 1: Three - test - 6.00 @@ -598,9 +592,8 @@ ==== qref adding 3 # HG changeset patch + # Date 6 0 # Parent - # Date 6 0 - Three diff -r ... 3 @@ -612,9 +605,8 @@ 0: [mq]: 1.patch - test - 4.00 ==== qref -m # HG changeset patch + # Date 6 0 # Parent - # Date 6 0 - Drei diff -r ... 3 @@ -626,9 +618,8 @@ 0: [mq]: 1.patch - test - 4.00 ==== qref -d # HG changeset patch + # Date 7 0 # Parent - # Date 7 0 - Drei diff -r ... 3 @@ -640,9 +631,8 @@ 0: [mq]: 1.patch - test - 4.00 ==== qref -d -m # HG changeset patch + # Date 8 0 # Parent - # Date 8 0 - Three (again) diff -r ... 3 @@ -693,8 +683,8 @@ ==== hg qref adding 5 # HG changeset patch + # Date 10 0 # Parent - # Date 10 0 diff -r ... 5 --- /dev/null @@ -706,8 +696,8 @@ 0: [mq]: 1.patch - test - 4.00 ==== hg qref -d # HG changeset patch + # Date 11 0 # Parent - # Date 11 0 diff -r ... 5 --- /dev/null @@ -757,8 +747,8 @@ ==== qnew -u adding 6 # HG changeset patch + # User jane # Parent - # User jane diff -r ... 6 --- /dev/null @@ -771,9 +761,9 @@ 0: [mq]: 1.patch - test ==== qref -d # HG changeset patch + # User jane # Date 12 0 # Parent - # User jane diff -r ... 6 --- /dev/null @@ -789,8 +779,8 @@ ==== qnew -d adding 7 # HG changeset patch + # Date 13 0 # Parent - # Date 13 0 diff -r ... 7 --- /dev/null @@ -804,8 +794,8 @@ ==== qref -u # HG changeset patch # User john + # Date 13 0 # Parent - # Date 13 0 diff -r ... 7 --- /dev/null @@ -833,8 +823,8 @@ 0: [mq]: 1.patch - test ==== qref -u -d # HG changeset patch + # User john # Date 14 0 - # User john # Parent diff -r ... 8 @@ -867,8 +857,8 @@ 0: [mq]: 1.patch - test ==== qref -u -d # HG changeset patch + # User john # Date 15 0 - # User john # Parent Nine
--- a/tests/test-mq-header-from.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-header-from.t Sat Sep 27 14:47:52 2014 -0500 @@ -176,7 +176,6 @@ 0: [mq]: 1.patch - mary ==== qnew -U -m From: test - Three 2: Three - test @@ -185,7 +184,6 @@ ==== qref adding 3 From: test - Three diff -r ... 3 @@ -198,7 +196,6 @@ 0: [mq]: 1.patch - mary ==== qref -m From: test - Drei diff -r ... 3 @@ -211,7 +208,6 @@ 0: [mq]: 1.patch - mary ==== qref -u From: mary - Drei diff -r ... 3 @@ -224,7 +220,6 @@ 0: [mq]: 1.patch - mary ==== qref -u -m From: maria - Three (again) diff -r ... 3 @@ -275,8 +270,8 @@ ==== hg qref adding 5 # HG changeset patch + # User johndoe # Parent - # User johndoe diff -r ... 5 --- /dev/null @@ -290,8 +285,8 @@ 0: [mq]: 1.patch - mary ==== hg qref -U # HG changeset patch + # User test # Parent - # User test diff -r ... 5 --- /dev/null @@ -305,8 +300,8 @@ 0: [mq]: 1.patch - mary ==== hg qref -u # HG changeset patch + # User johndeere # Parent - # User johndeere diff -r ... 5 --- /dev/null @@ -404,14 +399,15 @@ ==== init ==== qnew -U # HG changeset patch + # User test # Parent - # User test + 0: [mq]: 1.patch - test ==== qref adding 1 # HG changeset patch + # User test # Parent - # User test diff -r ... 1 --- /dev/null @@ -421,8 +417,8 @@ 0: [mq]: 1.patch - test ==== qref -u # HG changeset patch + # User mary # Parent - # User mary diff -r ... 1 --- /dev/null @@ -456,8 +452,8 @@ 0: [mq]: 1.patch - mary ==== qnew -U -m # HG changeset patch + # User test # Parent - # User test Three 2: Three - test @@ -466,8 +462,8 @@ ==== qref adding 3 # HG changeset patch + # User test # Parent - # User test Three diff -r ... 3 @@ -480,8 +476,8 @@ 0: [mq]: 1.patch - mary ==== qref -m # HG changeset patch + # User test # Parent - # User test Drei diff -r ... 3 @@ -494,8 +490,8 @@ 0: [mq]: 1.patch - mary ==== qref -u # HG changeset patch + # User mary # Parent - # User mary Drei diff -r ... 3 @@ -508,8 +504,8 @@ 0: [mq]: 1.patch - mary ==== qref -u -m # HG changeset patch + # User maria # Parent - # User maria Three (again) diff -r ... 3 @@ -564,8 +560,8 @@ ==== hg qref adding 5 # HG changeset patch + # User johndoe # Parent - # User johndoe diff -r ... 5 --- /dev/null @@ -579,8 +575,8 @@ 0: [mq]: 1.patch - mary ==== hg qref -U # HG changeset patch + # User test # Parent - # User test diff -r ... 5 --- /dev/null @@ -594,8 +590,8 @@ 0: [mq]: 1.patch - mary ==== hg qref -u # HG changeset patch + # User johndeere # Parent - # User johndeere diff -r ... 5 --- /dev/null @@ -688,14 +684,15 @@ ==== init ==== qnew -U # HG changeset patch + # User test # Parent - # User test + 0: [mq]: 1.patch - test ==== qref adding 1 # HG changeset patch + # User test # Parent - # User test diff -r ... 1 --- /dev/null @@ -705,8 +702,8 @@ 0: [mq]: 1.patch - test ==== qref -u # HG changeset patch + # User mary # Parent - # User mary diff -r ... 1 --- /dev/null @@ -740,8 +737,8 @@ 0: [mq]: 1.patch - mary ==== qnew -U -m # HG changeset patch + # User test # Parent - # User test Three 2: Three - test @@ -750,8 +747,8 @@ ==== qref adding 3 # HG changeset patch + # User test # Parent - # User test Three diff -r ... 3 @@ -764,8 +761,8 @@ 0: [mq]: 1.patch - mary ==== qref -m # HG changeset patch + # User test # Parent - # User test Drei diff -r ... 3 @@ -778,8 +775,8 @@ 0: [mq]: 1.patch - mary ==== qref -u # HG changeset patch + # User mary # Parent - # User mary Drei diff -r ... 3 @@ -792,8 +789,8 @@ 0: [mq]: 1.patch - mary ==== qref -u -m # HG changeset patch + # User maria # Parent - # User maria Three (again) diff -r ... 3 @@ -848,8 +845,8 @@ ==== hg qref adding 5 # HG changeset patch + # User johndoe # Parent - # User johndoe diff -r ... 5 --- /dev/null @@ -863,8 +860,8 @@ 0: [mq]: 1.patch - mary ==== hg qref -U # HG changeset patch + # User test # Parent - # User test diff -r ... 5 --- /dev/null @@ -878,8 +875,8 @@ 0: [mq]: 1.patch - mary ==== hg qref -u # HG changeset patch + # User johndeere # Parent - # User johndeere diff -r ... 5 --- /dev/null
--- a/tests/test-mq-merge.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-merge.t Sat Sep 27 14:47:52 2014 -0500 @@ -138,7 +138,7 @@ $ cat .hg/patches/patcha # HG changeset patch - # Parent d3873e73d99ef67873dac33fbcc66268d5d2b6f4 + # Parent d3873e73d99ef67873dac33fbcc66268d5d2b6f4 diff --git a/a b/a --- a/a @@ -160,8 +160,8 @@ $ cat .hg/patches/patcha2 # HG changeset patch - # Parent ???????????????????????????????????????? (glob) # Date 0 0 + # Parent ???????????????????????????????????????? (glob) diff -r ???????????? -r ???????????? a (glob) --- a/a
--- a/tests/test-mq-qclone-http.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-qclone-http.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons hide outer repo $ hg init
--- a/tests/test-mq-qfold.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-qfold.t Sat Sep 27 14:47:52 2014 -0500 @@ -87,7 +87,7 @@ $ cat .hg/patches/regular # HG changeset patch - # Parent ???????????????????????????????????????? (glob) + # Parent ???????????????????????????????????????? (glob) diff --git a/a b/a --- a/a @@ -129,7 +129,7 @@ $ cat .hg/patches/git # HG changeset patch - # Parent ???????????????????????????????????????? (glob) + # Parent ???????????????????????????????????????? (glob) diff --git a/a b/aa copy from a
--- a/tests/test-mq-qimport.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-qimport.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons $ cat > writelines.py <<EOF > import sys
--- a/tests/test-mq-qnew.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-qnew.t Sat Sep 27 14:47:52 2014 -0500 @@ -209,6 +209,7 @@ M d/b # HG changeset patch # Parent + diff --git a/d/b b/d/b --- a/d/b +++ b/d/b @@ -217,12 +218,14 @@ +b % qnew -u with no username configured # HG changeset patch + # User blue # Parent - # User blue + % qnew -e -u with no username configured # HG changeset patch + # User chartreuse # Parent - # User chartreuse + % fail when trying to import a merge adding a 1 files updated, 0 files merged, 0 files removed, 0 files unresolved @@ -336,7 +339,8 @@ ==== $ cat ".hg/patches/patch " # HG changeset patch - # Parent 0000000000000000000000000000000000000000 + # Parent 0000000000000000000000000000000000000000 + $ cd ..
--- a/tests/test-mq-qpush-fail.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-qpush-fail.t Sat Sep 27 14:47:52 2014 -0500 @@ -23,7 +23,7 @@ $ echo bar > bar $ hg add bar $ hg qrefresh -m 'patch 2' - $ hg qnew --config 'mq.plain=true' bad-patch + $ hg qnew --config 'mq.plain=true' -U bad-patch $ echo >> foo $ hg qrefresh $ hg qpop -a
--- a/tests/test-mq-qrefresh-interactive.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-qrefresh-interactive.t Sat Sep 27 14:47:52 2014 -0500 @@ -29,7 +29,7 @@ Returns 0 on success. - options: + options ([+] can be repeated): -e --edit invoke editor on commit messages -g --git use git extended diff format @@ -44,9 +44,7 @@ -m --message TEXT use text as commit message -l --logfile FILE read commit message from file - [+] marked option can be specified multiple times - - use "hg -v help qrefresh" to show the global options + (some details hidden, use --verbose to show complete help) help qrefresh (record) @@ -73,7 +71,7 @@ Returns 0 on success. - options: + options ([+] can be repeated): -e --edit invoke editor on commit messages -g --git use git extended diff format @@ -89,9 +87,7 @@ -l --logfile FILE read commit message from file -i --interactive interactively select changes to refresh - [+] marked option can be specified multiple times - - use "hg -v help qrefresh" to show the global options + (some details hidden, use --verbose to show complete help) $ hg init a $ cd a
--- a/tests/test-mq-qrefresh-replace-log-message.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-qrefresh-replace-log-message.t Sat Sep 27 14:47:52 2014 -0500 @@ -32,17 +32,19 @@ $ cat >> .hg/hgrc <<EOF > [committemplate] + > listupfiles = {file_adds % + > "HG: added {file}\n" }{file_mods % + > "HG: changed {file}\n" }{file_dels % + > "HG: removed {file}\n" }{if(files, "", + > "HG: no files changed\n")} + > > changeset = HG: this is customized commit template > {desc}\n\n > HG: Enter commit message. Lines beginning with 'HG:' are removed. > HG: {extramsg} > HG: -- > HG: user: {author} - > HG: branch '{branch}'\n{file_adds % - > "HG: added {file}\n" }{file_mods % - > "HG: changed {file}\n" }{file_dels % - > "HG: removed {file}\n" }{if(files, "", - > "HG: no files changed\n")} + > HG: branch '{branch}'\n{listupfiles} > EOF $ echo bbbb > file
--- a/tests/test-mq-qrefresh.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-qrefresh.t Sat Sep 27 14:47:52 2014 -0500 @@ -49,7 +49,7 @@ $ cat .hg/patches/mqbase # HG changeset patch - # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa + # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa mqbase diff -r e7af5904b465 1/base @@ -98,7 +98,7 @@ $ cat .hg/patches/mqbase # HG changeset patch - # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa + # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa mqbase diff -r e7af5904b465 1/base @@ -142,7 +142,7 @@ $ cat .hg/patches/mqbase # HG changeset patch - # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa + # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa mqbase diff -r e7af5904b465 1/base @@ -186,7 +186,7 @@ $ cat .hg/patches/mqbase # HG changeset patch - # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa + # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa mqbase diff -r e7af5904b465 1/base @@ -234,7 +234,7 @@ $ cat .hg/patches/mqbase # HG changeset patch - # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa + # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa mqbase diff -r e7af5904b465 1/base @@ -267,7 +267,7 @@ $ cat .hg/patches/mqbase # HG changeset patch - # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa + # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa mqbase diff -r e7af5904b465 1/base @@ -289,7 +289,7 @@ $ cat .hg/patches/mqbase # HG changeset patch - # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa + # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa mqbase diff -r e7af5904b465 1/base @@ -312,7 +312,7 @@ $ cat .hg/patches/mqbase # HG changeset patch - # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa + # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa mqbase diff -r e7af5904b465 2/base @@ -328,7 +328,7 @@ $ cat .hg/patches/mqbase # HG changeset patch - # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa + # Parent e7af5904b465cd1f4f3cf6b26fe14e8db6f63eaa mqbase diff -r e7af5904b465 1/base @@ -453,7 +453,7 @@ $ cat .hg/patches/patch # HG changeset patch - # Parent 1a60229be7ac3e4a7f647508e99b87bef1f03593 + # Parent 1a60229be7ac3e4a7f647508e99b87bef1f03593 diff -r 1a60229be7ac b --- a/b @@ -507,7 +507,8 @@ $ rm a $ cat .hg/patches/a # HG changeset patch - # Parent 0000000000000000000000000000000000000000 + # Parent 0000000000000000000000000000000000000000 + diff --git a/a b/a new file mode 100644 $ hg qpush @@ -521,7 +522,8 @@ [255] $ cat .hg/patches/a # HG changeset patch - # Parent 0000000000000000000000000000000000000000 + # Parent 0000000000000000000000000000000000000000 + diff --git a/a b/a new file mode 100644 $ cd ..
--- a/tests/test-mq-qrename.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-qrename.t Sat Sep 27 14:47:52 2014 -0500 @@ -113,7 +113,7 @@ $ hg qmv addb $ cat .hg/patches/addb # HG changeset patch - # Parent 0000000000000000000000000000000000000000 + # Parent 0000000000000000000000000000000000000000 diff -r 000000000000 a --- /dev/null * (glob)
--- a/tests/test-mq-subrepo-svn.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-subrepo-svn.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" svn13 || exit 80 +#require svn13 $ echo "[extensions]" >> $HGRCPATH $ echo "mq=" >> $HGRCPATH
--- a/tests/test-mq-subrepo.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-subrepo.t Sat Sep 27 14:47:52 2014 -0500 @@ -419,9 +419,9 @@ +b6f6e9c41f3dfd374a6d2ed4535c87951cf979cf sub $ cat .hg/patches/import-at-qnew # HG changeset patch - # Parent f499373e340cdca5d01dee904aeb42dd2a325e71 # User test # Date 0 0 + # Parent f499373e340cdca5d01dee904aeb42dd2a325e71 diff -r f499373e340c -r f69e96d86e75 .hgsub --- /dev/null @@ -482,9 +482,9 @@ +88ac1bef5ed43b689d1d200b59886b675dec474b sub $ cat .hg/patches/import-at-qrefresh # HG changeset patch + # User test # Date 0 0 - # User test - # Parent 05b056bb9c8c05ff15258b84fd42ab3527271033 + # Parent 05b056bb9c8c05ff15258b84fd42ab3527271033 diff -r 05b056bb9c8c .hgsubstate --- a/.hgsubstate @@ -507,9 +507,9 @@ +88ac1bef5ed43b689d1d200b59886b675dec474b sub $ cat .hg/patches/import-at-qrefresh # HG changeset patch + # User test # Date 0 0 - # User test - # Parent 05b056bb9c8c05ff15258b84fd42ab3527271033 + # Parent 05b056bb9c8c05ff15258b84fd42ab3527271033 diff -r 05b056bb9c8c .hgsubstate --- a/.hgsubstate @@ -554,9 +554,9 @@ +88ac1bef5ed43b689d1d200b59886b675dec474b sub $ cat .hg/patches/checkstate-at-qnew # HG changeset patch - # Parent 4d91eb2fa1d1b22ec513347b9cd06f6b49d470fa # User test # Date 0 0 + # Parent 4d91eb2fa1d1b22ec513347b9cd06f6b49d470fa diff -r 4d91eb2fa1d1 -r 1259c112d884 .hgsubstate --- a/.hgsubstate
--- a/tests/test-mq-symlinks.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq-symlinks.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" symlink || exit 80 +#require symlink $ echo "[extensions]" >> $HGRCPATH $ echo "mq=" >> $HGRCPATH
--- a/tests/test-mq.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-mq.t Sat Sep 27 14:47:52 2014 -0500 @@ -95,7 +95,7 @@ qtop print the name of the current patch qunapplied print the patches not yet applied - use "hg -v help mq" to show builtin aliases and global options + (use "hg help -v mq" to show built-in aliases and global options) $ hg init a $ cd a
--- a/tests/test-newbranch.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-newbranch.t Sat Sep 27 14:47:52 2014 -0500 @@ -51,11 +51,28 @@ date: Thu Jan 01 00:00:00 1970 +0000 summary: clear branch name +Merging and branches $ hg co foo 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg branch foo + + set existing branch name fails unless force - setting existing parent branch works without force: + + $ hg branch bar + abort: a branch of the same name already exists + (use 'hg update' to switch to it) + [255] + + $ 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" @@ -65,46 +82,40 @@ $ hg branch foo + + set existing branch name where branch head is ancestor: + + $ hg branch bar + abort: a branch of the same name already exists + (use 'hg update' to switch to it) + [255] + + set (other) parent branch as branch name + + $ 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" - $ hg log - changeset: 5:530046499edf - branch: foo - tag: tip - parent: 4:adf1a74a7f7b - parent: 3:1c28f494dae6 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: merge - - changeset: 4:adf1a74a7f7b - branch: foo - parent: 1:6c0e42da283a - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: modify a branch - - changeset: 3:1c28f494dae6 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: clear branch name - - changeset: 2:c21617b13b22 - branch: bar - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: change branch name - - changeset: 1:6c0e42da283a - branch: foo - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add branch name - - changeset: 0:db01e8ea3388 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: initial + $ hg log -G -T '{rev}:{node|short} {branch} {desc}\n' + @ 5:530046499edf foo merge + |\ + | o 4:adf1a74a7f7b foo modify a branch + | | + o | 3:1c28f494dae6 default clear branch name + | | + o | 2:c21617b13b22 bar change branch name + |/ + o 1:6c0e42da283a foo add branch name + | + o 0:db01e8ea3388 default initial $ hg branches foo 5:530046499edf
--- a/tests/test-newcgi.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-newcgi.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" no-msys || exit 80 # MSYS will translate web paths as if they were file paths +#require no-msys # MSYS will translate web paths as if they were file paths This tests if CGI files from after d0db3462d568 but before d74fc8dec2b4 still work.
--- a/tests/test-newercgi.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-newercgi.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" no-msys || exit 80 # MSYS will translate web paths as if they were file paths +#require no-msys # MSYS will translate web paths as if they were file paths This is a rudimentary test of the CGI files as of d74fc8dec2b4.
--- a/tests/test-no-symlinks.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-no-symlinks.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" no-symlink || exit 80 +#require no-symlink # The following script was used to create the bundle: #
--- a/tests/test-obsolete.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-obsolete.t Sat Sep 27 14:47:52 2014 -0500 @@ -2,6 +2,8 @@ > [phases] > # public changeset are not obsolete > publish=false + > [ui] + > logtemplate="{rev}:{node|short} ({phase}) [{tags} {bookmarks}] {desc|firstline}\n" > EOF $ mkcommit() { > echo "$1" > "$1" @@ -52,17 +54,13 @@ [255] $ hg debugobsolete -d '0 0' `getid kill_me` -u babar $ hg debugobsolete - 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 {'date': '0 0', 'user': 'babar'} + 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'babar'} (test that mercurial is not confused) $ hg up null --quiet # having 0 as parent prevents it to be hidden $ hg tip - changeset: -1:000000000000 - tag: tip - user: - date: Thu Jan 01 00:00:00 1970 +0000 - + -1:000000000000 (public) [tip ] $ hg up --hidden tip --quiet Killing a single changeset with itself should fail @@ -90,13 +88,13 @@ $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden 2:245bde4270cd add original_c $ hg debugrevlog -cd - # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads - 0 -1 -1 0 59 0 0 0 0 58 58 0 1 - 1 0 -1 59 118 59 59 0 0 58 116 0 1 - 2 1 -1 118 204 59 59 59 0 76 192 0 1 - 3 1 -1 204 271 204 204 59 0 66 258 0 2 + # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen + 0 -1 -1 0 59 0 0 0 0 58 58 0 1 0 + 1 0 -1 59 118 59 59 0 0 58 116 0 1 0 + 2 1 -1 118 204 59 59 59 0 76 192 0 1 1 + 3 1 -1 204 271 204 204 59 0 66 258 0 2 0 $ hg debugobsolete - 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} do it again (it read the obsstore before adding new changeset) @@ -106,8 +104,8 @@ created new head $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c` $ hg debugobsolete - 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'} - cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'} Register two markers with a missing node @@ -118,10 +116,10 @@ $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c` $ hg debugobsolete - 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'} - cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'} - ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'} - 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 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'} Refuse pathological nullid successors $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000 @@ -133,59 +131,22 @@ Check that graphlog detect that a changeset is obsolete: $ hg log -G - @ changeset: 5:5601fb93a350 - | tag: tip - | parent: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add new_3_c + @ 5:5601fb93a350 (draft) [tip ] add new_3_c | - o changeset: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add b + o 1:7c3bad9141dc (draft) [ ] add b | - o changeset: 0:1f0dee641bb7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add a + o 0:1f0dee641bb7 (draft) [ ] add a check that heads does not report them $ hg heads - changeset: 5:5601fb93a350 - tag: tip - parent: 1:7c3bad9141dc - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add new_3_c - + 5:5601fb93a350 (draft) [tip ] add new_3_c $ hg heads --hidden - changeset: 5:5601fb93a350 - tag: tip - parent: 1:7c3bad9141dc - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add new_3_c - - changeset: 4:ca819180edb9 - parent: 1:7c3bad9141dc - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add new_2_c - - changeset: 3:cdbce2fbb163 - parent: 1:7c3bad9141dc - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add new_c - - changeset: 2:245bde4270cd - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add original_c - + 5:5601fb93a350 (draft) [tip ] add new_3_c + 4:ca819180edb9 (draft) [ ] add new_2_c + 3:cdbce2fbb163 (draft) [ ] add new_c + 2:245bde4270cd (draft) [ ] add original_c check that summary does not report them @@ -212,13 +173,7 @@ check that various commands work well with filtering $ hg tip - changeset: 5:5601fb93a350 - tag: tip - parent: 1:7c3bad9141dc - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add new_3_c - + 5:5601fb93a350 (draft) [tip ] add new_3_c $ hg log -r 6 abort: unknown revision '6'! [255] @@ -230,27 +185,13 @@ $ hg --hidden phase --public 2 $ hg log -G - @ changeset: 5:5601fb93a350 - | tag: tip - | parent: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add new_3_c + @ 5:5601fb93a350 (draft) [tip ] add new_3_c | - | o changeset: 2:245bde4270cd - |/ user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add original_c + | o 2:245bde4270cd (public) [ ] add original_c + |/ + o 1:7c3bad9141dc (public) [ ] add b | - o changeset: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add b - | - o changeset: 0:1f0dee641bb7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add a + o 0:1f0dee641bb7 (public) [ ] add a And that bumped changeset are detected @@ -261,13 +202,7 @@ the public changeset $ hg log --hidden -r 'bumped()' - changeset: 5:5601fb93a350 - tag: tip - parent: 1:7c3bad9141dc - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add new_3_c - + 5:5601fb93a350 (draft) [tip ] add new_3_c And that we can't push bumped changeset @@ -297,27 +232,13 @@ $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c` $ hg log -r 'bumped()' $ hg log -G - @ changeset: 6:6f9641995072 - | tag: tip - | parent: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add n3w_3_c + @ 6:6f9641995072 (draft) [tip ] add n3w_3_c | - | o changeset: 2:245bde4270cd - |/ user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add original_c + | o 2:245bde4270cd (public) [ ] add original_c + |/ + o 1:7c3bad9141dc (public) [ ] add b | - o changeset: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add b - | - o changeset: 0:1f0dee641bb7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add a + o 0:1f0dee641bb7 (public) [ ] add a @@ -336,28 +257,10 @@ $ cd tmpc $ hg incoming ../tmpb comparing with ../tmpb - changeset: 0:1f0dee641bb7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add a - - changeset: 1:7c3bad9141dc - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add b - - changeset: 2:245bde4270cd - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add original_c - - changeset: 6:6f9641995072 - tag: tip - parent: 1:7c3bad9141dc - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add n3w_3_c - + 0:1f0dee641bb7 (public) [ ] add a + 1:7c3bad9141dc (public) [ ] add b + 2:245bde4270cd (public) [ ] add original_c + 6:6f9641995072 (draft) [tip ] add n3w_3_c Try to pull markers (extinct changeset are excluded but marker are pushed) @@ -371,32 +274,32 @@ added 4 changesets with 4 changes to 4 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg debugobsolete - 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'} - cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'} - ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'} - 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'} - 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 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'} Rollback//Transaction support $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb $ hg debugobsolete - 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'} - cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'} - ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'} - 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'} - 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'} - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '1340 0', 'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 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'} + 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 - 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'} - cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'} - ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'} - 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'} - 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 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'} $ cd .. @@ -410,21 +313,22 @@ adding manifests adding file changes added 4 changesets with 4 changes to 4 files (+1 heads) - $ hg -R tmpd debugobsolete - 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'} - cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'} - ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'} - 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'} - 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'} + $ 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:44 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'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'} Check obsolete keys are exchanged only if source has an obsolete store $ hg init empty $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd pushing to tmpd + listkeys phases + listkeys bookmarks no changes found listkeys phases - listkeys bookmarks [1] clone support @@ -434,52 +338,26 @@ updating to branch default 3 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg -R clone-dest log -G --hidden - @ changeset: 6:6f9641995072 - | tag: tip - | parent: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add n3w_3_c - | - | x changeset: 5:5601fb93a350 - |/ parent: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add new_3_c - | - | x changeset: 4:ca819180edb9 - |/ parent: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add new_2_c + @ 6:6f9641995072 (draft) [tip ] add n3w_3_c | - | x changeset: 3:cdbce2fbb163 - |/ parent: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add new_c + | x 5:5601fb93a350 (draft) [ ] add new_3_c + |/ + | x 4:ca819180edb9 (draft) [ ] add new_2_c + |/ + | x 3:cdbce2fbb163 (draft) [ ] add new_c + |/ + | o 2:245bde4270cd (public) [ ] add original_c + |/ + o 1:7c3bad9141dc (public) [ ] add b | - | o changeset: 2:245bde4270cd - |/ user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add original_c - | - o changeset: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add b - | - o changeset: 0:1f0dee641bb7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add a + o 0:1f0dee641bb7 (public) [ ] add a $ hg -R clone-dest debugobsolete - 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'} - cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'} - ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'} - 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'} - 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 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'} Destination repo have existing data @@ -489,7 +367,7 @@ $ hg init tmpe $ cd tmpe - $ hg debugobsolete -d '1339 0' 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 + $ hg debugobsolete -d '1339 0' 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 $ hg pull ../tmpb pulling from ../tmpb requesting all changes @@ -499,12 +377,12 @@ added 4 changesets with 4 changes to 4 files (+1 heads) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg debugobsolete - 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'} - 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'} - cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'} - ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'} - 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'} - 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'} + 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 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'} On push @@ -515,78 +393,45 @@ no changes found [1] $ hg -R ../tmpc debugobsolete - 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'} - cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'} - ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'} - 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'} - 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'} - 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 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'} + 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'} detect outgoing obsolete and unstable --------------------------------------- $ hg log -G - o changeset: 3:6f9641995072 - | tag: tip - | parent: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add n3w_3_c + o 3:6f9641995072 (draft) [tip ] add n3w_3_c | - | o changeset: 2:245bde4270cd - |/ user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add original_c + | o 2:245bde4270cd (public) [ ] add original_c + |/ + o 1:7c3bad9141dc (public) [ ] add b | - o changeset: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add b - | - o changeset: 0:1f0dee641bb7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add a + o 0:1f0dee641bb7 (public) [ ] add a $ hg up 'desc("n3w_3_c")' 3 files updated, 0 files merged, 0 files removed, 0 files unresolved $ mkcommit original_d $ mkcommit original_e - $ hg debugobsolete `getid original_d` -d '0 0' + $ hg debugobsolete --record-parents `getid original_d` -d '0 0' + $ hg debugobsolete | grep `getid original_d` + 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} $ hg log -r 'obsolete()' - changeset: 4:94b33453f93b - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add original_d - + 4:94b33453f93b (draft) [ ] add original_d $ hg log -G -r '::unstable()' - @ changeset: 5:cda648ca50f5 - | tag: tip - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add original_e + @ 5:cda648ca50f5 (draft) [tip ] add original_e | - x changeset: 4:94b33453f93b - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add original_d + x 4:94b33453f93b (draft) [ ] add original_d + | + o 3:6f9641995072 (draft) [ ] add n3w_3_c | - o changeset: 3:6f9641995072 - | parent: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add n3w_3_c + o 1:7c3bad9141dc (public) [ ] add b | - o changeset: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add b - | - o changeset: 0:1f0dee641bb7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add a + o 0:1f0dee641bb7 (public) [ ] add a refuse to push obsolete changeset @@ -615,38 +460,12 @@ $ hg out ../tmpf comparing with ../tmpf searching for changes - changeset: 0:1f0dee641bb7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add a - - changeset: 1:7c3bad9141dc - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add b - - changeset: 2:245bde4270cd - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add original_c - - changeset: 3:6f9641995072 - parent: 1:7c3bad9141dc - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add n3w_3_c - - changeset: 4:94b33453f93b - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add original_d - - changeset: 5:cda648ca50f5 - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add original_e - + 0:1f0dee641bb7 (public) [ ] add a + 1:7c3bad9141dc (public) [ ] add b + 2:245bde4270cd (public) [ ] add original_c + 3:6f9641995072 (draft) [ ] add n3w_3_c + 4:94b33453f93b (draft) [ ] add original_d + 5:cda648ca50f5 (draft) [tip ] add original_e $ hg push ../tmpf -f # -f because be push unstable too pushing to ../tmpf searching for changes @@ -666,37 +485,17 @@ Do not warn about new head when the new head is a successors of a remote one $ hg log -G - @ changeset: 5:cda648ca50f5 - | tag: tip - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add original_e + @ 5:cda648ca50f5 (draft) [tip ] add original_e | - x changeset: 4:94b33453f93b - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add original_d + x 4:94b33453f93b (draft) [ ] add original_d + | + o 3:6f9641995072 (draft) [ ] add n3w_3_c | - o changeset: 3:6f9641995072 - | parent: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add n3w_3_c + | o 2:245bde4270cd (public) [ ] add original_c + |/ + o 1:7c3bad9141dc (public) [ ] add b | - | o changeset: 2:245bde4270cd - |/ user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add original_c - | - o changeset: 1:7c3bad9141dc - | user: test - | date: Thu Jan 01 00:00:00 1970 +0000 - | summary: add b - | - o changeset: 0:1f0dee641bb7 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add a + o 0:1f0dee641bb7 (public) [ ] add a $ hg up -q 'desc(n3w_3_c)' $ mkcommit obsolete_e @@ -705,13 +504,7 @@ $ hg outgoing ../tmpf # parasite hg outgoing testin comparing with ../tmpf searching for changes - changeset: 6:3de5eca88c00 - tag: tip - parent: 3:6f9641995072 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add obsolete_e - + 6:3de5eca88c00 (draft) [tip ] add obsolete_e $ hg push ../tmpf pushing to ../tmpf searching for changes @@ -720,6 +513,74 @@ adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) +test relevance computation +--------------------------------------- + +Checking simple case of "marker relevance". + + +Reminder of the repo situation + + $ hg log --hidden --graph + @ 6:3de5eca88c00 (draft) [tip ] add obsolete_e + | + | x 5:cda648ca50f5 (draft) [ ] add original_e + | | + | x 4:94b33453f93b (draft) [ ] add original_d + |/ + o 3:6f9641995072 (draft) [ ] add n3w_3_c + | + | o 2:245bde4270cd (public) [ ] add original_c + |/ + o 1:7c3bad9141dc (public) [ ] add b + | + o 0:1f0dee641bb7 (public) [ ] add a + + +List of all markers + + $ hg debugobsolete + 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 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'} + 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob) + +List of changesets with no chain + + $ hg debugobsolete --hidden --rev ::2 + +List of changesets that are included on marker chain + + $ hg debugobsolete --hidden --rev 6 + cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob) + +List of changesets with a longer chain, (including a pruned children) + + $ hg debugobsolete --hidden --rev 3 + 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'} + 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'} + 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'} + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'} + +List of both + + $ hg debugobsolete --hidden --rev 3::6 + 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'} + 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'} + 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:44 1970 -0000) {'user': 'test'} + 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'} + 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} + ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'} + cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob) + cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'} + #if serve check hgweb does not explode @@ -781,13 +642,7 @@ $ echo "obs=!" >> $HGRCPATH $ hg log -r tip obsolete feature not enabled but 68 markers found! - changeset: 68:c15e9edfca13 - tag: tip - parent: 7:50c51b361e60 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: add celestine - + 68:c15e9edfca13 (draft) [tip ] add celestine reenable for later test @@ -813,40 +668,19 @@ $ hg ci --amend $ cd ../other-issue3805 $ hg log -G - @ changeset: 0:193e9254ce7e - tag: tip - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: A + @ 0:193e9254ce7e (draft) [tip ] A $ hg log -G -R ../repo-issue3805 - @ changeset: 2:3816541e5485 - tag: tip - parent: -1:000000000000 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: A + @ 2:3816541e5485 (draft) [tip ] A $ hg incoming comparing with $TESTTMP/tmpe/repo-issue3805 (glob) searching for changes - changeset: 2:3816541e5485 - tag: tip - parent: -1:000000000000 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: A - + 2:3816541e5485 (draft) [tip ] A $ hg incoming --bundle ../issue3805.hg comparing with $TESTTMP/tmpe/repo-issue3805 (glob) searching for changes - changeset: 2:3816541e5485 - tag: tip - parent: -1:000000000000 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: A - + 2:3816541e5485 (draft) [tip ] A $ hg outgoing comparing with $TESTTMP/tmpe/repo-issue3805 (glob) searching for changes @@ -861,13 +695,7 @@ $ hg incoming http://localhost:$HGPORT comparing with http://localhost:$HGPORT/ searching for changes - changeset: 1:3816541e5485 - tag: tip - parent: -1:000000000000 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: A - + 1:3816541e5485 (public) [tip ] A $ hg outgoing http://localhost:$HGPORT comparing with http://localhost:$HGPORT/ searching for changes @@ -902,18 +730,9 @@ $ hg tag -l visible -r 0 --hidden $ hg log -G - @ changeset: 2:3816541e5485 - tag: tip - parent: -1:000000000000 - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: A + @ 2:3816541e5485 (draft) [tip ] A - x changeset: 0:193e9254ce7e - tag: visible - user: test - date: Thu Jan 01 00:00:00 1970 +0000 - summary: A + x 0:193e9254ce7e (draft) [visible ] A Test that removing a local tag does not cause some commands to fail
--- a/tests/test-oldcgi.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-oldcgi.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" no-msys || exit 80 # MSYS will translate web paths as if they were file paths +#require no-msys # MSYS will translate web paths as if they were file paths This tests if CGI files from before d0db3462d568 still work.
--- a/tests/test-patchbomb.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-patchbomb.t Sat Sep 27 14:47:52 2014 -0500 @@ -8,6 +8,21 @@ --===+[0-9]+=+--$ -> --===*=-- (glob) --===+[0-9]+=+$ -> --===*= (glob) + $ cat > prune-blank-after-boundary.py <<EOF + > import sys + > skipblank = False + > trim = lambda x: x.strip(' \r\n') + > for l in sys.stdin: + > if trim(l).endswith('=--') or trim(l).endswith('=='): + > skipblank = True + > print l, + > continue + > if not trim(l) and skipblank: + > continue + > skipblank = False + > print l, + > EOF + $ FILTERBOUNDARY="python `pwd`/prune-blank-after-boundary.py" $ echo "[extensions]" >> $HGRCPATH $ echo "patchbomb=" >> $HGRCPATH @@ -214,7 +229,7 @@ test bundle and description: $ hg email --date '1970-1-1 0:3' -n -f quux -t foo \ - > -c bar -s test -r tip -b --desc description + > -c bar -s test -r tip -b --desc description | $FILTERBOUNDARY searching for changes 1 changesets found @@ -689,7 +704,7 @@ test inline for single patch: - $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i -r 2 + $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i -r 2 | $FILTERBOUNDARY this patch series consists of 1 patches. @@ -732,7 +747,7 @@ test inline for single patch (quoted-printable): - $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i -r 4 + $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i -r 4 | $FILTERBOUNDARY this patch series consists of 1 patches. @@ -791,7 +806,7 @@ test inline for multiple patches: $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i \ - > -r 0:1 -r 4 + > -r 0:1 -r 4 | $FILTERBOUNDARY this patch series consists of 3 patches. @@ -943,7 +958,7 @@ --===*=-- (glob) test attach for single patch: - $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a -r 2 + $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a -r 2 | $FILTERBOUNDARY this patch series consists of 1 patches. @@ -994,7 +1009,7 @@ --===*=-- (glob) test attach for single patch (quoted-printable): - $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a -r 4 + $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a -r 4 | $FILTERBOUNDARY this patch series consists of 1 patches. @@ -1061,7 +1076,7 @@ --===*=-- (glob) test attach and body for single patch: - $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a --body -r 2 + $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a --body -r 2 | $FILTERBOUNDARY this patch series consists of 1 patches. @@ -1123,7 +1138,7 @@ test attach for multiple patches: $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -a \ - > -r 0:1 -r 4 + > -r 0:1 -r 4 | $FILTERBOUNDARY this patch series consists of 3 patches. @@ -1579,7 +1594,8 @@ $ hg tag -r2 two two.diff test inline for single named patch: - $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i -r 2 + $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i \ + > -r 2 | $FILTERBOUNDARY this patch series consists of 1 patches. @@ -1621,7 +1637,8 @@ --===*=-- (glob) test inline for multiple named/unnamed patches: - $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i -r 0:1 + $ hg email --date '1970-1-1 0:1' -n -f quux -t foo -c bar -s test -i \ + > -r 0:1 | $FILTERBOUNDARY this patch series consists of 2 patches. @@ -1927,7 +1944,7 @@ $ hg up -qr1 $ echo dirt > a $ hg email --date '1970-1-1 0:1' -n --flag fooFlag -f quux -t foo -c bar -s test \ - > -r 2 + > -r 2 | $FILTERBOUNDARY this patch series consists of 1 patches.
--- a/tests/test-permissions.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-permissions.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ -#if unix-permissions no-root +#require unix-permissions no-root $ hg init t $ cd t @@ -70,5 +70,3 @@ $ chmod +rx dir $ cd .. - -#endif
--- a/tests/test-phases-exchange.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-phases-exchange.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons $ hgph() { hg log -G --template "{rev} {phase} {desc} - {node|short}\n" $*; }
--- a/tests/test-pull-http.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-pull-http.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons $ hg init test $ cd test @@ -26,6 +26,14 @@ updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cat test3/.hg/hgrc + # You may want to set your username here if it is not set + # globally, or this repository requires a different + # username from your usual configuration. If you want to + # set something for all of your repositories on this + # computer, try running the command + # 'hg config --edit --global' + # [ui] + # username = Jane Doe <jdoe@example.com> [paths] default = http://foo@localhost:$HGPORT/ $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
--- a/tests/test-pull-permission.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-pull-permission.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ -#if unix-permissions no-root +#require unix-permissions no-root $ hg init a $ cd a @@ -30,5 +30,3 @@ 1 files, 1 changesets, 1 total revisions $ cd .. - -#endif
--- a/tests/test-pull.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-pull.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve $ hg init test $ cd test
--- a/tests/test-push-cgi.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-push-cgi.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" no-msys || exit 80 # MSYS will translate web paths as if they were file paths +#require no-msys # MSYS will translate web paths as if they were file paths This is a test of the push wire protocol over CGI-based hgweb.
--- a/tests/test-push-hook-lock.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-push-hook-lock.t Sat Sep 27 14:47:52 2014 -0500 @@ -16,6 +16,7 @@ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ echo '[hooks]' >> 2/.hg/hgrc + $ echo 'pretxnchangegroup.a = hg debuglocks; true' >> 2/.hg/hgrc $ echo 'changegroup.push = hg push -qf ../1' >> 2/.hg/hgrc $ echo bar >> 3/foo @@ -28,4 +29,6 @@ adding manifests adding file changes added 1 changesets with 1 changes to 1 files + lock: user *, process * (*s) (glob) + wlock: free
--- a/tests/test-push-http.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-push-http.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons $ hg init test $ cd test
--- a/tests/test-push-warn.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-push-warn.t Sat Sep 27 14:47:52 2014 -0500 @@ -35,6 +35,9 @@ searching: 2 queries query 2; still undecided: 1, sample size is: 1 2 total queries + listing keys for "phases" + checking for updated bookmarks + listing keys for "bookmarks" listing keys for "bookmarks" remote has heads on branch 'default' that are not known locally: 1c9246a22a0a new remote heads on branch 'default':
--- a/tests/test-qrecord.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-qrecord.t Sat Sep 27 14:47:52 2014 -0500 @@ -9,7 +9,7 @@ record extension - commands to interactively select changes for commit/qrefresh - use "hg help extensions" for information on enabling extensions + (use "hg help extensions" for information on enabling extensions) help qrecord (no record) @@ -18,7 +18,7 @@ record commands to interactively select changes for commit/qrefresh - use "hg help extensions" for information on enabling extensions + (use "hg help extensions" for information on enabling extensions) $ echo "[extensions]" >> $HGRCPATH $ echo "record=" >> $HGRCPATH @@ -54,7 +54,7 @@ This command is not available when committing a merge. - options: + options ([+] can be repeated): -A --addremove mark new/missing files as added/removed before committing @@ -74,9 +74,7 @@ -b --ignore-space-change ignore changes in the amount of white space -B --ignore-blank-lines ignore changes whose lines are all blank - [+] marked option can be specified multiple times - - use "hg -v help record" to show the global options + (some details hidden, use --verbose to show complete help) help (no mq, so no qrecord) @@ -87,7 +85,7 @@ See "hg help qnew" & "hg help record" for more information and usage. - use "hg -v help qrecord" to show the global options + (some details hidden, use --verbose to show complete help) $ hg init a @@ -99,7 +97,7 @@ interactively record a new patch - use "hg help qrecord" to show the full help text + (use "hg qrecord -h" to show more help) [255] qrecord patch (mq not present) @@ -119,7 +117,7 @@ See "hg help qnew" & "hg help record" for more information and usage. - use "hg -v help qrecord" to show the global options + (some details hidden, use --verbose to show complete help) help (mq present) @@ -133,7 +131,7 @@ See "hg help qnew" & "hg help record" for more information and usage. - options: + options ([+] can be repeated): -e --edit invoke editor on commit messages -g --git use git extended diff format @@ -150,9 +148,7 @@ -B --ignore-blank-lines ignore changes whose lines are all blank --mq operate on patch repository - [+] marked option can be specified multiple times - - use "hg -v help qrecord" to show the global options + (some details hidden, use --verbose to show complete help) $ cd a
--- a/tests/test-rebase-cache.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-rebase-cache.t Sat Sep 27 14:47:52 2014 -0500 @@ -470,5 +470,11 @@ o 0 A public - $ hg rebase --dest 7 --source 5 + $ cat > $TESTTMP/checkeditform.sh <<EOF + > env | grep HGEDITFORM + > true + > EOF + $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg rebase --dest 7 --source 5 -e + HGEDITFORM=rebase.merge + HGEDITFORM=rebase.normal saved backup bundle to $TESTTMP/a3/c4/.hg/strip-backup/*-backup.hg (glob)
--- a/tests/test-rebase-collapse.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-rebase-collapse.t Sat Sep 27 14:47:52 2014 -0500 @@ -148,7 +148,12 @@ abort: message can only be specified with collapse [255] - $ hg rebase --source 4 --collapse -m 'custom message' + $ cat > $TESTTMP/checkeditform.sh <<EOF + > env | grep HGEDITFORM + > true + > EOF + $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg rebase --source 4 --collapse -m 'custom message' -e + HGEDITFORM=rebase.collapse saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob) $ hg tglog
--- a/tests/test-rebase-obsolete.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-rebase-obsolete.t Sat Sep 27 14:47:52 2014 -0500 @@ -101,9 +101,9 @@ o 0:cd010b8cd998 A $ hg debugobsolete - 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 e4e5be0395b2cbd471ed22a26b1b6a1a0658a794 0 {'date': '*', 'user': 'test'} (glob) - 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 2327fea05063f39961b14cb69435a9898dc9a245 0 {'date': '*', 'user': 'test'} (glob) - 32af7686d403cf45b5d95f2d70cebea587ac806a 8eeb3c33ad33d452c89e5dcf611c347f978fb42b 0 {'date': '*', 'user': 'test'} (glob) + 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 e4e5be0395b2cbd471ed22a26b1b6a1a0658a794 0 (*) {'user': 'test'} (glob) + 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 2327fea05063f39961b14cb69435a9898dc9a245 0 (*) {'user': 'test'} (glob) + 32af7686d403cf45b5d95f2d70cebea587ac806a 8eeb3c33ad33d452c89e5dcf611c347f978fb42b 0 (*) {'user': 'test'} (glob) $ cd .. @@ -166,19 +166,19 @@ o 0:cd010b8cd998 A $ hg debugobsolete - 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {'date': '*', 'user': 'test'} (glob) - 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 {'date': '*', 'user': 'test'} (glob) - 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {'date': '*', 'user': 'test'} (glob) + 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob) + 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob) + 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob) More complex case were part of the rebase set were already rebased $ hg rebase --rev 'desc(D)' --dest 'desc(H)' $ hg debugobsolete - 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {'date': '*', 'user': 'test'} (glob) - 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 {'date': '*', 'user': 'test'} (glob) - 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {'date': '*', 'user': 'test'} (glob) - 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 {'date': '* *', 'user': 'test'} (glob) + 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob) + 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob) + 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob) + 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob) $ hg log -G @ 11:4596109a6a43 D | @@ -200,13 +200,13 @@ $ hg rebase --source 'desc(B)' --dest 'tip' $ hg debugobsolete - 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {'date': '* *', 'user': 'test'} (glob) - 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 {'date': '* *', 'user': 'test'} (glob) - 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {'date': '* *', 'user': 'test'} (glob) - 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 {'date': '* *', 'user': 'test'} (glob) - 8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 {'date': '* *', 'user': 'test'} (glob) - 08483444fef91d6224f6655ee586a65d263ad34c 0 {'date': '* *', 'user': 'test'} (glob) - 5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 {'date': '* *', 'user': 'test'} (glob) + 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob) + 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob) + 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob) + 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob) + 8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 (*) {'user': 'test'} (glob) + 08483444fef91d6224f6655ee586a65d263ad34c 0 {8877864f1edb05d0e07dc4ba77b67a80a7b86672} (*) {'user': 'test'} (glob) + 5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 (*) {'user': 'test'} (glob) $ hg log --rev 'divergent()' $ hg log -G o 13:98f6af4ee953 C @@ -286,9 +286,9 @@ $ hg id --debug -r tip 4dc2197e807bae9817f09905b50ab288be2dbbcf tip $ hg debugobsolete - 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 {'date': '*', 'user': 'test'} (glob) - 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 {'date': '*', 'user': 'test'} (glob) - 32af7686d403cf45b5d95f2d70cebea587ac806a 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 {'date': '*', 'user': 'test'} (glob) + 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob) + 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob) + 32af7686d403cf45b5d95f2d70cebea587ac806a 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob) $ cd .. @@ -345,9 +345,9 @@ o 0:cd010b8cd998 A $ hg debugobsolete - 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b e273c5e7d2d29df783dce9f9eaa3ac4adc69c15d 0 {'date': '*', 'user': 'test'} (glob) - 32af7686d403cf45b5d95f2d70cebea587ac806a cf44d2f5a9f4297a62be94cbdd3dff7c7dc54258 0 {'date': '*', 'user': 'test'} (glob) - 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 7c6027df6a99d93f461868e5433f63bde20b6dfb 0 {'date': '*', 'user': 'test'} (glob) + 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b e273c5e7d2d29df783dce9f9eaa3ac4adc69c15d 0 (*) {'user': 'test'} (glob) + 32af7686d403cf45b5d95f2d70cebea587ac806a cf44d2f5a9f4297a62be94cbdd3dff7c7dc54258 0 (*) {'user': 'test'} (glob) + 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 7c6027df6a99d93f461868e5433f63bde20b6dfb 0 (*) {'user': 'test'} (glob) Test that rewriting leaving instability behind is allowed ---------------------------------------------------------------------
--- a/tests/test-rebase-parameters.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-rebase-parameters.t Sat Sep 27 14:47:52 2014 -0500 @@ -459,4 +459,12 @@ tool option will be ignored saved backup bundle to $TESTTMP/b3/.hg/strip-backup/*-backup.hg (glob) + $ hg rebase -i + abort: interactive history editing is supported by the 'histedit' extension (see 'hg help histedit') + [255] + + $ hg rebase --interactive + abort: interactive history editing is supported by the 'histedit' extension (see 'hg help histedit') + [255] + $ cd ..
--- a/tests/test-rebase-scenario-global.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-rebase-scenario-global.t Sat Sep 27 14:47:52 2014 -0500 @@ -663,7 +663,7 @@ o 0: 'A' -Test that rebase is not confused by $CWD disappearing during rebase (issue 4121) +Test that rebase is not confused by $CWD disappearing during rebase (issue4121) $ cd .. $ hg init cwd-vanish
--- a/tests/test-relink.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-relink.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" hardlink || exit 80 +#require hardlink $ echo "[extensions]" >> $HGRCPATH $ echo "relink=" >> $HGRCPATH
--- a/tests/test-repair-strip.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-repair-strip.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ -#if unix-permissions no-root +#require unix-permissions no-root $ echo "[extensions]" >> $HGRCPATH $ echo "mq=">> $HGRCPATH @@ -130,5 +130,3 @@ 2 files, 2 changesets, 2 total revisions $ cd .. - -#endif
--- a/tests/test-revert-flags.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-revert-flags.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" execbit || exit 80 +#require execbit $ hg init repo $ cd repo
--- a/tests/test-revert.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-revert.t Sat Sep 27 14:47:52 2014 -0500 @@ -14,101 +14,94 @@ [255] $ hg revert --all - $ echo 123 > b +Introduce some changes and revert them +-------------------------------------- -should show b unknown + $ echo 123 > b $ hg status ? b $ echo 12 > c -should show b unknown and c modified - $ hg status M c ? b $ hg add b -should show b added and c modified - $ hg status M c A b $ hg rm a -should show a removed, b added and c modified - $ hg status M c A b R a - $ hg revert a -should show b added, copy saved, and c modified +revert removal of a file + $ hg revert a $ hg status M c A b - $ hg revert b -should show b unknown, and c modified +revert addition of a file + $ hg revert b $ hg status M c ? b - $ hg revert --no-backup c -should show unknown: b +revert modification of a file (--no-backup) + $ hg revert --no-backup c $ hg status ? b - $ hg add b -should show b added +revert deletion (! status) of a added file +------------------------------------------ + + $ hg add b $ hg status b A b $ rm b - -should show b deleted - $ hg status b ! b $ hg revert -v b forgetting b - -should not find b - $ hg status b b: * (glob) -should show a c e - $ ls a c e -should verbosely save backup to e.orig +Test creation of backup (.orig) files +------------------------------------- $ echo z > e $ hg revert --all -v saving current version of e as e.orig reverting e -should say no changes needed +revert on clean file (no change) +-------------------------------- $ hg revert a no changes needed to a -should say file not managed +revert on an untracked file +--------------------------- $ echo q > q $ hg revert q file not managed: q $ rm q -should say file not found +revert on file that does not exists +----------------------------------- $ hg revert notfound notfound: no such file in rev 334a9e57682c @@ -122,21 +115,26 @@ A z ? e.orig -should add a, remove d, forget z +revert to another revision (--rev) +---------------------------------- $ hg revert --all -r0 adding a removing d forgetting z -should forget a, undelete d +revert explicitly to parent (--rev) +----------------------------------- $ hg revert --all -rtip forgetting a undeleting d $ rm a *.orig -should silently add a +revert to another revision (--rev) and exact match +-------------------------------------------------- + +exact match are more silent $ hg revert -r0 a $ hg st a @@ -145,21 +143,24 @@ $ hg st d R d -should silently keep d removed +should keep d removed $ hg revert -r0 d + no changes needed to d $ hg st d R d $ hg update -C 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + +revert of exec bit +------------------ + #if execbit $ chmod +x c $ hg revert --all reverting c -should print non-executable - $ test -x c || echo non-executable non-executable @@ -170,8 +171,6 @@ $ hg revert --all reverting c -should print executable - $ test -x c && echo executable executable #endif @@ -180,6 +179,7 @@ Issue241: update and revert produces inconsistent repositories +-------------------------------------------------------------- $ hg init a $ cd a @@ -193,20 +193,23 @@ $ mkdir b $ echo b > b/b -should fail - no arguments +call `hg revert` with no file specified +--------------------------------------- $ hg revert -rtip abort: no files or directories specified (use --all to revert all files, or 'hg update 1' to update) [255] -should succeed +call `hg revert` with --all +--------------------------- $ hg revert --all -rtip reverting a Issue332: confusing message when reverting directory +---------------------------------------------------- $ hg ci -A -m b adding b/b @@ -224,6 +227,7 @@ reverting a rename target should revert the source +-------------------------------------------------- $ hg mv a newa $ hg revert newa @@ -258,6 +262,7 @@ $ hg rm removed ignoreddir/removed should revert ignored* and undelete *removed +-------------------------------------------- $ hg revert -a --no-backup reverting ignored @@ -271,10 +276,14 @@ $ hg rm removed should silently revert the named files +-------------------------------------- $ hg revert --no-backup ignored removed $ hg st -mardi +Reverting copy (issue3920) +-------------------------- + someone set up us the copies $ rm .hgignore @@ -300,8 +309,9 @@ R ignored Test revert of a file added by one side of the merge +==================================================== -(remove any pending change) +remove any pending change $ hg revert --all forgetting allyour @@ -309,7 +319,7 @@ undeleting ignored $ hg purge --all --config extensions.purge= -(Adds a new commit) +Adds a new commit $ echo foo > newadd $ hg add newadd @@ -317,7 +327,7 @@ created new head -(merge it with the other head) +merge it with the other head $ hg merge # merge 1 into 2 2 files updated, 0 files merged, 1 files removed, 0 files unresolved @@ -331,7 +341,7 @@ commit: 2 modified, 1 removed (merge) update: (current) -(clarifies who added what) +clarifies who added what $ hg status M allyour @@ -344,7 +354,8 @@ A base R ignored -(revert file added by p1() to p1() state) +revert file added by p1() to p1() state +----------------------------------------- $ hg revert -r 'p1()' 'glob:newad?' $ hg status @@ -352,7 +363,8 @@ M base R ignored -(revert file added by p1() to p2() state) +revert file added by p1() to p2() state +------------------------------------------ $ hg revert -r 'p2()' 'glob:newad?' removing newadd @@ -362,7 +374,8 @@ R ignored R newadd -(revert file added by p2() to p2() state) +revert file added by p2() to p2() state +------------------------------------------ $ hg revert -r 'p2()' 'glob:allyou?' $ hg status @@ -371,7 +384,8 @@ R ignored R newadd -(revert file added by p2() to p1() state) +revert file added by p2() to p1() state +------------------------------------------ $ hg revert -r 'p1()' 'glob:allyou?' removing allyour @@ -381,4 +395,807 @@ R ignored R newadd +Systematic behavior validation of most possible cases +===================================================== +This section tests most of the possible combinations of working directory +changes and inter-revision changes. The number of possible cases is significant +but they all have a slighly different handling. So this section commits to +generating and testing all of them to allow safe refactoring of the revert code. + +A python script is used to generate a file history for each combination of +changes between, on one side the working directory and its parent and on +the other side, changes between a revert target (--rev) and working directory +parent. The three states generated are: + +- a "base" revision +- a "parent" revision +- the working directory (based on "parent") + +The file generated have names of the form: + + <changeset-state>_<working-copy-state> + +Here, "changeset-state" conveys the state in "base" and "parent" (or the change +that happen between them), "working-copy-state" is self explanatory. + +All known states are not tested yet. See inline documentation for details. +Special cases from merge and rename are not tested by this section. + +There are also multiple cases where the current revert implementation is known to +slightly misbehave. + +Write the python script to disk +------------------------------- + + $ cat << EOF > gen-revert-cases.py + > # generate proper file state to test revert behavior + > import sys + > import os + > + > # content of the file in "base" and "parent" + > # None means no file at all + > ctxcontent = { + > # clean: no change from base to parent + > 'clean': ['base', 'base'], + > # modified: file content change from base to parent + > 'modified': ['base', 'parent'], + > # added: file is missing from base and added in parent + > 'added': [None, 'parent'], + > # removed: file exist in base but is removed from parent + > 'removed': ['base', None], + > # file exist neither in base not in parent + > 'missing': [None, None], + > } + > + > # content of file in working copy + > wccontent = { + > # clean: wc content is the same as parent + > 'clean': lambda cc: cc[1], + > # revert: wc content is the same as base + > 'revert': lambda cc: cc[0], + > # wc: file exist with a content different from base and parent + > 'wc': lambda cc: 'wc', + > # removed: file is missing and marked as untracked + > 'removed': lambda cc: None, + > # deleted: file is recorded as tracked but missing + > # rely on file deletion outside of this script + > 'deleted': lambda cc:'TOBEDELETED', + > } + > # untracked-X is a version of X where the file is not tracked (? unknown) + > wccontent['untracked-clean'] = wccontent['clean'] + > wccontent['untracked-revert'] = wccontent['revert'] + > wccontent['untracked-wc'] = wccontent['wc'] + > + > # build the combination of possible states + > combination = [] + > for ctxkey in ctxcontent: + > for wckey in wccontent: + > filename = "%s_%s" % (ctxkey, wckey) + > combination.append((filename, ctxkey, wckey)) + > + > # make sure we have stable output + > combination.sort() + > + > # retrieve the state we must generate + > target = sys.argv[1] + > + > # compute file content + > content = [] + > for filename, ctxkey, wckey in combination: + > cc = ctxcontent[ctxkey] + > if target == 'filelist': + > print filename + > elif target == 'base': + > content.append((filename, cc[0])) + > elif target == 'parent': + > content.append((filename, cc[1])) + > elif target == 'wc': + > content.append((filename, wccontent[wckey](cc))) + > else: + > print >> sys.stderr, "unknown target:", target + > sys.exit(1) + > + > # write actual content + > for filename, data in content: + > if data is not None: + > f = open(filename, 'w') + > f.write(data + '\n') + > f.close() + > elif os.path.exists(filename): + > os.remove(filename) + > EOF + +check list of planned files + + $ python gen-revert-cases.py filelist + added_clean + added_deleted + added_removed + added_revert + added_untracked-clean + added_untracked-revert + added_untracked-wc + added_wc + clean_clean + clean_deleted + clean_removed + clean_revert + clean_untracked-clean + clean_untracked-revert + clean_untracked-wc + clean_wc + missing_clean + missing_deleted + missing_removed + missing_revert + missing_untracked-clean + missing_untracked-revert + missing_untracked-wc + missing_wc + modified_clean + modified_deleted + modified_removed + modified_revert + modified_untracked-clean + modified_untracked-revert + modified_untracked-wc + modified_wc + removed_clean + removed_deleted + removed_removed + removed_revert + removed_untracked-clean + removed_untracked-revert + removed_untracked-wc + removed_wc + +Script to make a simple text version of the content +--------------------------------------------------- + + $ cat << EOF >> dircontent.py + > # generate a simple text view of the directory for easy comparison + > import os + > files = os.listdir('.') + > files.sort() + > for filename in files: + > if os.path.isdir(filename): + > continue + > content = open(filename).read() + > print '%-6s %s' % (content.strip(), filename) + > EOF + +Generate appropriate repo state +------------------------------- + + $ hg init revert-ref + $ cd revert-ref + +Generate base changeset + + $ python ../gen-revert-cases.py base + $ hg addremove --similarity 0 + adding clean_clean + adding clean_deleted + adding clean_removed + adding clean_revert + adding clean_untracked-clean + adding clean_untracked-revert + adding clean_untracked-wc + adding clean_wc + adding modified_clean + adding modified_deleted + adding modified_removed + adding modified_revert + adding modified_untracked-clean + adding modified_untracked-revert + adding modified_untracked-wc + adding modified_wc + adding removed_clean + adding removed_deleted + adding removed_removed + adding removed_revert + adding removed_untracked-clean + adding removed_untracked-revert + adding removed_untracked-wc + adding removed_wc + $ hg status + A clean_clean + A clean_deleted + A clean_removed + A clean_revert + A clean_untracked-clean + A clean_untracked-revert + A clean_untracked-wc + A clean_wc + A modified_clean + A modified_deleted + A modified_removed + A modified_revert + A modified_untracked-clean + A modified_untracked-revert + A modified_untracked-wc + A modified_wc + A removed_clean + A removed_deleted + A removed_removed + A removed_revert + A removed_untracked-clean + A removed_untracked-revert + A removed_untracked-wc + A removed_wc + $ hg commit -m 'base' + +(create a simple text version of the content) + + $ python ../dircontent.py > ../content-base.txt + $ cat ../content-base.txt + base clean_clean + base clean_deleted + base clean_removed + base clean_revert + base clean_untracked-clean + base clean_untracked-revert + base clean_untracked-wc + base clean_wc + base modified_clean + base modified_deleted + base modified_removed + base modified_revert + base modified_untracked-clean + base modified_untracked-revert + base modified_untracked-wc + base modified_wc + base removed_clean + base removed_deleted + base removed_removed + base removed_revert + base removed_untracked-clean + base removed_untracked-revert + base removed_untracked-wc + base removed_wc + +Create parent changeset + + $ python ../gen-revert-cases.py parent + $ hg addremove --similarity 0 + adding added_clean + adding added_deleted + adding added_removed + adding added_revert + adding added_untracked-clean + adding added_untracked-revert + adding added_untracked-wc + adding added_wc + removing removed_clean + removing removed_deleted + removing removed_removed + removing removed_revert + removing removed_untracked-clean + removing removed_untracked-revert + removing removed_untracked-wc + removing removed_wc + $ hg status + M modified_clean + M modified_deleted + M modified_removed + M modified_revert + M modified_untracked-clean + M modified_untracked-revert + M modified_untracked-wc + M modified_wc + A added_clean + A added_deleted + A added_removed + A added_revert + A added_untracked-clean + A added_untracked-revert + A added_untracked-wc + A added_wc + R removed_clean + R removed_deleted + R removed_removed + R removed_revert + R removed_untracked-clean + R removed_untracked-revert + R removed_untracked-wc + R removed_wc + $ hg commit -m 'parent' + +(create a simple text version of the content) + + $ python ../dircontent.py > ../content-parent.txt + $ cat ../content-parent.txt + parent added_clean + parent added_deleted + parent added_removed + parent added_revert + parent added_untracked-clean + parent added_untracked-revert + parent added_untracked-wc + parent added_wc + base clean_clean + base clean_deleted + base clean_removed + base clean_revert + base clean_untracked-clean + base clean_untracked-revert + base clean_untracked-wc + base clean_wc + parent modified_clean + parent modified_deleted + parent modified_removed + parent modified_revert + parent modified_untracked-clean + parent modified_untracked-revert + parent modified_untracked-wc + parent modified_wc + +Setup working directory + + $ python ../gen-revert-cases.py wc | cat + $ hg addremove --similarity 0 + removing added_removed + removing added_revert + removing added_untracked-revert + removing clean_removed + adding missing_deleted + adding missing_untracked-wc + adding missing_wc + removing modified_removed + adding removed_deleted + adding removed_revert + adding removed_untracked-revert + adding removed_untracked-wc + adding removed_wc + $ hg forget *untracked* + $ rm *deleted* + $ hg status + M added_wc + M clean_wc + M modified_revert + M modified_wc + A missing_wc + A removed_revert + A removed_wc + R added_removed + R added_revert + R added_untracked-clean + R added_untracked-revert + R added_untracked-wc + R clean_removed + R clean_untracked-clean + R clean_untracked-revert + R clean_untracked-wc + R modified_removed + R modified_untracked-clean + R modified_untracked-revert + R modified_untracked-wc + ! added_deleted + ! clean_deleted + ! missing_deleted + ! modified_deleted + ! removed_deleted + ? missing_untracked-wc + ? removed_untracked-revert + ? removed_untracked-wc + + $ hg status --rev 'desc("base")' + M clean_wc + M modified_clean + M modified_wc + M removed_wc + A added_clean + A added_wc + A missing_wc + R clean_removed + R clean_untracked-clean + R clean_untracked-revert + R clean_untracked-wc + R modified_removed + R modified_untracked-clean + R modified_untracked-revert + R modified_untracked-wc + R removed_clean + R removed_deleted + R removed_removed + R removed_untracked-clean + R removed_untracked-revert + R removed_untracked-wc + ! added_deleted + ! clean_deleted + ! missing_deleted + ! modified_deleted + ! removed_deleted + ? missing_untracked-wc + +(create a simple text version of the content) + + $ python ../dircontent.py > ../content-wc.txt + $ cat ../content-wc.txt + parent added_clean + parent added_untracked-clean + wc added_untracked-wc + wc added_wc + base clean_clean + base clean_revert + base clean_untracked-clean + base clean_untracked-revert + wc clean_untracked-wc + wc clean_wc + wc missing_untracked-wc + wc missing_wc + parent modified_clean + base modified_revert + parent modified_untracked-clean + base modified_untracked-revert + wc modified_untracked-wc + wc modified_wc + base removed_revert + base removed_untracked-revert + wc removed_untracked-wc + wc removed_wc + + $ cd .. + +Test revert --all to parent content +----------------------------------- + +(setup from reference repo) + + $ cp -r revert-ref revert-parent-all + $ cd revert-parent-all + +check revert output + + $ hg revert --all + reverting added_deleted + undeleting added_removed + undeleting added_revert + undeleting added_untracked-clean + undeleting added_untracked-revert + undeleting added_untracked-wc + reverting added_wc + reverting clean_deleted + undeleting clean_removed + undeleting clean_untracked-clean + undeleting clean_untracked-revert + undeleting clean_untracked-wc + reverting clean_wc + forgetting missing_deleted + forgetting missing_wc + reverting modified_deleted + undeleting modified_removed + reverting modified_revert + undeleting modified_untracked-clean + undeleting modified_untracked-revert + undeleting modified_untracked-wc + reverting modified_wc + forgetting removed_deleted + forgetting removed_revert + forgetting removed_wc + +Compare resulting directory with revert target. + +The diff is filtered to include change only. The only difference should be +additional `.orig` backup file when applicable. + + $ python ../dircontent.py > ../content-parent-all.txt + $ cd .. + $ diff -U 0 -- content-parent.txt content-parent-all.txt | grep _ + +wc added_untracked-wc.orig + +wc added_wc.orig + +wc clean_untracked-wc.orig + +wc clean_wc.orig + +wc missing_untracked-wc + +wc missing_wc + +base modified_revert.orig + +base modified_untracked-revert.orig + +wc modified_untracked-wc.orig + +wc modified_wc.orig + +base removed_revert + +base removed_untracked-revert + +wc removed_untracked-wc + +wc removed_wc + +Test revert --all to "base" content +----------------------------------- + +(setup from reference repo) + + $ cp -r revert-ref revert-base-all + $ cd revert-base-all + +check revert output + + $ hg revert --all --rev 'desc(base)' + removing added_clean + removing added_deleted + removing added_wc + reverting clean_deleted + undeleting clean_removed + undeleting clean_untracked-clean + undeleting clean_untracked-revert + undeleting clean_untracked-wc + reverting clean_wc + forgetting missing_deleted + forgetting missing_wc + reverting modified_clean + reverting modified_deleted + undeleting modified_removed + undeleting modified_untracked-clean + undeleting modified_untracked-revert + undeleting modified_untracked-wc + reverting modified_wc + adding removed_clean + reverting removed_deleted + adding removed_removed + adding removed_untracked-clean + adding removed_untracked-revert + adding removed_untracked-wc + reverting removed_wc + +Compare resulting directory with revert target. + +The diff is filtered to include change only. The only difference should be +additional `.orig` backup file when applicable. + +Misbehavior: + +- no backup for +| - added_wc (DATA LOSS) + + $ python ../dircontent.py > ../content-base-all.txt + $ cd .. + $ diff -U 0 -- content-base.txt content-base-all.txt | grep _ + +parent added_untracked-clean + +wc added_untracked-wc + +wc clean_untracked-wc.orig + +wc clean_wc.orig + +wc missing_untracked-wc + +wc missing_wc + +parent modified_untracked-clean.orig + +wc modified_untracked-wc.orig + +wc modified_wc.orig + +wc removed_untracked-wc.orig + +wc removed_wc.orig + +Test revert to parent content with explicit file name +----------------------------------------------------- + +(setup from reference repo) + + $ cp -r revert-ref revert-parent-explicit + $ cd revert-parent-explicit + +revert all files individually and check the output +(output is expected to be different than in the --all case) + + $ for file in `python ../gen-revert-cases.py filelist`; do + > echo '### revert for:' $file; + > hg revert $file; + > echo + > done + ### revert for: added_clean + no changes needed to added_clean + + ### revert for: added_deleted + + ### revert for: added_removed + + ### revert for: added_revert + + ### revert for: added_untracked-clean + + ### revert for: added_untracked-revert + + ### revert for: added_untracked-wc + + ### revert for: added_wc + + ### revert for: clean_clean + no changes needed to clean_clean + + ### revert for: clean_deleted + + ### revert for: clean_removed + + ### revert for: clean_revert + no changes needed to clean_revert + + ### revert for: clean_untracked-clean + + ### revert for: clean_untracked-revert + + ### revert for: clean_untracked-wc + + ### revert for: clean_wc + + ### revert for: missing_clean + missing_clean: no such file in rev * (glob) + + ### revert for: missing_deleted + + ### revert for: missing_removed + missing_removed: no such file in rev * (glob) + + ### revert for: missing_revert + missing_revert: no such file in rev * (glob) + + ### revert for: missing_untracked-clean + missing_untracked-clean: no such file in rev * (glob) + + ### revert for: missing_untracked-revert + missing_untracked-revert: no such file in rev * (glob) + + ### revert for: missing_untracked-wc + file not managed: missing_untracked-wc + + ### revert for: missing_wc + + ### revert for: modified_clean + no changes needed to modified_clean + + ### revert for: modified_deleted + + ### revert for: modified_removed + + ### revert for: modified_revert + + ### revert for: modified_untracked-clean + + ### revert for: modified_untracked-revert + + ### revert for: modified_untracked-wc + + ### revert for: modified_wc + + ### revert for: removed_clean + removed_clean: no such file in rev * (glob) + + ### revert for: removed_deleted + + ### revert for: removed_removed + removed_removed: no such file in rev * (glob) + + ### revert for: removed_revert + + ### revert for: removed_untracked-clean + removed_untracked-clean: no such file in rev * (glob) + + ### revert for: removed_untracked-revert + file not managed: removed_untracked-revert + + ### revert for: removed_untracked-wc + file not managed: removed_untracked-wc + + ### revert for: removed_wc + + +check resulting directory againt the --all run +(There should be no difference) + + $ python ../dircontent.py > ../content-parent-explicit.txt + $ cd .. + $ diff -U 0 -- content-parent-all.txt content-parent-explicit.txt | grep _ + [1] + +Test revert to "base" content with explicit file name +----------------------------------------------------- + +(setup from reference repo) + + $ cp -r revert-ref revert-base-explicit + $ cd revert-base-explicit + +revert all files individually and check the output +(output is expected to be different than in the --all case) + + $ for file in `python ../gen-revert-cases.py filelist`; do + > echo '### revert for:' $file; + > hg revert $file --rev 'desc(base)'; + > echo + > done + ### revert for: added_clean + + ### revert for: added_deleted + + ### revert for: added_removed + no changes needed to added_removed + + ### revert for: added_revert + no changes needed to added_revert + + ### revert for: added_untracked-clean + no changes needed to added_untracked-clean + + ### revert for: added_untracked-revert + no changes needed to added_untracked-revert + + ### revert for: added_untracked-wc + no changes needed to added_untracked-wc + + ### revert for: added_wc + + ### revert for: clean_clean + no changes needed to clean_clean + + ### revert for: clean_deleted + + ### revert for: clean_removed + + ### revert for: clean_revert + no changes needed to clean_revert + + ### revert for: clean_untracked-clean + + ### revert for: clean_untracked-revert + + ### revert for: clean_untracked-wc + + ### revert for: clean_wc + + ### revert for: missing_clean + missing_clean: no such file in rev * (glob) + + ### revert for: missing_deleted + + ### revert for: missing_removed + missing_removed: no such file in rev * (glob) + + ### revert for: missing_revert + missing_revert: no such file in rev * (glob) + + ### revert for: missing_untracked-clean + missing_untracked-clean: no such file in rev * (glob) + + ### revert for: missing_untracked-revert + missing_untracked-revert: no such file in rev * (glob) + + ### revert for: missing_untracked-wc + file not managed: missing_untracked-wc + + ### revert for: missing_wc + + ### revert for: modified_clean + + ### revert for: modified_deleted + + ### revert for: modified_removed + + ### revert for: modified_revert + no changes needed to modified_revert + + ### revert for: modified_untracked-clean + + ### revert for: modified_untracked-revert + + ### revert for: modified_untracked-wc + + ### revert for: modified_wc + + ### revert for: removed_clean + + ### revert for: removed_deleted + + ### revert for: removed_removed + + ### revert for: removed_revert + no changes needed to removed_revert + + ### revert for: removed_untracked-clean + + ### revert for: removed_untracked-revert + + ### revert for: removed_untracked-wc + + ### revert for: removed_wc + + +check resulting directory againt the --all run +(There should be no difference) + + $ python ../dircontent.py > ../content-base-explicit.txt + $ cd .. + $ diff -U 0 -- content-base-all.txt content-base-explicit.txt | grep _ + [1]
--- a/tests/test-revset-outgoing.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-revset-outgoing.t Sat Sep 27 14:47:52 2014 -0500 @@ -36,6 +36,14 @@ $ cd b $ cat .hg/hgrc + # You may want to set your username here if it is not set + # globally, or this repository requires a different + # username from your usual configuration. If you want to + # set something for all of your repositories on this + # computer, try running the command + # 'hg config --edit --global' + # [ui] + # username = Jane Doe <jdoe@example.com> [paths] default = $TESTTMP/a#stable (glob) @@ -76,6 +84,14 @@ $ echo "green = ../a#default" >> .hg/hgrc $ cat .hg/hgrc + # You may want to set your username here if it is not set + # globally, or this repository requires a different + # username from your usual configuration. If you want to + # set something for all of your repositories on this + # computer, try running the command + # 'hg config --edit --global' + # [ui] + # username = Jane Doe <jdoe@example.com> [paths] default = $TESTTMP/a#stable (glob) green = ../a#default
--- a/tests/test-revset.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-revset.t Sat Sep 27 14:47:52 2014 -0500 @@ -567,10 +567,10 @@ test intersecting something with an addset $ log 'parents(outgoing() or removes(a))' + 8 1 4 5 - 8 check that conversion to only works $ try --optimize '::3 - ::1'
--- a/tests/test-rollback.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-rollback.t Sat Sep 27 14:47:52 2014 -0500 @@ -96,7 +96,7 @@ bar $ hg bookmark --delete foo -rollback by pretxncommit saves commit message (issue 1635) +rollback by pretxncommit saves commit message (issue1635) $ echo a >> a $ hg --config hooks.pretxncommit=false commit -m"precious commit message"
--- a/tests/test-run-tests.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-run-tests.t Sat Sep 27 14:47:52 2014 -0500 @@ -13,6 +13,8 @@ $ cat > test-success.t << EOF > $ echo babar > babar + > $ echo xyzzy + > xyzzy > EOF $ $TESTDIR/run-tests.py --with-hg=`which hg` @@ -25,16 +27,20 @@ $ cat > test-failure.t << EOF > $ echo babar > rataxes + > This is a noop statement so that + > this test is still more bytes than success. > EOF $ $TESTDIR/run-tests.py --with-hg=`which hg` --- $TESTTMP/test-failure.t (glob) +++ $TESTTMP/test-failure.t.err (glob) - @@ -1,2 +1,2 @@ + @@ -1,4 +1,4 @@ $ echo babar - rataxes + babar + This is a noop statement so that + this test is still more bytes than success. ERROR: test-failure.t output changed !. @@ -42,6 +48,39 @@ # Ran 2 tests, 0 skipped, 0 warned, 1 failed. python hash seed: * (glob) [1] +test --xunit support + $ $TESTDIR/run-tests.py --with-hg=`which hg` --xunit=xunit.xml + + --- $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. + + ERROR: test-failure.t output changed + !. + Failed test-failure.t: output changed + # Ran 2 tests, 0 skipped, 0 warned, 1 failed. + python hash seed: * (glob) + [1] + $ cat xunit.xml + <?xml version="1.0" encoding="utf-8"?> + <testsuite errors="0" failures="1" name="run-tests" skipped="0" tests="2"> + <testcase name="test-success.t" time="*"/> (glob) + <testcase name="test-failure.t" time="*"> (glob) + <![CDATA[--- $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. + ]]> </testcase> + </testsuite> test for --retest ==================== @@ -50,15 +89,17 @@ --- $TESTTMP/test-failure.t (glob) +++ $TESTTMP/test-failure.t.err (glob) - @@ -1,2 +1,2 @@ + @@ -1,4 +1,4 @@ $ echo babar - rataxes + babar + This is a noop statement so that + this test is still more bytes than success. ERROR: test-failure.t output changed ! Failed test-failure.t: output changed - # Ran 1 tests, 1 skipped, 0 warned, 1 failed. + # Ran 2 tests, 1 skipped, 0 warned, 1 failed. python hash seed: * (glob) [1] @@ -71,16 +112,23 @@ . # Ran 1 tests, 0 skipped, 0 warned, 0 failed. +success w/ keyword + $ $TESTDIR/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 --- $TESTTMP/test-failure.t (glob) +++ $TESTTMP/test-failure.t.err (glob) - @@ -1,2 +1,2 @@ + @@ -1,4 +1,4 @@ $ echo babar - rataxes + babar + This is a noop statement so that + this test is still more bytes than success. ERROR: test-failure.t output changed ! @@ -89,6 +137,25 @@ python hash seed: * (glob) [1] +failure w/ keyword + $ $TESTDIR/run-tests.py --with-hg=`which hg` -k rataxes + + --- $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. + + ERROR: test-failure.t output changed + ! + Failed test-failure.t: output changed + # Ran 2 tests, 1 skipped, 0 warned, 1 failed. + python hash seed: * (glob) + [1] + Running In Debug Mode ====================== @@ -97,14 +164,18 @@ SALT* 0 0 (glob) + echo babar babar - + echo SALT* 2 0 (glob) - SALT* 2 0 (glob) + + echo SALT* 4 0 (glob) + SALT* 4 0 (glob) .+ echo SALT* 0 0 (glob) SALT* 0 0 (glob) + echo babar babar + echo SALT* 2 0 (glob) SALT* 2 0 (glob) + + echo xyzzy + xyzzy + + echo SALT* 4 0 (glob) + SALT* 4 0 (glob) . # Ran 2 tests, 0 skipped, 0 warned, 0 failed. @@ -118,19 +189,23 @@ --- $TESTTMP/test-failure*.t (glob) +++ $TESTTMP/test-failure*.t.err (glob) - @@ -1,2 +1,2 @@ + @@ -1,4 +1,4 @@ $ echo babar - rataxes + babar + This is a noop statement so that + this test is still more bytes than success. ERROR: test-failure*.t output changed (glob) ! --- $TESTTMP/test-failure*.t (glob) +++ $TESTTMP/test-failure*.t.err (glob) - @@ -1,2 +1,2 @@ + @@ -1,4 +1,4 @@ $ echo babar - rataxes + babar + This is a noop statement so that + this test is still more bytes than success. ERROR: test-failure*.t output changed (glob) ! @@ -156,10 +231,12 @@ --- $TESTTMP/test-failure.t +++ $TESTTMP/test-failure.t.err - @@ -1,2 +1,2 @@ + @@ -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] ERROR: test-failure.t output changed !. @@ -171,6 +248,32 @@ $ cat test-failure.t $ echo babar rataxes + This is a noop statement so that + this test is still more bytes than success. + +Interactive with custom view + + $ echo 'n' | $TESTDIR/run-tests.py --with-hg=`which hg` -i --view echo + $TESTTMP/test-failure.t $TESTTMP/test-failure.t.err + Accept this change? [n]* (glob) + ERROR: test-failure.t output changed + !. + Failed test-failure.t: output changed + # Ran 2 tests, 0 skipped, 0 warned, 1 failed. + python hash seed: * (glob) + [1] + +View the fix + + $ echo 'y' | $TESTDIR/run-tests.py --with-hg=`which hg` --view echo + $TESTTMP/test-failure.t $TESTTMP/test-failure.t.err + + ERROR: test-failure.t output changed + !. + Failed test-failure.t: output changed + # Ran 2 tests, 0 skipped, 0 warned, 1 failed. + python hash seed: * (glob) + [1] Accept the fix @@ -178,16 +281,20 @@ --- $TESTTMP/test-failure.t +++ $TESTTMP/test-failure.t.err - @@ -1,2 +1,2 @@ + @@ -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] .. # Ran 2 tests, 0 skipped, 0 warned, 0 failed. $ cat test-failure.t $ echo babar babar + This is a noop statement so that + this test is still more bytes than success. (reinstall) $ mv backup test-failure.t @@ -201,3 +308,107 @@ # Ran 2 tests, 0 skipped, 0 warned, 1 failed. python hash seed: * (glob) [1] + +test for --time +================== + + $ $TESTDIR/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) + +test for --time with --job enabled +==================================== + + $ $TESTDIR/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) + +Skips +================ + $ cat > test-skip.t <<EOF + > $ echo xyzzy + > #require false + > EOF + $ $TESTDIR/run-tests.py --with-hg=`which hg` --nodiff + !.s + Skipped test-skip.t: skipped + Failed test-failure.t: output changed + # Ran 2 tests, 1 skipped, 0 warned, 1 failed. + python hash seed: * (glob) + [1] + + $ $TESTDIR/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 \ + > --xunit=xunit.xml + .s + Skipped test-skip.t: skipped + # Ran 2 tests, 2 skipped, 0 warned, 0 failed. + $ cat xunit.xml + <?xml version="1.0" encoding="utf-8"?> + <testsuite errors="0" failures="0" name="run-tests" skipped="2" tests="2"> + <testcase name="test-success.t" time="*"/> (glob) + </testsuite> + +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 \ + > test-failure.t test-bogus.t + ss + Skipped test-bogus.t: Doesn't exist + Skipped test-failure.t: blacklisted + # Ran 0 tests, 2 skipped, 0 warned, 0 failed. + +test for --json +================== + + $ $TESTDIR/run-tests.py --with-hg=`which hg` --json + + --- $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. + + ERROR: test-failure.t output changed + !.s + Skipped test-skip.t: skipped + Failed test-failure.t: output changed + # Ran 2 tests, 1 skipped, 0 warned, 1 failed. + python hash seed: * (glob) + [1] + + $ cat report.json + testreport ={ + "test-failure.t": [\{] (re) + "csys": "\s*[\d\.]{5}", (re) + "cuser": "\s*[\d\.]{5}", (re) + "result": "failure", + "time": "\s*[\d\.]{5}" (re) + }, + "test-skip.t": { + "csys": "\s*[\d\.]{5}", (re) + "cuser": "\s*[\d\.]{5}", (re) + "result": "skip", + "time": "\s*[\d\.]{5}" (re) + }, + "test-success.t": [\{] (re) + "csys": "\s*[\d\.]{5}", (re) + "cuser": "\s*[\d\.]{5}", (re) + "result": "success", + "time": "\s*[\d\.]{5}" (re) + } + } (no-eol)
--- a/tests/test-schemes.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-schemes.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve $ cat <<EOF >> $HGRCPATH > [extensions]
--- a/tests/test-serve.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-serve.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" serve || exit 80 +#require serve $ hgserve() > {
--- a/tests/test-share.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-share.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons $ echo "[extensions]" >> $HGRCPATH $ echo "share = " >> $HGRCPATH
--- a/tests/test-shelve.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-shelve.t Sat Sep 27 14:47:52 2014 -0500 @@ -446,7 +446,7 @@ $ hg --config extensions.mq=! unshelve unshelving change 'test' -shelve should leave dirstate clean (issue 4055) +shelve should leave dirstate clean (issue4055) $ cd .. $ hg init shelverebase @@ -475,7 +475,7 @@ $ cd .. -shelve should only unshelve pending changes (issue 4068) +shelve should only unshelve pending changes (issue4068) $ hg init onlypendingchanges $ cd onlypendingchanges @@ -680,9 +680,6 @@ g $ hg unshelve --abort rebase aborted - no changes needed to a - no changes needed to d - no changes needed to e unshelve of 'default' aborted $ hg st ? f.orig
--- a/tests/test-simplemerge.py Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-simplemerge.py Sat Sep 27 14:47:52 2014 -0500 @@ -320,66 +320,6 @@ self.log(''.join(ml)) self.assertEquals(ml, MERGED_RESULT) - def test_minimal_conflicts_common(self): - """Reprocessing""" - base_text = ("a\n" * 20).splitlines(True) - this_text = ("a\n"*10+"b\n" * 10).splitlines(True) - other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True) - m3 = Merge3(base_text, other_text, this_text) - m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True) - merged_text = "".join(list(m_lines)) - optimal_text = ("a\n" * 10 + "<<<<<<< OTHER\nc\n=======\n" - + ">>>>>>> THIS\n" - + 8* "b\n" + "<<<<<<< OTHER\nc\n=======\n" - + 2* "b\n" + ">>>>>>> THIS\n") - self.assertEquals(optimal_text, merged_text) - - def test_minimal_conflicts_unique(self): - def add_newline(s): - """Add a newline to each entry in the string""" - return [(x+'\n') for x in s] - - base_text = add_newline("abcdefghijklm") - this_text = add_newline("abcdefghijklmNOPQRSTUVWXYZ") - other_text = add_newline("abcdefghijklm1OPQRSTUVWXY2") - m3 = Merge3(base_text, other_text, this_text) - m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True) - merged_text = "".join(list(m_lines)) - optimal_text = ''.join(add_newline("abcdefghijklm") - + ["<<<<<<< OTHER\n1\n=======\nN\n>>>>>>> THIS\n"] - + add_newline('OPQRSTUVWXY') - + ["<<<<<<< OTHER\n2\n=======\nZ\n>>>>>>> THIS\n"] - ) - self.assertEquals(optimal_text, merged_text) - - def test_minimal_conflicts_nonunique(self): - def add_newline(s): - """Add a newline to each entry in the string""" - return [(x+'\n') for x in s] - - base_text = add_newline("abacddefgghij") - this_text = add_newline("abacddefgghijkalmontfprz") - other_text = add_newline("abacddefgghijknlmontfprd") - m3 = Merge3(base_text, other_text, this_text) - m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True) - merged_text = "".join(list(m_lines)) - optimal_text = ''.join(add_newline("abacddefgghijk") - + ["<<<<<<< OTHER\nn\n=======\na\n>>>>>>> THIS\n"] - + add_newline('lmontfpr') - + ["<<<<<<< OTHER\nd\n=======\nz\n>>>>>>> THIS\n"] - ) - self.assertEquals(optimal_text, merged_text) - - def test_reprocess_and_base(self): - """Reprocessing and showing base breaks correctly""" - base_text = ("a\n" * 20).splitlines(True) - this_text = ("a\n"*10+"b\n" * 10).splitlines(True) - other_text = ("a\n"*10+"c\n"+"b\n" * 8 + "c\n").splitlines(True) - m3 = Merge3(base_text, other_text, this_text) - m_lines = m3.merge_lines('OTHER', 'THIS', reprocess=True, - base_marker='|||||||') - self.assertRaises(CantReprocessAndShowBase, list, m_lines) - def test_binary(self): self.assertRaises(util.Abort, Merge3, ['\x00'], ['a'], ['b'])
--- a/tests/test-simplemerge.py.out Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-simplemerge.py.out Sat Sep 27 14:47:52 2014 -0500 @@ -1,5 +1,5 @@ -.................... +................ ---------------------------------------------------------------------- -Ran 20 tests in 0.000s +Ran 16 tests in 0.000s OK
--- a/tests/test-ssh.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-ssh.t Sat Sep 27 14:47:52 2014 -0500 @@ -360,6 +360,47 @@ $ 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 + + $ 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 @@ -387,3 +428,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 '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_URL=remote:ssh:127.0.0.1
--- a/tests/test-static-http.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-static-http.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons #if windows $ hg clone http://localhost:$HGPORT/ copy @@ -125,7 +125,7 @@ updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved -test with "/" URI (issue 747) and subrepo +test with "/" URI (issue747) and subrepo $ hg init $ hg init sub
--- a/tests/test-status-color.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-status-color.t Sat Sep 27 14:47:52 2014 -0500 @@ -20,6 +20,14 @@ \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4mb/in_b\x1b[0m (esc) \x1b[0;35;1;4m? \x1b[0m\x1b[0;35;1;4min_root\x1b[0m (esc) + $ hg status --color=debug + [status.unknown|? ][status.unknown|a/1/in_a_1] + [status.unknown|? ][status.unknown|a/in_a] + [status.unknown|? ][status.unknown|b/1/in_b_1] + [status.unknown|? ][status.unknown|b/2/in_b_2] + [status.unknown|? ][status.unknown|b/in_b] + [status.unknown|? ][status.unknown|in_root] + hg status . in repo root: $ hg status --color=always . @@ -137,6 +145,13 @@ adding deleted adding modified adding removed + $ hg log --color=debug + [log.changeset changeset.draft|changeset: 0:389aef86a55e] + [log.tag|tag: tip] + [log.user|user: test] + [log.date|date: Thu Jan 01 00:00:00 1970 +0000] + [log.summary|summary: initial checkin] + $ touch modified added unknown ignored $ hg add added $ hg remove removed
--- a/tests/test-status.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-status.t Sat Sep 27 14:47:52 2014 -0500 @@ -165,6 +165,48 @@ C .hgignore C modified + $ hg status -A -Tjson + [ + { + "path": "added", + "status": "A" + }, + { + "copy": "modified", + "path": "copied", + "status": "A" + }, + { + "path": "removed", + "status": "R" + }, + { + "path": "deleted", + "status": "!" + }, + { + "path": "unknown", + "status": "?" + }, + { + "path": "ignored", + "status": "I" + }, + { + "path": ".hgignore", + "status": "C" + }, + { + "path": "modified", + "status": "C" + } + ] + + $ hg status -A -Tpickle > pickle + >>> import pickle + >>> print sorted((x['status'], x['path']) for x in pickle.load(open("pickle"))) + [('!', 'deleted'), ('?', 'pickle'), ('?', 'unknown'), ('A', 'added'), ('A', 'copied'), ('C', '.hgignore'), ('C', 'modified'), ('I', 'ignored'), ('R', 'removed')] + $ rm pickle $ echo "^ignoreddir$" > .hgignore $ mkdir ignoreddir @@ -350,6 +392,11 @@ $ hg status -A --rev 1 1 R 1/2/3/4/5/b.txt + $ hg status --config ui.formatdebug=True --rev 1 1 + status = [ + {*'path': '1/2/3/4/5/b.txt'*}, (glob) + ] + #if windows $ hg --config ui.slash=false status -A --rev 1 1 R 1\2\3\4\5\b.txt
--- a/tests/test-strict.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-strict.t Sat Sep 27 14:47:52 2014 -0500 @@ -37,7 +37,7 @@ summary summarize working directory state update update working directory (or switch revisions) - use "hg help" for the full list of commands or "hg -v" for details + (use "hg help" for the full list of commands or "hg -v" for details) [255] $ hg annotate a 0: a
--- a/tests/test-strip.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-strip.t Sat Sep 27 14:47:52 2014 -0500 @@ -532,9 +532,9 @@ strip changesets and all their descendants from the repository - use "hg help -e strip" to show help for the strip extension + (use "hg help -e strip" to show help for the strip extension) - options: + options ([+] can be repeated): -r --rev REV [+] strip specified revision (optional, can specify revisions without this option) @@ -545,7 +545,5 @@ -B --bookmark VALUE remove revs only reachable from given bookmark --mq operate on patch repository - [+] marked option can be specified multiple times - - use "hg help strip" to show the full help text + (use "hg strip -h" to show more help) [255]
--- a/tests/test-subrepo-git.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-subrepo-git.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" git || exit 80 +#require git make git commits repeatable
--- a/tests/test-subrepo-relative-path.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-subrepo-relative-path.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons Preparing the subrepository 'sub'
--- a/tests/test-subrepo-svn.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-subrepo-svn.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" svn15 || exit 80 +#require svn15 $ SVNREPOPATH=`pwd`/svn-repo #if windows
--- a/tests/test-symlink-placeholder.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-symlink-placeholder.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" symlink || exit 80 +#require symlink Create extension that can disable symlink support:
--- a/tests/test-symlinks.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-symlinks.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" symlink || exit 80 +#require symlink == tests added in 0.7 ==
--- a/tests/test-transplant.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-transplant.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons $ cat <<EOF >> $HGRCPATH > [extensions] @@ -95,8 +95,13 @@ $ hg ci -qm "b4" $ hg status --rev "7^1" --rev 7 A b3 - $ HGEDITOR=cat hg transplant --edit 7 + $ cat > $TESTTMP/checkeditform.sh <<EOF + > env | grep HGEDITFORM + > true + > EOF + $ HGEDITOR="sh $TESTTMP/checkeditform.sh; cat" hg transplant --edit 7 applying ffd6818a3975 + HGEDITFORM=transplant.normal b3 @@ -373,7 +378,8 @@ patch failed to apply abort: fix up the merge and run hg transplant --continue [255] - $ hg transplant --continue + $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant --continue -e + HGEDITFORM=transplant.normal 46ae92138f3c transplanted as 9159dada197d $ hg transplant 1:3 skipping already applied revision 1:46ae92138f3c @@ -430,9 +436,30 @@ transplant - $ hg transplant -m 1 + $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant -m 1 -e applying 42dc4432fd35 + HGEDITFORM=transplant.merge 1:42dc4432fd35 merged at a9f4acbac129 + $ hg update -q -C 2 + $ cat > a <<EOF + > x + > y + > z + > EOF + $ hg commit -m replace + $ hg update -q -C 4 + $ hg transplant -m 5 + applying 600a3cdcb41d + patching file a + Hunk #1 FAILED at 0 + 1 out of 1 hunks FAILED -- saving rejects to file a.rej + patch failed to apply + abort: fix up the merge and run hg transplant --continue + [255] + $ HGEDITOR="sh $TESTTMP/checkeditform.sh" hg transplant --continue -e + HGEDITFORM=transplant.merge + 600a3cdcb41d transplanted as a3f88be652e0 + $ cd .. test transplant into empty repository
--- a/tests/test-treediscovery-legacy.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-treediscovery-legacy.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons Tests discovery against servers without getbundle support:
--- a/tests/test-treediscovery.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-treediscovery.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons Tests discovery against servers without getbundle support: @@ -522,12 +522,13 @@ "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases "GET /?cmd=capabilities HTTP/1.1" 200 - "GET /?cmd=heads HTTP/1.1" 200 - + "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+1827a5bb63e602382eb89dd58f2ac9f3b007ad91 "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=capabilities HTTP/1.1" 200 - "GET /?cmd=heads HTTP/1.1" 200 - "GET /?cmd=capabilities HTTP/1.1" 200 -
--- a/tests/test-unbundlehash.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-unbundlehash.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" killdaemons || exit 80 +#require killdaemons Test wire protocol unbundle with hashed heads (capability: unbundlehash)
--- a/tests/test-update-issue1456.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-update-issue1456.t Sat Sep 27 14:47:52 2014 -0500 @@ -1,4 +1,4 @@ - $ "$TESTDIR/hghave" execbit || exit 80 +#require execbit $ rm -rf a $ hg init a
--- a/tests/test-url-rev.t Mon Sep 22 23:46:38 2014 +0900 +++ b/tests/test-url-rev.t Sat Sep 27 14:47:52 2014 -0500 @@ -41,6 +41,14 @@ summary: change a $ cat clone/.hg/hgrc + # You may want to set your username here if it is not set + # globally, or this repository requires a different + # username from your usual configuration. If you want to + # set something for all of your repositories on this + # computer, try running the command + # 'hg config --edit --global' + # [ui] + # username = Jane Doe <jdoe@example.com> [paths] default = $TESTTMP/repo#foo (glob)