# HG changeset patch # User Matt Mackall # Date 1445374750 18000 # Node ID b66e3ca0b90c3095ea28dfd39aa24247bebf5c20 # Parent d3712209921d2598a59af262cab4f0726ae25a5e# Parent 58a309e9cf80d74d96e8c56cb95be20a4b130092 merge default into stable for code freeze diff -r d3712209921d -r b66e3ca0b90c Makefile --- a/Makefile Thu Oct 08 23:24:38 2015 +0900 +++ b/Makefile Tue Oct 20 15:59:10 2015 -0500 @@ -51,6 +51,9 @@ build: $(PYTHON) setup.py $(PURE) build $(COMPILER:%=-c %) +wheel: + FORCE_SETUPTOOLS=1 $(PYTHON) setup.py $(PURE) bdist_wheel $(COMPILER:%=-c %) + doc: $(MAKE) -C doc @@ -157,14 +160,12 @@ N=`cd dist && echo mercurial-*.mpkg | sed 's,\.mpkg$$,,'` && hdiutil create -srcfolder dist/$$N.mpkg/ -scrub -volname "$$N" -ov packages/osx/$$N.dmg rm -rf dist/mercurial-*.mpkg -debian-jessie: - mkdir -p packages/debian-jessie - contrib/builddeb - mv debbuild/*.deb packages/debian-jessie - rm -rf debbuild +deb: + mkdir -p packages/debian-unknown + contrib/builddeb --release unknown docker-debian-jessie: - mkdir -p packages/debian/jessie + mkdir -p packages/debian-jessie contrib/dockerdeb jessie fedora20: diff -r d3712209921d -r b66e3ca0b90c README --- a/README Thu Oct 08 23:24:38 2015 +0900 +++ b/README Tue Oct 20 15:59:10 2015 -0500 @@ -16,5 +16,5 @@ $ make local # build for inplace usage $ ./hg --version # should show the latest version -See http://mercurial.selenic.com/ for detailed installation +See https://mercurial-scm.org/ for detailed installation instructions, platform-specific notes, and Mercurial user information. diff -r d3712209921d -r b66e3ca0b90c contrib/Makefile.python --- a/contrib/Makefile.python Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/Makefile.python Tue Oct 20 15:59:10 2015 -0500 @@ -1,4 +1,4 @@ -PYTHONVER=2.7.9 +PYTHONVER=2.7.10 PYTHONNAME=python- PREFIX=$(HOME)/bin/prefix-$(PYTHONNAME)$(PYTHONVER) SYMLINKDIR=$(HOME)/bin @@ -17,9 +17,9 @@ @echo ' symlink - create a $$SYMLINKDIR/$(PYTHONNAME)$$PYTHONVER symlink' @echo @echo 'Example: create a temporary Python installation:' - @echo ' $$ make -f Makefile.python python PYTHONVER=2.4 PREFIX=/tmp/p24' - @echo ' $$ /tmp/p24/bin/python -V' - @echo ' Python 2.4' + @echo ' $$ make -f Makefile.python python PYTHONVER=${PYTHONVER} PREFIX=/tmp/p27' + @echo ' $$ /tmp/p27/bin/python -V' + @echo ' Python 2.7' @echo @echo 'Some external libraries are required for building Python: zlib bzip2 openssl.' @echo 'Make sure their development packages are installed systemwide.' @@ -27,7 +27,7 @@ # debian: apt-get install zlib1g-dev libbz2-dev libssl-dev @echo @echo 'To build a nice collection of interesting Python versions:' - @echo ' $$ for v in 2.{4{,.2,.3},5{,.6},6{,.1,.2,.9},7{,.8,.9}}; do' + @echo ' $$ for v in 2.{6{,.1,.2,.9},7{,.8,.10}}; do' @echo ' make -f Makefile.python symlink PYTHONVER=$$v || break; done' @echo 'To run a Mercurial test on all these Python versions:' @echo ' $$ for py in `cd ~/bin && ls $(PYTHONNAME)2.*`; do' @@ -38,7 +38,7 @@ export LC_ALL=C python: $(PREFIX)/bin/python docutils - printf 'import sys, zlib, bz2, docutils\nif sys.version_info >= (2,6):\n import ssl' | $(PREFIX)/bin/python + printf 'import sys, zlib, bz2, docutils, ssl' | $(PREFIX)/bin/python PYTHON_SRCDIR=Python-$(PYTHONVER) PYTHON_SRCFILE=$(PYTHON_SRCDIR).tgz @@ -49,15 +49,12 @@ tar xf $(PYTHON_SRCFILE) # Ubuntu disables SSLv2 the hard way, disable it on old Pythons too -sed -i 's,self.*SSLv2_method(),0;//\0,g' $(PYTHON_SRCDIR)/Modules/_ssl.c - # Find multiarch system libraries on Ubuntu with Python 2.4.x - # http://lipyrary.blogspot.dk/2011/05/how-to-compile-python-on-ubuntu-1104.html - -sed -i "s|lib_dirs = .* \[|\0'/usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH`',|g" $(PYTHON_SRCDIR)/setup.py # Find multiarch system libraries on Ubuntu and disable fortify error when setting argv LDFLAGS="-L/usr/lib/`dpkg-architecture -qDEB_HOST_MULTIARCH`"; \ BASECFLAGS=-U_FORTIFY_SOURCE; \ export LDFLAGS BASECFLAGS; \ cd $(PYTHON_SRCDIR) && ./configure --prefix=$(PREFIX) && make all SVNVERSION=pwd && make install - printf 'import sys, zlib, bz2\nif sys.version_info >= (2,6):\n import ssl' | $(PREFIX)/bin/python + printf 'import sys, zlib, bz2, ssl' | $(PREFIX)/bin/python rm -rf $(PYTHON_SRCDIR) DOCUTILSVER=0.12 diff -r d3712209921d -r b66e3ca0b90c contrib/builddeb --- a/contrib/builddeb Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/builddeb Tue Oct 20 15:59:10 2015 -0500 @@ -7,13 +7,23 @@ . $(dirname $0)/packagelib.sh BUILD=1 -DEBBUILDDIR="$PWD/debbuild" +CLEANUP=1 +DEBVERSION=jessie while [ "$1" ]; do case "$1" in - --prepare ) + --release ) + shift + DEBVERSION="$1" + shift + ;; + --cleanup ) shift BUILD= ;; + --build ) + shift + CLEANUP= + ;; --debbuilddir ) shift DEBBUILDDIR="$1" @@ -26,10 +36,9 @@ esac done -set -u +trap "if [ '$CLEANUP' ] ; then rm -r '$PWD/debian' ; fi" EXIT -rm -rf $DEBBUILDDIR -mkdir -p $DEBBUILDDIR +set -u if [ ! -d .hg ]; then echo 'You are not inside a Mercurial repository!' 1>&2 @@ -38,25 +47,38 @@ gethgversion -cp -r $PWD/contrib/debian $DEBBUILDDIR/DEBIAN -chmod -R 0755 $DEBBUILDDIR/DEBIAN - -control=$DEBBUILDDIR/DEBIAN/control - -# This looks like sed -i, but sed -i behaves just differently enough -# between BSD and GNU sed that I gave up and did the dumb thing. -sed "s/__VERSION__/$version/" < $control > $control.tmp -mv $control.tmp $control +control=debian/control +changelog=debian/changelog if [ "$BUILD" ]; then - dpkg-deb --build $DEBBUILDDIR - mv $DEBBUILDDIR.deb $DEBBUILDDIR/mercurial-$version-$release.deb - if [ $? = 0 ]; then - echo - echo "Built packages for $version-$release:" - find $DEBBUILDDIR/ -type f -newer $control + if [ -d debian ] ; then + echo "Error! debian control directory already exists!" + exit 1 fi -else - echo "Prepared sources for $version-$release $control are in $DEBBUILDDIR - use like:" - echo "dpkg-deb --build $DEBBUILDDIR" + + cp -r $PWD/contrib/debian debian + chmod -R 0755 debian + + # This looks like sed -i, but sed -i behaves just differently enough + # between BSD and GNU sed that I gave up and did the dumb thing. + sed "s/__VERSION__/$version/" < $changelog > $changelog.tmp + date=$(date --rfc-2822) + sed "s/__DATE__/$date/" < $changelog.tmp > $changelog + rm $changelog.tmp + + debuild -us -uc -b + if [ $? != 0 ]; then + echo 'debuild failed!' + exit 1 + fi + fi +if [ "$CLEANUP" ] ; then + echo + OUTPUTDIR=${OUTPUTDIR:=packages/debian-$DEBVERSION} + find ../mercurial*.deb ../mercurial_*.build ../mercurial_*.changes \ + -type f -newer $control -print0 | \ + xargs -Inarf -0 mv narf "$OUTPUTDIR" + echo "Built packages for $version-$release:" + find "$OUTPUTDIR" -type f -newer $control -name '*.deb' +fi diff -r d3712209921d -r b66e3ca0b90c contrib/buildrpm --- a/contrib/buildrpm Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/buildrpm Tue Oct 20 15:59:10 2015 -0500 @@ -19,8 +19,8 @@ ;; --withpython | --with-python) shift - PYTHONVER=2.7.9 - PYTHONMD5=5eebcaa0030dc4061156d3429657fb83 + PYTHONVER=2.7.10 + PYTHONMD5=d7547558fd673bd9d38e2108c6b42521 ;; --rpmbuilddir ) shift @@ -56,6 +56,7 @@ RPMPYTHONVER=%{nil} fi +mkdir -p $RPMBUILDDIR/SOURCES $HG archive -t tgz $RPMBUILDDIR/SOURCES/mercurial-$version-$release.tar.gz if [ "$PYTHONVER" ]; then ( @@ -79,6 +80,7 @@ ) fi +mkdir -p $RPMBUILDDIR/SPECS rpmspec=$RPMBUILDDIR/SPECS/mercurial.spec sed -e "s,^Version:.*,Version: $version," \ diff -r d3712209921d -r b66e3ca0b90c contrib/check-code.py --- a/contrib/check-code.py Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/check-code.py Tue Oct 20 15:59:10 2015 -0500 @@ -123,7 +123,9 @@ (r'sed (-e )?\'(\d+|/[^/]*/)i(?!\\\n)', "put a backslash-escaped newline after sed 'i' command"), (r'^diff *-\w*u.*$\n(^ \$ |^$)', "prefix diff -u with cmp"), - (r'seq ', "don't use 'seq', use $TESTDIR/seq.py") + (r'seq ', "don't use 'seq', use $TESTDIR/seq.py"), + (r'\butil\.Abort\b', "directly use error.Abort"), + (r'\|&', "don't use |&, use 2>&1"), ], # warnings [ @@ -197,7 +199,6 @@ pypats = [ [ - (r'\([^)]*\*\w[^()]+\w+=', "can't pass varargs with keyword in Py2.5"), (r'^\s*def\s*\w+\s*\(.*,\s*\(', "tuple parameter unpacking not available in Python 3+"), (r'lambda\s*\(.*,.*\)', @@ -291,6 +292,9 @@ (r'os\.path\.join\(.*, *(""|\'\')\)', "use pathutil.normasprefix(path) instead of os.path.join(path, '')"), (r'\s0[0-7]+\b', 'legacy octal syntax; use "0o" prefix instead of "0"'), + # XXX only catch mutable arguments on the first line of the definition + (r'def.*[( ]\w+=\{\}', "don't use mutable default arguments"), + (r'\butil\.Abort\b', "directly use error.Abort"), ], # warnings [ diff -r d3712209921d -r b66e3ca0b90c contrib/check-commit --- a/contrib/check-commit Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/check-commit Tue Oct 20 15:59:10 2015 -0500 @@ -13,7 +13,7 @@ # # $ BYPASS= hg commit # -# See also: http://mercurial.selenic.com/wiki/ContributingChanges +# See also: https://mercurial-scm.org/wiki/ContributingChanges import re, sys, os diff -r d3712209921d -r b66e3ca0b90c contrib/debian/cacerts.rc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/debian/cacerts.rc Tue Oct 20 15:59:10 2015 -0500 @@ -0,0 +1,5 @@ +# This config file points Mercurial at the system-wide certificate +# store from the ca-certificates package. + +[web] +cacerts = /etc/ssl/certs/ca-certificates.crt diff -r d3712209921d -r b66e3ca0b90c contrib/debian/changelog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/debian/changelog Tue Oct 20 15:59:10 2015 -0500 @@ -0,0 +1,5 @@ +mercurial (__VERSION__) unstable; urgency=medium + + * Automated build performed by upstream. + + -- Mercurial Devel __DATE__ diff -r d3712209921d -r b66e3ca0b90c contrib/debian/compat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/debian/compat Tue Oct 20 15:59:10 2015 -0500 @@ -0,0 +1,1 @@ +9 diff -r d3712209921d -r b66e3ca0b90c contrib/debian/control --- a/contrib/debian/control Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/debian/control Tue Oct 20 15:59:10 2015 -0500 @@ -1,9 +1,47 @@ -Package: mercurial -Version: __VERSION__ +Source: mercurial Section: vcs Priority: optional +Maintainer: Mercurial Developers +Build-Depends: + debhelper (>= 7), + dh-python, + python-all +Standards-Version: 3.9.4 +X-Python-Version: >= 2.6 + +Package: mercurial +Depends: + python, + ${shlibs:Depends}, + ${misc:Depends}, + ${python:Depends}, + mercurial-common (= ${source:Version}) +Architecture: any +Description: fast, easy to use, distributed revision control tool. + Mercurial is a fast, lightweight Source Control Management system designed + for efficient handling of very large distributed projects. + . + Its features include: + * O(1) delta-compressed file storage and retrieval scheme + * Complete cross-indexing of files and changesets for efficient exploration + of project history + * Robust SHA1-based integrity checking and append-only storage model + * Decentralized development model with arbitrary merging between trees + * Easy-to-use command-line interface + * Integrated stand-alone web interface + * Small Python codebase + +Package: mercurial-common Architecture: all -Depends: python -Conflicts: mercurial-common -Maintainer: Mercurial Developers -Description: Mercurial (probably nightly) package built by upstream. +Depends: + ${misc:Depends}, + ${python:Depends}, +Recommends: mercurial (= ${source:Version}), ca-certificates +Breaks: mercurial (<< ${source:Version}) +Replaces: mercurial (<< 2.6.3) +Description: easy-to-use, scalable distributed version control system (common files) + Mercurial is a fast, lightweight Source Control Management system designed + for efficient handling of very large distributed projects. + . + This package contains the architecture independent components of Mercurial, + and is generally useless without the mercurial package. diff -r d3712209921d -r b66e3ca0b90c contrib/debian/copyright --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/debian/copyright Tue Oct 20 15:59:10 2015 -0500 @@ -0,0 +1,27 @@ +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: mercurial +Source: http://www.selenic.com/mercurial/ + +Files: * +Copyright: 2005-2015, Matt Mackall and others. +License: GPL-2+ + This program is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later + version. + . + This program is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. See the GNU General Public License for more + details. + . + You should have received a copy of the GNU General Public + License along with this package; if not, write to the Free + Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301 USA + . + On Debian systems, the full text of the GNU General Public + License version 2 can be found in the file + `/usr/share/common-licenses/GPL-2'. diff -r d3712209921d -r b66e3ca0b90c contrib/debian/hgkpath.rc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/debian/hgkpath.rc Tue Oct 20 15:59:10 2015 -0500 @@ -0,0 +1,2 @@ +[hgk] +path = /usr/share/mercurial/hgk diff -r d3712209921d -r b66e3ca0b90c contrib/debian/rules --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/debian/rules Tue Oct 20 15:59:10 2015 -0500 @@ -0,0 +1,36 @@ +#!/usr/bin/make -f +# Uncomment this to turn on verbose mode. +# export DH_VERBOSE=1 + +CPUS=$(shell cat /proc/cpuinfo | grep -E ^processor | wc -l) + +%: + dh $@ --with python2 + +override_dh_auto_test: + http_proxy='' dh_auto_test -- TESTFLAGS="-j$(CPUS)" + +override_dh_python2: + dh_python2 + find debian/mercurial/usr/share -type d -empty -delete + +override_dh_install: + python$(PYVERS) setup.py install --root $(CURDIR)/debian/mercurial --install-layout=deb + # remove arch-independent python stuff + find $(CURDIR)/debian/mercurial/usr/lib \ + ! -name '*.so' ! -type d -delete , \ + -type d -empty -delete + python$(PYVERS) setup.py install --root $(CURDIR)/debian/mercurial-common --install-layout=deb + make install-doc PREFIX=$(CURDIR)/debian/mercurial-common/usr + # remove arch-dependent python stuff + find $(CURDIR)/debian/mercurial-common/usr/lib \ + -name '*.so' ! -type d -delete , \ + -type d -empty -delete + cp contrib/hg-ssh $(CURDIR)/debian/mercurial-common/usr/bin + mkdir -p $(CURDIR)/debian/mercurial-common/usr/share/mercurial + cp contrib/hgk $(CURDIR)/debian/mercurial-common/usr/share/mercurial + mkdir -p $(CURDIR)/debian/mercurial-common/etc/mercurial/hgrc.d/ + cp contrib/debian/*.rc $(CURDIR)/debian/mercurial-common/etc/mercurial/hgrc.d/ + mkdir -p $(CURDIR)/debian/mercurial-common/usr/share/bash-completion/completions + cp contrib/bash_completion $(CURDIR)/debian/mercurial-common/usr/share/bash-completion/completions/hg + rm $(CURDIR)/debian/mercurial-common/usr/bin/hg diff -r d3712209921d -r b66e3ca0b90c contrib/dockerdeb --- a/contrib/dockerdeb Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/dockerdeb Tue Oct 20 15:59:10 2015 -0500 @@ -8,32 +8,27 @@ checkdocker +DEBPLATFORM="$1" PLATFORM="debian-$1" shift # extra params are passed to build process +OUTPUTDIR=${OUTPUTDIR:=$ROOTDIR/packages/$PLATFORM} + initcontainer $PLATFORM -DEBBUILDDIR=$ROOTDIR/packages/$PLATFORM -contrib/builddeb --debbuilddir $DEBBUILDDIR/staged --prepare +# debuild only appears to be able to save built debs etc to .., so we +# have to share the .. of the current directory with the docker +# container and hope it's writable. Whee. +dn=$(basename $PWD) -DSHARED=/mnt/shared/ if [ $(uname) = "Darwin" ] ; then - $DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED -v $PWD:/mnt/hg $CONTAINER \ - sh -c "cd /mnt/hg && make clean && make local" + $DOCKER run -u $DBUILDUSER --rm -v $PWD/..:/mnt $CONTAINER \ + sh -c "cd /mnt/$dn && make clean && make local" fi -$DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED -v $PWD:/mnt/hg $CONTAINER \ - sh -c "cd /mnt/hg && make PREFIX=$DSHARED/staged/usr install" -$DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED $CONTAINER \ - dpkg-deb --build $DSHARED/staged +$DOCKER run -u $DBUILDUSER --rm -v $PWD/..:/mnt $CONTAINER \ + sh -c "cd /mnt/$dn && DEB_BUILD_OPTIONS='${DEB_BUILD_OPTIONS:=}' contrib/builddeb --build --release $DEBPLATFORM" +contrib/builddeb --cleanup --release $DEBPLATFORM if [ $(uname) = "Darwin" ] ; then - $DOCKER run -u $DBUILDUSER --rm -v $DEBBUILDDIR:$DSHARED -v $PWD:/mnt/hg $CONTAINER \ - sh -c "cd /mnt/hg && make clean" + $DOCKER run -u $DBUILDUSER --rm -v $PWD/..:/mnt $CONTAINER \ + sh -c "cd /mnt/$dn && make clean" fi - -gethgversion - -rm -r $DEBBUILDDIR/staged -mv $DEBBUILDDIR/staged.deb $DEBBUILDDIR/mercurial-$version-$release.deb - -echo -echo "Build complete - results can be found in $DEBBUILDDIR" diff -r d3712209921d -r b66e3ca0b90c contrib/editmerge --- a/contrib/editmerge Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/editmerge Tue Oct 20 15:59:10 2015 -0500 @@ -10,23 +10,23 @@ # editmerge.check=changed # editmerge.premerge=keep -FILE=$1 +FILE="$1" getlines() { - grep -n "<<<<<<" $FILE | cut -f1 -d: + grep -n "^<<<<<<" "$FILE" | cut -f1 -d: } -# editor preference loosely based on http://mercurial.selenic.com/wiki/editor +# editor preference loosely based on https://mercurial-scm.org/wiki/editor # hg showconfig is at the bottom though, since it's slow to run (0.15 seconds) -ED=$HGEDITOR +ED="$HGEDITOR" if [ "$ED" = "" ] ; then - ED=$VISUAL + ED="$VISUAL" fi if [ "$ED" = "" ] ; then - ED=$EDITOR + ED="$EDITOR" fi if [ "$ED" = "" ] ; then - ED=$(hg showconfig ui.editor) + ED="$(hg showconfig ui.editor)" fi if [ "$ED" = "" ] ; then echo "merge failed - unable to find editor" @@ -34,22 +34,22 @@ fi if [ "$ED" = "emacs" ] || [ "$ED" = "nano" ] || [ "$ED" = "vim" ] ; then - FIRSTLINE=$(getlines | head -n 1) + FIRSTLINE="$(getlines | head -n 1)" PREVIOUSLINE="" # open the editor to the first conflict until there are no more # or the user stops editing the file while [ ! "$FIRSTLINE" = "" ] && [ ! "$FIRSTLINE" = "$PREVIOUSLINE" ] ; do - $ED +$FIRSTLINE $FILE - PREVIOUSLINE=$FIRSTLINE - FIRSTLINE=$(getlines | head -n 1) + $ED "+$FIRSTLINE" "$FILE" + PREVIOUSLINE="$FIRSTLINE" + FIRSTLINE="$(getlines | head -n 1)" done else - $ED $FILE + $ED "$FILE" fi # get the line numbers of the remaining conflicts -CONFLICTS=$(getlines | sed ':a;N;$!ba;s/\n/, /g') +CONFLICTS="$(getlines | sed ':a;N;$!ba;s/\n/, /g')" if [ ! "$CONFLICTS" = "" ] ; then echo "merge failed - resolve the conflicts (line $CONFLICTS) then use 'hg resolve --mark'" exit 1 diff -r d3712209921d -r b66e3ca0b90c contrib/hgweb.wsgi --- a/contrib/hgweb.wsgi Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/hgweb.wsgi Tue Oct 20 15:59:10 2015 -0500 @@ -1,5 +1,5 @@ # An example WSGI for use with mod_wsgi, edit as necessary -# See http://mercurial.selenic.com/wiki/modwsgi for more information +# See https://mercurial-scm.org/wiki/modwsgi for more information # Path to repo or hgweb config to serve (see 'hg help hgweb') config = "/path/to/repo/or/config" diff -r d3712209921d -r b66e3ca0b90c contrib/import-checker.py --- a/contrib/import-checker.py Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/import-checker.py Tue Oct 20 15:59:10 2015 -0500 @@ -65,7 +65,7 @@ Mercurial specific) modules. This function assumes that module names not existing in - `localmods` are ones of Python standard libarary. + `localmods` are from the Python standard library. This function returns the function, which takes `name` argument, and returns `(absname, dottedpath, hassubmod)` tuple if `name` @@ -164,7 +164,7 @@ for m in ['msvcrt', '_winreg']: yield m # These get missed too - for m in 'ctypes', 'email': + for m in 'ctypes', 'email', 'multiprocessing': yield m yield 'builtins' # python3 only for m in 'fcntl', 'grp', 'pwd', 'termios': # Unix only @@ -200,8 +200,7 @@ for name in files: if name == '__init__.py': continue - if not (name.endswith('.py') or name.endswith('.so') - or name.endswith('.pyd')): + if not name.endswith(('.py', '.so', '.pyc', '.pyo', '.pyd')): continue full_path = os.path.join(top, name) rel_path = full_path[len(libpath) + 1:] diff -r d3712209921d -r b66e3ca0b90c contrib/macosx/Readme.html --- a/contrib/macosx/Readme.html Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/macosx/Readme.html Tue Oct 20 15:59:10 2015 -0500 @@ -25,7 +25,7 @@


Documentation


-

Visit the Mercurial web site and wiki

+

Visit the Mercurial web site and wiki


There's also a free book, Distributed revision control with Mercurial


diff -r d3712209921d -r b66e3ca0b90c contrib/macosx/Welcome.html --- a/contrib/macosx/Welcome.html Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/macosx/Welcome.html Tue Oct 20 15:59:10 2015 -0500 @@ -11,10 +11,10 @@ -

This is a prepackaged release of Mercurial for Mac OS X.

+

This is a prepackaged release of Mercurial for Mac OS X.



-Please be sure to read the latest release notes.

+Please be sure to read the latest release notes.

diff -r d3712209921d -r b66e3ca0b90c contrib/mercurial.spec --- a/contrib/mercurial.spec Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/mercurial.spec Tue Oct 20 15:59:10 2015 -0500 @@ -25,7 +25,7 @@ Release: 0 License: GPLv2+ Group: Development/Tools -URL: http://mercurial.selenic.com/ +URL: https://mercurial-scm.org/ Source0: %{name}-%{version}-%{release}.tar.gz %if "%{?withpython}" Source1: %{pythonname}.tgz diff -r d3712209921d -r b66e3ca0b90c contrib/perf.py --- a/contrib/perf.py Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/perf.py Tue Oct 20 15:59:10 2015 -0500 @@ -222,7 +222,7 @@ "a" in ds def d(): ds._dirty = True - ds.write() + ds.write(repo.currenttransaction()) timer(d) fm.end() diff -r d3712209921d -r b66e3ca0b90c contrib/plan9/README --- a/contrib/plan9/README Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/plan9/README Tue Oct 20 15:59:10 2015 -0500 @@ -35,5 +35,5 @@ A proto(2) file is included in this directory as an example of how a binary distribution could be packaged, ostensibly with contrib(1). -See http://mercurial.selenic.com/ for detailed installation +See https://mercurial-scm.org/ for detailed installation instructions, platform-specific notes, and Mercurial user information. diff -r d3712209921d -r b66e3ca0b90c contrib/revsetbenchmarks.py --- a/contrib/revsetbenchmarks.py Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/revsetbenchmarks.py Tue Oct 20 15:59:10 2015 -0500 @@ -33,6 +33,8 @@ """update the repo to a revision""" try: check_call(['hg', 'update', '--quiet', '--check', str(rev)]) + check_output(['make', 'local'], + stderr=None) # suppress output except for error/warning except CalledProcessError as exc: print >> sys.stderr, 'update to revision %s failed, aborting' % rev sys.exit(exc.returncode) @@ -59,7 +61,7 @@ except CalledProcessError as exc: print >> sys.stderr, 'abort: cannot run revset benchmark: %s' % exc.cmd if exc.output is None: - print >> sys.stderr, '(no ouput)' + print >> sys.stderr, '(no output)' else: print >> sys.stderr, exc.output return None @@ -112,7 +114,7 @@ def getfactor(main, other, field, sensitivity=0.05): """return the relative factor between values for 'field' in main and other - Return None if the factor is insignicant (less than + Return None if the factor is insignificant (less than variation).""" factor = 1 if main is not None: @@ -216,7 +218,7 @@ helptext="""This script will run multiple variants of provided revsets using different revisions in your mercurial repository. After the benchmark are run -summary output is provided. Use itto demonstrate speed improvements or pin +summary output is provided. Use it to demonstrate speed improvements or pin point regressions. Revsets to run are specified in a file (or from stdin), one revsets per line. Line starting with '#' will be ignored, allowing insertion of comments.""" diff -r d3712209921d -r b66e3ca0b90c contrib/showstack.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/showstack.py Tue Oct 20 15:59:10 2015 -0500 @@ -0,0 +1,17 @@ +# showstack.py - extension to dump a Python stack trace on signal +# +# binds to both SIGQUIT (Ctrl-\) and SIGINFO (Ctrl-T on BSDs) + +import sys, signal, traceback + +def sigshow(*args): + sys.stderr.write("\n") + traceback.print_stack(args[1], limit=10, file=sys.stderr) + sys.stderr.write("----\n") + +def extsetup(ui): + signal.signal(signal.SIGQUIT, sigshow) + try: + signal.signal(signal.SIGINFO, sigshow) + except AttributeError: + pass diff -r d3712209921d -r b66e3ca0b90c contrib/simplemerge --- a/contrib/simplemerge Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/simplemerge Tue Oct 20 15:59:10 2015 -0500 @@ -5,7 +5,7 @@ import sys from mercurial.i18n import _ -from mercurial import simplemerge, fancyopts, util, ui +from mercurial import error, simplemerge, fancyopts, util, ui options = [('L', 'label', [], _('labels to use on conflict markers')), ('a', 'text', None, _('treat all files as text')), @@ -59,7 +59,7 @@ sys.stdout.write("%s: %s\n" % (sys.argv[0], e)) showhelp() sys.exit(1) -except util.Abort, e: +except error.Abort, e: sys.stderr.write("abort: %s\n" % e) sys.exit(255) except KeyboardInterrupt: diff -r d3712209921d -r b66e3ca0b90c contrib/synthrepo.py --- a/contrib/synthrepo.py Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/synthrepo.py Tue Oct 20 15:59:10 2015 -0500 @@ -37,7 +37,7 @@ ''' import bisect, collections, itertools, json, os, random, time, sys -from mercurial import cmdutil, context, patch, scmutil, util, hg +from mercurial import cmdutil, context, patch, scmutil, util, hg, error from mercurial.i18n import _ from mercurial.node import nullrev, nullid, short @@ -254,7 +254,7 @@ try: fp = hg.openpath(ui, descpath) except Exception as err: - raise util.Abort('%s: %s' % (descpath, err[0].strerror)) + raise error.Abort('%s: %s' % (descpath, err[0].strerror)) desc = json.load(fp) fp.close() @@ -286,7 +286,7 @@ try: fp = open(dictfile, 'rU') except IOError as err: - raise util.Abort('%s: %s' % (dictfile, err.strerror)) + raise error.Abort('%s: %s' % (dictfile, err.strerror)) words = fp.read().splitlines() fp.close() diff -r d3712209921d -r b66e3ca0b90c contrib/vagrant/Vagrantfile --- a/contrib/vagrant/Vagrantfile Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/vagrant/Vagrantfile Tue Oct 20 15:59:10 2015 -0500 @@ -1,9 +1,8 @@ # -*- mode: ruby -*- Vagrant.configure('2') do |config| - # Debian 7.4 32-bit i386 without configuration management software - config.vm.box = "puppetlabs/debian-7.4-32-nocm" - #config.vm.box = "pnd/debian-wheezy32-basebox" + # Debian 8.1 x86_64 without configuration management software + config.vm.box = "debian/jessie64" config.vm.hostname = "tests" config.vm.define "tests" do |conf| diff -r d3712209921d -r b66e3ca0b90c contrib/vim/hgcommand.vim --- a/contrib/vim/hgcommand.vim Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/vim/hgcommand.vim Tue Oct 20 15:59:10 2015 -0500 @@ -1226,7 +1226,7 @@ Author: Mathieu Clabaut Credits: Bob Hiestand -Mercurial: http://mercurial.selenic.com/ +Mercurial: https://mercurial-scm.org/ Mercurial (noted Hg) is a fast, lightweight Source Control Management system designed for efficient handling of very large distributed projects. diff -r d3712209921d -r b66e3ca0b90c contrib/vim/patchreview.txt --- a/contrib/vim/patchreview.txt Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/vim/patchreview.txt Tue Oct 20 15:59:10 2015 -0500 @@ -30,7 +30,7 @@ software development projects. This plugin provides that missing functionality. -It also improves on |:diffpatch|'s behaviour of creating the patched files in +It also improves on |:diffpatch|'s behavior of creating the patched files in the same directory as original file which can lead to project workspace pollution. diff -r d3712209921d -r b66e3ca0b90c contrib/win32/ReadMe.html --- a/contrib/win32/ReadMe.html Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/win32/ReadMe.html Tue Oct 20 15:59:10 2015 -0500 @@ -49,7 +49,7 @@

For documentation, please visit the Mercurial web site. + href="https://mercurial-scm.org/">Mercurial web site. You can also download a free book, Mercurial: The Definitive Guide. @@ -100,7 +100,7 @@ By default, Mercurial will use the merge program defined by the HGMERGE environment variable, or uses the one defined in the mercurial.ini file. (see MergeProgram + href="https://mercurial-scm.org/wiki/MergeProgram">MergeProgram on the Mercurial Wiki for more information)

@@ -108,9 +108,9 @@

Before you report any problems, please consult the Mercurial web site + href="https://mercurial-scm.org/">Mercurial web site and see if your question is already in our list of Frequently + href="https://mercurial-scm.org/wiki/FAQ">Frequently Answered Questions (the "FAQ").

diff -r d3712209921d -r b66e3ca0b90c contrib/win32/mercurial.iss --- a/contrib/win32/mercurial.iss Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/win32/mercurial.iss Tue Oct 20 15:59:10 2015 -0500 @@ -36,9 +36,9 @@ LicenseFile=COPYING ShowLanguageDialog=yes AppPublisher=Matt Mackall and others -AppPublisherURL=http://mercurial.selenic.com/ -AppSupportURL=http://mercurial.selenic.com/ -AppUpdatesURL=http://mercurial.selenic.com/ +AppPublisherURL=https://mercurial-scm.org/ +AppSupportURL=https://mercurial-scm.org/ +AppUpdatesURL=https://mercurial-scm.org/ AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3} AppContact=mercurial@selenic.com DefaultDirName={pf}\Mercurial @@ -90,7 +90,7 @@ Source: COPYING; DestDir: {app}; DestName: Copying.txt [INI] -Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: http://mercurial.selenic.com/ +Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: https://mercurial-scm.org/ Filename: {app}\default.d\editor.rc; Section: ui; Key: editor; String: notepad [UninstallDelete] diff -r d3712209921d -r b66e3ca0b90c contrib/win32/postinstall.txt --- a/contrib/win32/postinstall.txt Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/win32/postinstall.txt Tue Oct 20 15:59:10 2015 -0500 @@ -6,4 +6,4 @@ Also check the release notes at: - http://mercurial.selenic.com/wiki/WhatsNew + https://mercurial-scm.org/wiki/WhatsNew diff -r d3712209921d -r b66e3ca0b90c contrib/win32/win32-build.txt --- a/contrib/win32/win32-build.txt Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/win32/win32-build.txt Tue Oct 20 15:59:10 2015 -0500 @@ -78,9 +78,6 @@ Copy add_path.exe and cacert.pem files into the dist directory that just got created. -If you are using Python up to version 2.5.4, copy mfc71.dll into the dist -directory that just got created. - If you are using Python 2.6 or later, or if you are using MSVC 2008 to compile mercurial, you must include the C runtime libraries in the installer. To do so, install the Visual C++ 2008 redistributable package. Then in your windows\winsxs diff -r d3712209921d -r b66e3ca0b90c contrib/wix/mercurial.wxs --- a/contrib/wix/mercurial.wxs Thu Oct 08 23:24:38 2015 +0900 +++ b/contrib/wix/mercurial.wxs Tue Oct 20 15:59:10 2015 -0500 @@ -44,10 +44,10 @@ mercurial@selenic.com - http://mercurial.selenic.com/wiki/ - http://mercurial.selenic.com/about/ - http://mercurial.selenic.com/downloads/ - http://mercurial.selenic.com/wiki/Support + https://mercurial-scm.org/wiki/ + https://mercurial-scm.org/about/ + https://mercurial-scm.org/downloads/ + https://mercurial-scm.org/wiki/Support hgIcon.ico diff -r d3712209921d -r b66e3ca0b90c doc/check-seclevel.py --- a/doc/check-seclevel.py Thu Oct 08 23:24:38 2015 +0900 +++ b/doc/check-seclevel.py Tue Oct 20 15:59:10 2015 -0500 @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# checkseclevel - checking section title levels in each online help documents +# checkseclevel - checking section title levels in each online help document import sys, os import optparse @@ -14,15 +14,7 @@ from mercurial.help import helptable from mercurial import extensions from mercurial import minirst - -_verbose = False - -def verbose(msg): - if _verbose: - print msg - -def error(msg): - sys.stderr.write('%s\n' % msg) +from mercurial import ui as uimod level2mark = ['"', '=', '-', '.', '#'] reservedmarks = ['"'] @@ -37,12 +29,12 @@ initlevel_ext = 1 initlevel_ext_cmd = 3 -def showavailables(initlevel): - error(' available marks and order of them in this help: %s' % - (', '.join(['%r' % (m * 4) for m in level2mark[initlevel + 1:]]))) +def showavailables(ui, initlevel): + ui.warn((' available marks and order of them in this help: %s\n') % + (', '.join(['%r' % (m * 4) for m in level2mark[initlevel + 1:]]))) -def checkseclevel(doc, name, initlevel): - verbose('checking "%s"' % name) +def checkseclevel(ui, doc, name, initlevel): + ui.note(('checking "%s"\n') % name) blocks, pruned = minirst.parse(doc, 0, ['verbose']) errorcnt = 0 curlevel = initlevel @@ -52,66 +44,66 @@ mark = block['underline'] title = block['lines'][0] if (mark not in mark2level) or (mark2level[mark] <= initlevel): - error('invalid section mark %r for "%s" of %s' % - (mark * 4, title, name)) - showavailables(initlevel) + ui.warn(('invalid section mark %r for "%s" of %s\n') % + (mark * 4, title, name)) + showavailables(ui, initlevel) errorcnt += 1 continue nextlevel = mark2level[mark] if curlevel < nextlevel and curlevel + 1 != nextlevel: - error('gap of section level at "%s" of %s' % - (title, name)) - showavailables(initlevel) + ui.warn(('gap of section level at "%s" of %s\n') % + (title, name)) + showavailables(ui, initlevel) errorcnt += 1 continue - verbose('appropriate section level for "%s %s"' % + ui.note(('appropriate section level for "%s %s"\n') % (mark * (nextlevel * 2), title)) curlevel = nextlevel return errorcnt -def checkcmdtable(cmdtable, namefmt, initlevel): +def checkcmdtable(ui, cmdtable, namefmt, initlevel): errorcnt = 0 for k, entry in cmdtable.items(): name = k.split("|")[0].lstrip("^") if not entry[0].__doc__: - verbose('skip checking %s: no help document' % + ui.note(('skip checking %s: no help document\n') % (namefmt % name)) continue - errorcnt += checkseclevel(entry[0].__doc__, + errorcnt += checkseclevel(ui, entry[0].__doc__, namefmt % name, initlevel) return errorcnt -def checkhghelps(): +def checkhghelps(ui): errorcnt = 0 for names, sec, doc in helptable: if callable(doc): - doc = doc() - errorcnt += checkseclevel(doc, + doc = doc(ui) + errorcnt += checkseclevel(ui, doc, '%s help topic' % names[0], initlevel_topic) - errorcnt += checkcmdtable(table, '%s command', initlevel_cmd) + errorcnt += checkcmdtable(ui, table, '%s command', initlevel_cmd) for name in sorted(extensions.enabled().keys() + extensions.disabled().keys()): mod = extensions.load(None, name, None) if not mod.__doc__: - verbose('skip checking %s extension: no help document' % name) + ui.note(('skip checking %s extension: no help document\n') % name) continue - errorcnt += checkseclevel(mod.__doc__, + errorcnt += checkseclevel(ui, mod.__doc__, '%s extension' % name, initlevel_ext) cmdtable = getattr(mod, 'cmdtable', None) if cmdtable: - errorcnt += checkcmdtable(cmdtable, + errorcnt += checkcmdtable(ui, cmdtable, '%s command of ' + name + ' extension', initlevel_ext_cmd) return errorcnt -def checkfile(filename, initlevel): +def checkfile(ui, filename, initlevel): if filename == '-': filename = 'stdin' doc = sys.stdin.read() @@ -122,11 +114,11 @@ finally: fp.close() - verbose('checking input from %s with initlevel %d' % + ui.note(('checking input from %s with initlevel %d\n') % (filename, initlevel)) - return checkseclevel(doc, 'input from %s' % filename, initlevel) + return checkseclevel(ui, doc, 'input from %s' % filename, initlevel) -if __name__ == "__main__": +def main(): optparser = optparse.OptionParser("""%prog [options] This checks all help documents of Mercurial (topics, commands, @@ -159,11 +151,15 @@ (options, args) = optparser.parse_args() - _verbose = options.verbose + ui = uimod.ui() + ui.setconfig('ui', 'verbose', options.verbose, '--verbose') if options.file: - if checkfile(options.file, options.initlevel): + if checkfile(ui, options.file, options.initlevel): sys.exit(1) else: - if checkhghelps(): + if checkhghelps(ui): sys.exit(1) + +if __name__ == "__main__": + main() diff -r d3712209921d -r b66e3ca0b90c doc/gendoc.py --- a/doc/gendoc.py Thu Oct 08 23:24:38 2015 +0900 +++ b/doc/gendoc.py Tue Oct 20 15:59:10 2015 -0500 @@ -14,6 +14,7 @@ from mercurial.i18n import gettext, _ from mercurial.help import helptable, loaddoc from mercurial import extensions +from mercurial import ui as uimod def get_desc(docstr): if not docstr: @@ -137,7 +138,7 @@ if sectionfunc: ui.write(sectionfunc(sec)) if callable(doc): - doc = doc() + doc = doc(ui) ui.write(doc) ui.write("\n") @@ -198,7 +199,8 @@ if len(sys.argv) > 1: doc = sys.argv[1] + ui = uimod.ui() if doc == 'hg.1.gendoc': - showdoc(sys.stdout) + showdoc(ui) else: - showtopic(sys.stdout, sys.argv[1]) + showtopic(ui, sys.argv[1]) diff -r d3712209921d -r b66e3ca0b90c doc/hgmanpage.py --- a/doc/hgmanpage.py Thu Oct 08 23:24:38 2015 +0900 +++ b/doc/hgmanpage.py Tue Oct 20 15:59:10 2015 -0500 @@ -18,11 +18,11 @@ 7 miscellaneous 8 system administration -Man pages are written *troff*, a text file formatting system. +Man pages are written in *troff*, a text file formatting system. See http://www.tldp.org/HOWTO/Man-Page for a start. -Man pages have no subsection only parts. +Man pages have no subsections only parts. Standard parts NAME , @@ -317,7 +317,7 @@ self._cnt = 0 self._indent = 2 if style == 'arabic': - # indentation depends on number of childrens + # indentation depends on number of children # and start value. self._indent = len(str(len(node.children))) self._indent += len(str(self._cnt)) + 1 @@ -427,7 +427,7 @@ pass def visit_block_quote(self, node): - # BUG/HACK: indent always uses the _last_ indention, + # BUG/HACK: indent always uses the _last_ indentation, # thus we need two of them. self.indent(BLOCKQOUTE_INDENT) self.indent(0) diff -r d3712209921d -r b66e3ca0b90c doc/style.css --- a/doc/style.css Thu Oct 08 23:24:38 2015 +0900 +++ b/doc/style.css Tue Oct 20 15:59:10 2015 -0500 @@ -1,8 +1,8 @@ /* - * Styles for man pages, which match with http://mercurial.selenic.com/ + * Styles for man pages, which match with https://mercurial-scm.org/ * * Color scheme & layout are borrowed from - * http://mercurial.selenic.com/css/styles.css + * https://mercurial-scm.org/css/styles.css * * Some styles are from html4css1.css from Docutils, which is in the * public domain. diff -r d3712209921d -r b66e3ca0b90c hgeditor --- a/hgeditor Thu Oct 08 23:24:38 2015 +0900 +++ b/hgeditor Tue Oct 20 15:59:10 2015 -0500 @@ -1,7 +1,7 @@ #!/bin/sh # # This is an example of using HGEDITOR to create of diff to review the -# changes while commiting. +# changes while committing. # If you want to pass your favourite editor some other parameters # only for Mercurial, modify this: diff -r d3712209921d -r b66e3ca0b90c hgext/acl.py --- a/hgext/acl.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/acl.py Tue Oct 20 15:59:10 2015 -0500 @@ -192,7 +192,7 @@ ''' from mercurial.i18n import _ -from mercurial import util, match +from mercurial import util, match, error import getpass, urllib # Note for extension authors: ONLY specify testedwith = 'internal' for @@ -213,7 +213,7 @@ try: return util.groupmembers(group) except KeyError: - raise util.Abort(_("group '%s' is undefined") % group) + raise error.Abort(_("group '%s' is undefined") % group) def _usermatch(ui, user, usersorgroups): @@ -268,7 +268,7 @@ def hook(ui, repo, hooktype, node=None, source=None, **kwargs): if hooktype not in ['pretxnchangegroup', 'pretxncommit']: - raise util.Abort(_('config error - hook type "%s" cannot stop ' + raise error.Abort(_('config error - hook type "%s" cannot stop ' 'incoming changesets nor commits') % hooktype) if (hooktype == 'pretxnchangegroup' and source not in ui.config('acl', 'sources', 'serve').split()): @@ -301,11 +301,11 @@ ctx = repo[rev] branch = ctx.branch() if denybranches and denybranches(branch): - raise util.Abort(_('acl: user "%s" denied on branch "%s"' + raise error.Abort(_('acl: user "%s" denied on branch "%s"' ' (changeset "%s")') % (user, branch, ctx)) if allowbranches and not allowbranches(branch): - raise util.Abort(_('acl: user "%s" not allowed on branch "%s"' + raise error.Abort(_('acl: user "%s" not allowed on branch "%s"' ' (changeset "%s")') % (user, branch, ctx)) ui.debug('acl: branch access granted: "%s" on branch "%s"\n' @@ -313,9 +313,9 @@ for f in ctx.files(): if deny and deny(f): - raise util.Abort(_('acl: user "%s" denied on "%s"' + raise error.Abort(_('acl: user "%s" denied on "%s"' ' (changeset "%s")') % (user, f, ctx)) if allow and not allow(f): - raise util.Abort(_('acl: user "%s" not allowed on "%s"' + raise error.Abort(_('acl: user "%s" not allowed on "%s"' ' (changeset "%s")') % (user, f, ctx)) ui.debug('acl: path access granted: "%s"\n' % ctx) diff -r d3712209921d -r b66e3ca0b90c hgext/blackbox.py --- a/hgext/blackbox.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/blackbox.py Tue Oct 20 15:59:10 2015 -0500 @@ -107,9 +107,11 @@ if blackbox: date = util.datestr(None, '%Y/%m/%d %H:%M:%S') user = util.getuser() + pid = str(os.getpid()) formattedmsg = msg[0] % msg[1:] try: - blackbox.write('%s %s> %s' % (date, user, formattedmsg)) + blackbox.write('%s %s (%s)> %s' % + (date, user, pid, formattedmsg)) except IOError as err: self.debug('warning: cannot write to blackbox.log: %s\n' % err.strerror) diff -r d3712209921d -r b66e3ca0b90c hgext/bugzilla.py --- a/hgext/bugzilla.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/bugzilla.py Tue Oct 20 15:59:10 2015 -0500 @@ -279,7 +279,7 @@ from mercurial.i18n import _ from mercurial.node import short -from mercurial import cmdutil, mail, util +from mercurial import cmdutil, mail, util, error import re, time, urlparse, xmlrpclib # Note for extension authors: ONLY specify testedwith = 'internal' for @@ -358,7 +358,7 @@ import MySQLdb as mysql bzmysql._MySQLdb = mysql except ImportError as err: - raise util.Abort(_('python mysql support not available: %s') % err) + raise error.Abort(_('python mysql support not available: %s') % err) bzaccess.__init__(self, ui) @@ -392,7 +392,7 @@ self.run('select fieldid from fielddefs where name = "longdesc"') ids = self.cursor.fetchall() if len(ids) != 1: - raise util.Abort(_('unknown database schema')) + raise error.Abort(_('unknown database schema')) return ids[0][0] def filter_real_bug_ids(self, bugs): @@ -437,7 +437,7 @@ ret = fp.close() if ret: self.ui.warn(out) - raise util.Abort(_('bugzilla notify command %s') % + raise error.Abort(_('bugzilla notify command %s') % util.explainexit(ret)[0]) self.ui.status(_('done\n')) @@ -470,12 +470,12 @@ try: defaultuser = self.ui.config('bugzilla', 'bzuser') if not defaultuser: - raise util.Abort(_('cannot find bugzilla user id for %s') % + raise error.Abort(_('cannot find bugzilla user id for %s') % user) userid = self.get_user_id(defaultuser) user = defaultuser except KeyError: - raise util.Abort(_('cannot find bugzilla user id for %s or %s') + raise error.Abort(_('cannot find bugzilla user id for %s or %s') % (user, defaultuser)) return (user, userid) @@ -517,7 +517,7 @@ self.run('select id from fielddefs where name = "longdesc"') ids = self.cursor.fetchall() if len(ids) != 1: - raise util.Abort(_('unknown database schema')) + raise error.Abort(_('unknown database schema')) return ids[0][0] # Bugzilla via XMLRPC interface. @@ -705,7 +705,7 @@ self.bzemail = self.ui.config('bugzilla', 'bzemail') if not self.bzemail: - raise util.Abort(_("configuration 'bzemail' missing")) + raise error.Abort(_("configuration 'bzemail' missing")) mail.validateconfig(self.ui) def makecommandline(self, fieldname, value): @@ -735,8 +735,8 @@ matches = self.bzproxy.User.get({'match': [user], 'token': self.bztoken}) if not matches['users']: - raise util.Abort(_("default bugzilla user %s email not found") % - user) + raise error.Abort(_("default bugzilla user %s email not found") + % user) user = matches['users'][0]['email'] commands.append(self.makecommandline("id", bugid)) @@ -789,7 +789,7 @@ try: bzclass = bugzilla._versions[bzversion] except KeyError: - raise util.Abort(_('bugzilla version %s not supported') % + raise error.Abort(_('bugzilla version %s not supported') % bzversion) self.bzdriver = bzclass(self.ui) @@ -900,7 +900,7 @@ bugzilla bug id. only add a comment once per bug, so same change seen multiple times does not fill bug with duplicate data.''' if node is None: - raise util.Abort(_('hook type %s does not pass a changeset id') % + raise error.Abort(_('hook type %s does not pass a changeset id') % hooktype) try: bz = bugzilla(ui, repo) @@ -911,4 +911,4 @@ bz.update(bug, bugs[bug], ctx) bz.notify(bugs, util.email(ctx.user())) except Exception as e: - raise util.Abort(_('Bugzilla error: %s') % e) + raise error.Abort(_('Bugzilla error: %s') % e) diff -r d3712209921d -r b66e3ca0b90c hgext/censor.py --- a/hgext/censor.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/censor.py Tue Oct 20 15:59:10 2015 -0500 @@ -13,7 +13,7 @@ Typical uses for censor are due to security or legal requirements, including:: - * Passwords, private keys, crytographic material + * Passwords, private keys, cryptographic material * Licensed data/code/libraries for which the license has expired * Personally Identifiable Information or other private data @@ -43,47 +43,47 @@ _('-r REV [-t TEXT] [FILE]')) def censor(ui, repo, path, rev='', tombstone='', **opts): if not path: - raise util.Abort(_('must specify file path to censor')) + raise error.Abort(_('must specify file path to censor')) if not rev: - raise util.Abort(_('must specify revision to censor')) + raise error.Abort(_('must specify revision to censor')) wctx = repo[None] m = scmutil.match(wctx, (path,)) if m.anypats() or len(m.files()) != 1: - raise util.Abort(_('can only specify an explicit filename')) + raise error.Abort(_('can only specify an explicit filename')) path = m.files()[0] flog = repo.file(path) if not len(flog): - raise util.Abort(_('cannot censor file with no history')) + raise error.Abort(_('cannot censor file with no history')) rev = scmutil.revsingle(repo, rev, rev).rev() try: ctx = repo[rev] except KeyError: - raise util.Abort(_('invalid revision identifier %s') % rev) + raise error.Abort(_('invalid revision identifier %s') % rev) try: fctx = ctx.filectx(path) except error.LookupError: - raise util.Abort(_('file does not exist at revision %s') % rev) + raise error.Abort(_('file does not exist at revision %s') % rev) fnode = fctx.filenode() headctxs = [repo[c] for c in repo.heads()] heads = [c for c in headctxs if path in c and c.filenode(path) == fnode] if heads: headlist = ', '.join([short(c.node()) for c in heads]) - raise util.Abort(_('cannot censor file in heads (%s)') % headlist, + raise error.Abort(_('cannot censor file in heads (%s)') % headlist, hint=_('clean/delete and commit first')) wp = wctx.parents() if ctx.node() in [p.node() for p in wp]: - raise util.Abort(_('cannot censor working directory'), + raise error.Abort(_('cannot censor working directory'), hint=_('clean/delete/update first')) flogv = flog.version & 0xFFFF if flogv != revlog.REVLOGNG: - raise util.Abort( + raise error.Abort( _('censor does not support revlog version %d') % (flogv,)) tombstone = filelog.packmeta({"censored": tombstone}, "") @@ -91,7 +91,7 @@ crev = fctx.filerev() if len(tombstone) > flog.rawsize(crev): - raise util.Abort(_( + raise error.Abort(_( 'censor tombstone must be no longer than censored data')) # Using two files instead of one makes it easy to rewrite entry-by-entry diff -r d3712209921d -r b66e3ca0b90c hgext/churn.py --- a/hgext/churn.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/churn.py Tue Oct 20 15:59:10 2015 -0500 @@ -9,7 +9,7 @@ '''command to display statistics about repository history''' from mercurial.i18n import _ -from mercurial import patch, cmdutil, scmutil, util, commands +from mercurial import patch, cmdutil, scmutil, util, commands, error from mercurial import encoding import os import time, datetime @@ -27,7 +27,7 @@ t = cmdutil.changeset_templater(ui, repo, False, None, tmpl, None, False) except SyntaxError as inst: - raise util.Abort(inst.args[0]) + raise error.Abort(inst.args[0]) return t def changedlines(ui, repo, ctx1, ctx2, fns): diff -r d3712209921d -r b66e3ca0b90c hgext/clonebundles.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hgext/clonebundles.py Tue Oct 20 15:59:10 2015 -0500 @@ -0,0 +1,266 @@ +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. + +"""advertise pre-generated bundles to seed clones (experimental) + +"clonebundles" is a server-side extension used to advertise the existence +of pre-generated, externally hosted bundle files to clients that are +cloning so that cloning can be faster, more reliable, and require less +resources on the server. + +Cloning can be a CPU and I/O intensive operation on servers. Traditionally, +the server, in response to a client's request to clone, dynamically generates +a bundle containing the entire repository content and sends it to the client. +There is no caching on the server and the server will have to redundantly +generate the same outgoing bundle in response to each clone request. For +servers with large repositories or with high clone volume, the load from +clones can make scaling the server challenging and costly. + +This extension provides server operators the ability to offload potentially +expensive clone load to an external service. Here's how it works. + +1. A server operator establishes a mechanism for making bundle files available + on a hosting service where Mercurial clients can fetch them. +2. A manifest file listing available bundle URLs and some optional metadata + is added to the Mercurial repository on the server. +3. A client initiates a clone against a clone bundles aware server. +4. The client sees the server is advertising clone bundles and fetches the + manifest listing available bundles. +5. The client filters and sorts the available bundles based on what it + supports and prefers. +6. The client downloads and applies an available bundle from the + server-specified URL. +7. The client reconnects to the original server and performs the equivalent + of :hg:`pull` to retrieve all repository data not in the bundle. (The + repository could have been updated between when the bundle was created + and when the client started the clone.) + +Instead of the server generating full repository bundles for every clone +request, it generates full bundles once and they are subsequently reused to +bootstrap new clones. The server may still transfer data at clone time. +However, this is only data that has been added/changed since the bundle was +created. For large, established repositories, this can reduce server load for +clones to less than 1% of original. + +To work, this extension requires the following of server operators: + +* Generating bundle files of repository content (typically periodically, + such as once per day). +* A file server that clients have network access to and that Python knows + how to talk to through its normal URL handling facility (typically a + HTTP server). +* A process for keeping the bundles manifest in sync with available bundle + files. + +Strictly speaking, using a static file hosting server isn't required: a server +operator could use a dynamic service for retrieving bundle data. However, +static file hosting services are simple and scalable and should be sufficient +for most needs. + +Bundle files can be generated with the :hg:`bundle` comand. Typically +:hg:`bundle --all` is used to produce a bundle of the entire repository. + +:hg:`debugcreatestreamclonebundle` can be used to produce a special +*streaming clone bundle*. These are bundle files that are extremely efficient +to produce and consume (read: fast). However, they are larger than +traditional bundle formats and require that clients support the exact set +of repository data store formats in use by the repository that created them. +Typically, a newer server can serve data that is compatible with older clients. +However, *streaming clone bundles* don't have this guarantee. **Server +operators need to be aware that newer versions of Mercurial may produce +streaming clone bundles incompatible with older Mercurial versions.** + +The list of requirements printed by :hg:`debugcreatestreamclonebundle` should +be specified in the ``requirements`` parameter of the *bundle specification +string* for the ``BUNDLESPEC`` manifest property described below. e.g. +``BUNDLESPEC=none-packed1;requirements%3Drevlogv1``. + +A server operator is responsible for creating a ``.hg/clonebundles.manifest`` +file containing the list of available bundle files suitable for seeding +clones. If this file does not exist, the repository will not advertise the +existence of clone bundles when clients connect. + +The manifest file contains a newline (\n) delimited list of entries. + +Each line in this file defines an available bundle. Lines have the format: + + [=[ =]] + +That is, a URL followed by an optional, space-delimited list of key=value +pairs describing additional properties of this bundle. Both keys and values +are URI encoded. + +Keys in UPPERCASE are reserved for use by Mercurial and are defined below. +All non-uppercase keys can be used by site installations. An example use +for custom properties is to use the *datacenter* attribute to define which +data center a file is hosted in. Clients could then prefer a server in the +data center closest to them. + +The following reserved keys are currently defined: + +BUNDLESPEC + A "bundle specification" string that describes the type of the bundle. + + These are string values that are accepted by the "--type" argument of + :hg:`bundle`. + + The values are parsed in strict mode, which means they must be of the + "-" form. See + mercurial.exchange.parsebundlespec() for more details. + + Clients will automatically filter out specifications that are unknown or + unsupported so they won't attempt to download something that likely won't + apply. + + The actual value doesn't impact client behavior beyond filtering: + clients will still sniff the bundle type from the header of downloaded + files. + + **Use of this key is highly recommended**, as it allows clients to + easily skip unsupported bundles. + +REQUIRESNI + Whether Server Name Indication (SNI) is required to connect to the URL. + SNI allows servers to use multiple certificates on the same IP. It is + somewhat common in CDNs and other hosting providers. Older Python + versions do not support SNI. Defining this attribute enables clients + with older Python versions to filter this entry without experiencing + an opaque SSL failure at connection time. + + If this is defined, it is important to advertise a non-SNI fallback + URL or clients running old Python releases may not be able to clone + with the clonebundles facility. + + Value should be "true". + +Manifests can contain multiple entries. Assuming metadata is defined, clients +will filter entries from the manifest that they don't support. The remaining +entries are optionally sorted by client preferences +(``experimental.clonebundleprefers`` config option). The client then attempts +to fetch the bundle at the first URL in the remaining list. + +**Errors when downloading a bundle will fail the entire clone operation: +clients do not automatically fall back to a traditional clone.** The reason +for this is that if a server is using clone bundles, it is probably doing so +because the feature is necessary to help it scale. In other words, there +is an assumption that clone load will be offloaded to another service and +that the Mercurial server isn't responsible for serving this clone load. +If that other service experiences issues and clients start mass falling back to +the original Mercurial server, the added clone load could overwhelm the server +due to unexpected load and effectively take it offline. Not having clients +automatically fall back to cloning from the original server mitigates this +scenario. + +Because there is no automatic Mercurial server fallback on failure of the +bundle hosting service, it is important for server operators to view the bundle +hosting service as an extension of the Mercurial server in terms of +availability and service level agreements: if the bundle hosting service goes +down, so does the ability for clients to clone. Note: clients will see a +message informing them how to bypass the clone bundles facility when a failure +occurs. So server operators should prepare for some people to follow these +instructions when a failure occurs, thus driving more load to the original +Mercurial server when the bundle hosting service fails. + +The following config options influence the behavior of the clone bundles +feature: + +ui.clonebundleadvertise + Whether the server advertises the existence of the clone bundles feature + to compatible clients that aren't using it. + + When this is enabled (the default), a server will send a message to + compatible clients performing a traditional clone informing them of the + available clone bundles feature. Compatible clients are those that support + bundle2 and are advertising support for the clone bundles feature. + +ui.clonebundlefallback + Whether to automatically fall back to a traditional clone in case of + clone bundles failure. Defaults to false for reasons described above. + +experimental.clonebundles + Whether the clone bundles feature is enabled on clients. Defaults to true. + +experimental.clonebundleprefers + List of "key=value" properties the client prefers in bundles. Downloaded + bundle manifests will be sorted by the preferences in this list. e.g. + the value "BUNDLESPEC=gzip-v1, BUNDLESPEC=bzip2=v1" will prefer a gzipped + version 1 bundle type then bzip2 version 1 bundle type. + + If not defined, the order in the manifest will be used and the first + available bundle will be downloaded. +""" + +from mercurial.i18n import _ +from mercurial.node import nullid +from mercurial import ( + exchange, + extensions, + wireproto, +) + +testedwith = 'internal' + +def capabilities(orig, repo, proto): + caps = orig(repo, proto) + + # Only advertise if a manifest exists. This does add some I/O to requests. + # But this should be cheaper than a wasted network round trip due to + # missing file. + if repo.opener.exists('clonebundles.manifest'): + caps.append('clonebundles') + + return caps + +@wireproto.wireprotocommand('clonebundles', '') +def bundles(repo, proto): + """Server command for returning info for available bundles to seed clones. + + Clients will parse this response and determine what bundle to fetch. + + Other extensions may wrap this command to filter or dynamically emit + data depending on the request. e.g. you could advertise URLs for + the closest data center given the client's IP address. + """ + return repo.opener.tryread('clonebundles.manifest') + +@exchange.getbundle2partsgenerator('clonebundlesadvertise', 0) +def advertiseclonebundlespart(bundler, repo, source, bundlecaps=None, + b2caps=None, heads=None, common=None, + cbattempted=None, **kwargs): + """Inserts an output part to advertise clone bundles availability.""" + # Allow server operators to disable this behavior. + # # experimental config: ui.clonebundleadvertise + if not repo.ui.configbool('ui', 'clonebundleadvertise', True): + return + + # Only advertise if a manifest is present. + if not repo.opener.exists('clonebundles.manifest'): + return + + # And when changegroup data is requested. + if not kwargs.get('cg', True): + return + + # And when the client supports clone bundles. + if cbattempted is None: + return + + # And when the client didn't attempt a clone bundle as part of this pull. + if cbattempted: + return + + # And when a full clone is requested. + # Note: client should not send "cbattempted" for regular pulls. This check + # is defense in depth. + if common and common != [nullid]: + return + + msg = _('this server supports the experimental "clone bundles" feature ' + 'that should enable faster and more reliable cloning\n' + 'help test it by setting the "experimental.clonebundles" config ' + 'flag to "true"') + + bundler.newpart('output', data=msg) + +def extsetup(ui): + extensions.wrapfunction(wireproto, '_capabilities', capabilities) diff -r d3712209921d -r b66e3ca0b90c hgext/convert/__init__.py --- a/hgext/convert/__init__.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/__init__.py Tue Oct 20 15:59:10 2015 -0500 @@ -25,7 +25,7 @@ @command('convert', [('', 'authors', '', - _('username mapping filename (DEPRECATED, use --authormap instead)'), + _('username mapping filename (DEPRECATED) (use --authormap instead)'), _('FILE')), ('s', 'source-type', '', _('source repository type'), _('TYPE')), ('d', 'dest-type', '', _('destination repository type'), _('TYPE')), @@ -316,6 +316,9 @@ ``convert.git.remoteprefix`` as a prefix followed by a /. The default is 'remote'. + :convert.git.skipsubmodules: does not convert root level .gitmodules files + or files with 160000 mode indicating a submodule. Default is False. + Perforce Source ############### diff -r d3712209921d -r b66e3ca0b90c hgext/convert/bzr.py --- a/hgext/convert/bzr.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/bzr.py Tue Oct 20 15:59:10 2015 -0500 @@ -9,7 +9,7 @@ # it cannot access 'bar' repositories, but they were never used very much import os -from mercurial import demandimport +from mercurial import demandimport, error # these do not work with demandimport, blacklist demandimport.ignore.extend([ 'bzrlib.transactions', @@ -18,7 +18,7 @@ ]) from mercurial.i18n import _ -from mercurial import util +from mercurial import error from common import NoRepo, commit, converter_source try: @@ -108,7 +108,8 @@ pass revid = info.rev_id if revid is None: - raise util.Abort(_('%s is not a valid revision') % self.revs[0]) + raise error.Abort(_('%s is not a valid revision') + % self.revs[0]) heads = [revid] # Empty repositories return 'null:', which cannot be retrieved heads = [h for h in heads if h != 'null:'] @@ -127,7 +128,7 @@ if kind == 'symlink': target = revtree.get_symlink_target(fileid) if target is None: - raise util.Abort(_('%s.%s symlink has no target') + raise error.Abort(_('%s.%s symlink has no target') % (name, rev)) return target, mode else: @@ -136,7 +137,7 @@ def getchanges(self, version, full): if full: - raise util.Abort(_("convert from cvs do not support --full")) + raise error.Abort(_("convert from cvs does not support --full")) self._modecache = {} self._revtree = self.sourcerepo.revision_tree(version) # get the parentids from the cache diff -r d3712209921d -r b66e3ca0b90c hgext/convert/common.py --- a/hgext/convert/common.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/common.py Tue Oct 20 15:59:10 2015 -0500 @@ -7,7 +7,7 @@ import base64, errno, subprocess, os, datetime, re import cPickle as pickle -from mercurial import phases, util +from mercurial import phases, util, error from mercurial.i18n import _ propertycache = util.propertycache @@ -32,7 +32,7 @@ name = name or exe if not util.findexe(exe): if abort: - exc = util.Abort + exc = error.Abort else: exc = MissingTool raise exc(_('cannot find required "%s" tool') % name) @@ -73,7 +73,7 @@ such format for their revision numbering """ if not re.match(r'[0-9a-fA-F]{40,40}$', revstr): - raise util.Abort(_('%s entry %s is not a valid revision' + raise error.Abort(_('%s entry %s is not a valid revision' ' identifier') % (mapname, revstr)) def before(self): @@ -82,6 +82,13 @@ def after(self): pass + def targetfilebelongstosource(self, targetfilename): + """Returns true if the given targetfile belongs to the source repo. This + is useful when only a subdirectory of the target belongs to the source + repo.""" + # For normal full repo converts, this is always True. + return True + def setrevmap(self, revmap): """set the map of already-converted revisions""" pass @@ -362,7 +369,7 @@ self.ui.warn(_('%s error:\n') % self.command) self.ui.warn(output) msg = util.explainexit(status)[0] - raise util.Abort('%s %s' % (self.command, msg)) + raise error.Abort('%s %s' % (self.command, msg)) def run0(self, cmd, *args, **kwargs): output, status = self.run(cmd, *args, **kwargs) @@ -439,7 +446,7 @@ try: key, value = line.rsplit(' ', 1) except ValueError: - raise util.Abort( + raise error.Abort( _('syntax error in %s(%d): key/value pair expected') % (self.path, i + 1)) if key not in self: @@ -452,7 +459,7 @@ try: self.fp = open(self.path, 'a') except IOError as err: - raise util.Abort(_('could not open map file %r: %s') % + raise error.Abort(_('could not open map file %r: %s') % (self.path, err.strerror)) self.fp.write('%s %s\n' % (key, value)) self.fp.flush() diff -r d3712209921d -r b66e3ca0b90c hgext/convert/convcmd.py --- a/hgext/convert/convcmd.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/convcmd.py Tue Oct 20 15:59:10 2015 -0500 @@ -18,7 +18,7 @@ import filemap import os, shutil, shlex -from mercurial import hg, util, encoding +from mercurial import hg, util, encoding, error from mercurial.i18n import _ orig_encoding = 'ascii' @@ -82,7 +82,7 @@ def convertsource(ui, path, type, revs): exceptions = [] if type and type not in [s[0] for s in source_converters]: - raise util.Abort(_('%s: invalid source repository type') % type) + raise error.Abort(_('%s: invalid source repository type') % type) for name, source, sortmode in source_converters: try: if not type or name == type: @@ -92,11 +92,11 @@ if not ui.quiet: for inst in exceptions: ui.write("%s\n" % inst) - raise util.Abort(_('%s: missing or unsupported repository') % path) + raise error.Abort(_('%s: missing or unsupported repository') % path) def convertsink(ui, path, type): if type and type not in [s[0] for s in sink_converters]: - raise util.Abort(_('%s: invalid destination repository type') % type) + raise error.Abort(_('%s: invalid destination repository type') % type) for name, sink in sink_converters: try: if not type or name == type: @@ -104,8 +104,8 @@ except NoRepo as inst: ui.note(_("convert: %s\n") % inst) except MissingTool as inst: - raise util.Abort('%s\n' % inst) - raise util.Abort(_('%s: unknown repository type') % path) + raise error.Abort('%s\n' % inst) + raise error.Abort(_('%s: unknown repository type') % path) class progresssource(object): def __init__(self, ui, source, filecount): @@ -120,6 +120,9 @@ item=file, total=self.filecount) return self.source.getfile(file, rev) + def targetfilebelongstosource(self, targetfilename): + return self.source.targetfilebelongstosource(targetfilename) + def lookuprev(self, rev): return self.source.lookuprev(rev) @@ -182,7 +185,7 @@ line = list(lex) # check number of parents if not (2 <= len(line) <= 3): - raise util.Abort(_('syntax error in %s(%d): child parent1' + raise error.Abort(_('syntax error in %s(%d): child parent1' '[,parent2] expected') % (path, i + 1)) for part in line: self.source.checkrevformat(part) @@ -193,7 +196,7 @@ m[child] = p1 + p2 # if file does not exist or error reading, exit except IOError: - raise util.Abort(_('splicemap file not found or error reading %s:') + raise error.Abort(_('splicemap file not found or error reading %s:') % path) return m @@ -244,7 +247,7 @@ continue # Parent is not in dest and not being converted, not good if p not in parents: - raise util.Abort(_('unknown splice map parent: %s') % p) + raise error.Abort(_('unknown splice map parent: %s') % p) pc.append(p) parents[c] = pc @@ -340,7 +343,7 @@ elif sortmode == 'closesort': picknext = makeclosesorter() else: - raise util.Abort(_('unknown sort mode: %s') % sortmode) + raise error.Abort(_('unknown sort mode: %s') % sortmode) children, actives = mapchildren(parents) @@ -358,7 +361,7 @@ try: pendings[c].remove(n) except ValueError: - raise util.Abort(_('cycle detected between %s and %s') + raise error.Abort(_('cycle detected between %s and %s') % (recode(c), recode(n))) if not pendings[c]: # Parents are converted, node is eligible @@ -366,7 +369,7 @@ pendings[c] = None if len(s) != len(parents): - raise util.Abort(_("not all revisions were sorted")) + raise error.Abort(_("not all revisions were sorted")) return s @@ -437,7 +440,7 @@ try: parents = self.splicemap[rev] self.ui.status(_('spliced in %s as parents of %s\n') % - (parents, rev)) + (_(' and ').join(parents), rev)) parents = [self.map.get(p, p) for p in parents] except KeyError: parents = [b[0] for b in pbranches] @@ -553,16 +556,17 @@ sortmodes = ('branchsort', 'datesort', 'sourcesort', 'closesort') sortmode = [m for m in sortmodes if opts.get(m)] if len(sortmode) > 1: - raise util.Abort(_('more than one sort mode specified')) + raise error.Abort(_('more than one sort mode specified')) if sortmode: sortmode = sortmode[0] else: sortmode = defaultsort if sortmode == 'sourcesort' and not srcc.hasnativeorder(): - raise util.Abort(_('--sourcesort is not supported by this data source')) + raise error.Abort(_('--sourcesort is not supported by this data source') + ) if sortmode == 'closesort' and not srcc.hasnativeclose(): - raise util.Abort(_('--closesort is not supported by this data source')) + raise error.Abort(_('--closesort is not supported by this data source')) fmap = opts.get('filemap') if fmap: diff -r d3712209921d -r b66e3ca0b90c hgext/convert/cvs.py --- a/hgext/convert/cvs.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/cvs.py Tue Oct 20 15:59:10 2015 -0500 @@ -7,7 +7,7 @@ import os, re, socket, errno from cStringIO import StringIO -from mercurial import encoding, util +from mercurial import encoding, util, error from mercurial.i18n import _ from common import NoRepo, commit, converter_source, checktool @@ -43,14 +43,14 @@ maxrev = 0 if self.revs: if len(self.revs) > 1: - raise util.Abort(_('cvs source does not support specifying ' + raise error.Abort(_('cvs source does not support specifying ' 'multiple revs')) # TODO: handle tags try: # patchset number? maxrev = int(self.revs[0]) except ValueError: - raise util.Abort(_('revision %s is not a patchset number') + raise error.Abort(_('revision %s is not a patchset number') % self.revs[0]) d = os.getcwd() @@ -150,7 +150,7 @@ sck.send("\n".join(["BEGIN AUTH REQUEST", root, user, passw, "END AUTH REQUEST", ""])) if sck.recv(128) != "I LOVE YOU\n": - raise util.Abort(_("CVS pserver authentication failed")) + raise error.Abort(_("CVS pserver authentication failed")) self.writep = self.readp = sck.makefile('r+') @@ -193,7 +193,7 @@ self.writep.flush() r = self.readp.readline() if not r.startswith("Valid-requests"): - raise util.Abort(_('unexpected response from CVS server ' + raise error.Abort(_('unexpected response from CVS server ' '(expected "Valid-requests", but got %r)') % r) if "UseUnchanged" in r: @@ -215,7 +215,7 @@ while count > 0: data = fp.read(min(count, chunksize)) if not data: - raise util.Abort(_("%d bytes missing from remote file") + raise error.Abort(_("%d bytes missing from remote file") % count) count -= len(data) output.write(data) @@ -252,18 +252,18 @@ else: if line == "ok\n": if mode is None: - raise util.Abort(_('malformed response from CVS')) + raise error.Abort(_('malformed response from CVS')) return (data, "x" in mode and "x" or "") elif line.startswith("E "): self.ui.warn(_("cvs server: %s\n") % line[2:]) elif line.startswith("Remove"): self.readp.readline() else: - raise util.Abort(_("unknown CVS response: %s") % line) + raise error.Abort(_("unknown CVS response: %s") % line) def getchanges(self, rev, full): if full: - raise util.Abort(_("convert from cvs do not support --full")) + raise error.Abort(_("convert from cvs does not support --full")) self._parse() return sorted(self.files[rev].iteritems()), {}, set() diff -r d3712209921d -r b66e3ca0b90c hgext/convert/cvsps.py --- a/hgext/convert/cvsps.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/cvsps.py Tue Oct 20 15:59:10 2015 -0500 @@ -207,6 +207,7 @@ # state machine begins here tags = {} # dictionary of revisions on current file with their tags branchmap = {} # mapping between branch names and revision numbers + rcsmap = {} state = 0 store = False # set when a new record can be appended @@ -439,6 +440,8 @@ log.append(e) + rcsmap[e.rcs.replace('/Attic/', '/')] = e.rcs + if len(log) % 100 == 0: ui.status(util.ellipsis('%d %s' % (len(log), e.file), 80)+'\n') @@ -446,6 +449,13 @@ # find parent revisions of individual files versions = {} + for e in sorted(oldlog, key=lambda x: (x.rcs, x.revision)): + rcs = e.rcs.replace('/Attic/', '/') + if rcs in rcsmap: + e.rcs = rcsmap[rcs] + branch = e.revision[:-1] + versions[(e.rcs, branch)] = e.revision + for e in log: branch = e.revision[:-1] p = versions.get((e.rcs, branch), None) diff -r d3712209921d -r b66e3ca0b90c hgext/convert/darcs.py --- a/hgext/convert/darcs.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/darcs.py Tue Oct 20 15:59:10 2015 -0500 @@ -7,7 +7,7 @@ from common import NoRepo, checktool, commandline, commit, converter_source from mercurial.i18n import _ -from mercurial import util +from mercurial import util, error import os, shutil, tempfile, re, errno # The naming drift of ElementTree is fun! @@ -39,11 +39,11 @@ checktool('darcs') version = self.run0('--version').splitlines()[0].strip() if version < '2.1': - raise util.Abort(_('darcs version 2.1 or newer needed (found %r)') % - version) + raise error.Abort(_('darcs version 2.1 or newer needed (found %r)') + % version) if "ElementTree" not in globals(): - raise util.Abort(_("Python ElementTree module is not available")) + raise error.Abort(_("Python ElementTree module is not available")) self.path = os.path.realpath(path) @@ -158,7 +158,7 @@ def getchanges(self, rev, full): if full: - raise util.Abort(_("convert from darcs do not support --full")) + raise error.Abort(_("convert from darcs does not support --full")) copies = {} changes = [] man = None @@ -192,7 +192,7 @@ def getfile(self, name, rev): if rev != self.lastrev: - raise util.Abort(_('internal calling inconsistency')) + raise error.Abort(_('internal calling inconsistency')) path = os.path.join(self.tmppath, name) try: data = util.readfile(path) diff -r d3712209921d -r b66e3ca0b90c hgext/convert/filemap.py --- a/hgext/convert/filemap.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/filemap.py Tue Oct 20 15:59:10 2015 -0500 @@ -7,7 +7,7 @@ import posixpath import shlex from mercurial.i18n import _ -from mercurial import util, error +from mercurial import error from common import SKIPREV, converter_source def rpairs(path): @@ -42,9 +42,10 @@ self.include = {} self.exclude = {} self.rename = {} + self.targetprefixes = None if path: if self.parse(path): - raise util.Abort(_('errors in filemap')) + raise error.Abort(_('errors in filemap')) def parse(self, path): errs = 0 @@ -100,6 +101,30 @@ pass return '', name, '' + def istargetfile(self, filename): + """Return true if the given target filename is covered as a destination + of the filemap. This is useful for identifying what parts of the target + repo belong to the source repo and what parts don't.""" + if self.targetprefixes is None: + self.targetprefixes = set() + for before, after in self.rename.iteritems(): + self.targetprefixes.add(after) + + # If "." is a target, then all target files are considered from the + # source. + if not self.targetprefixes or '.' in self.targetprefixes: + return True + + filename = normalize(filename) + for pre, suf in rpairs(filename): + # This check is imperfect since it doesn't account for the + # include/exclude list, but it should work in filemaps that don't + # apply include/exclude to the same source directories they are + # renaming. + if pre in self.targetprefixes: + return True + return False + def __call__(self, name): if self.include: inc = self.lookup(name, self.include)[0] @@ -266,7 +291,7 @@ try: files = self.base.getchangedfiles(rev, i) except NotImplementedError: - raise util.Abort(_("source repository doesn't support --filemap")) + raise error.Abort(_("source repository doesn't support --filemap")) for f in files: if self.filemapper(f): return True @@ -410,6 +435,9 @@ return files, ncopies, ncleanp2 + def targetfilebelongstosource(self, targetfilename): + return self.filemapper.istargetfile(targetfilename) + def getfile(self, name, rev): realname, realrev = rev return self.base.getfile(realname, realrev) diff -r d3712209921d -r b66e3ca0b90c hgext/convert/git.py --- a/hgext/convert/git.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/git.py Tue Oct 20 15:59:10 2015 -0500 @@ -97,7 +97,7 @@ # 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')) + raise error.Abort(_('similarity must be between 0 and 100')) if similarity > 0: self.simopt = '-C%d%%' % similarity findcopiesharder = ui.configbool('convert', 'git.findcopiesharder', @@ -123,14 +123,14 @@ heads, ret = self.gitread('git rev-parse --branches --remotes') heads = heads.splitlines() if ret: - raise util.Abort(_('cannot retrieve git heads')) + raise error.Abort(_('cannot retrieve git heads')) else: heads = [] for rev in self.revs: rawhead, ret = self.gitread("git rev-parse --verify %s" % rev) heads.append(rawhead[:-1]) if ret: - raise util.Abort(_('cannot retrieve git head "%s"') % rev) + raise error.Abort(_('cannot retrieve git head "%s"') % rev) return heads def catfile(self, rev, type): @@ -140,11 +140,11 @@ self.catfilepipe[0].flush() info = self.catfilepipe[1].readline().split() if info[1] != type: - raise util.Abort(_('cannot read %r object at %s') % (type, rev)) + raise error.Abort(_('cannot read %r object at %s') % (type, rev)) size = int(info[2]) data = self.catfilepipe[1].read(size) if len(data) < size: - raise util.Abort(_('cannot read %r object at %s: unexpected size') + raise error.Abort(_('cannot read %r object at %s: unexpected size') % (type, rev)) # read the trailing newline self.catfilepipe[1].read(1) @@ -210,7 +210,7 @@ def getchanges(self, version, full): if full: - raise util.Abort(_("convert from git do not support --full")) + raise error.Abort(_("convert from git does not support --full")) self.modecache = {} fh = self.gitopen("git diff-tree -z --root -m -r %s %s" % ( self.simopt, version)) @@ -224,6 +224,8 @@ lcount = len(difftree) i = 0 + skipsubmodules = self.ui.configbool('convert', 'git.skipsubmodules', + False) def add(entry, f, isdest): seen.add(f) h = entry[3] @@ -232,6 +234,9 @@ renamesource = (not isdest and entry[4][0] == 'R') if f == '.gitmodules': + if skipsubmodules: + return + subexists[0] = True if entry[4] == 'D' or renamesource: subdeleted[0] = True @@ -239,7 +244,8 @@ else: changes.append(('.hgsub', '')) elif entry[1] == '160000' or entry[0] == ':160000': - subexists[0] = True + if not skipsubmodules: + subexists[0] = True else: if renamesource: h = hex(nullid) @@ -277,7 +283,7 @@ copies[fdest] = f entry = None if fh.close(): - raise util.Abort(_('cannot read changes in %s') % version) + raise error.Abort(_('cannot read changes in %s') % version) if subexists[0]: if subdeleted[0]: @@ -336,13 +342,13 @@ for line in fh: line = line.strip() if line.startswith("error:") or line.startswith("fatal:"): - raise util.Abort(_('cannot read tags from %s') % self.path) + raise error.Abort(_('cannot read tags from %s') % self.path) node, tag = line.split(None, 1) if not tag.startswith(prefix): continue alltags[tag[len(prefix):]] = node if fh.close(): - raise util.Abort(_('cannot read tags from %s') % self.path) + raise error.Abort(_('cannot read tags from %s') % self.path) # Filter out tag objects for annotated tag refs for tag in alltags: @@ -370,35 +376,38 @@ '"%s^%s" --' % (version, version, i + 1)) changes = [f.rstrip('\n') for f in fh] if fh.close(): - raise util.Abort(_('cannot read changes in %s') % version) + raise error.Abort(_('cannot read changes in %s') % version) return changes def getbookmarks(self): bookmarks = {} - # Interesting references in git are prefixed - prefix = 'refs/heads/' - prefixlen = len(prefix) + # Handle local and remote branches + remoteprefix = self.ui.config('convert', 'git.remoteprefix', 'remote') + reftypes = [ + # (git prefix, hg prefix) + ('refs/remotes/origin/', remoteprefix + '/'), + ('refs/heads/', '') + ] - # factor two commands - remoteprefix = self.ui.config('convert', 'git.remoteprefix', 'remote') - gitcmd = { remoteprefix + '/': 'git ls-remote --heads origin', - '': 'git show-ref'} + exclude = set([ + 'refs/remotes/origin/HEAD', + ]) - # Origin heads - for reftype in gitcmd: - try: - fh = self.gitopen(gitcmd[reftype], err=subprocess.PIPE) - for line in fh: - line = line.strip() - rev, name = line.split(None, 1) - if not name.startswith(prefix): + try: + fh = self.gitopen('git show-ref', err=subprocess.PIPE) + for line in fh: + line = line.strip() + rev, name = line.split(None, 1) + # Process each type of branch + for gitprefix, hgprefix in reftypes: + if not name.startswith(gitprefix) or name in exclude: continue - name = '%s%s' % (reftype, name[prefixlen:]) + name = '%s%s' % (hgprefix, name[len(gitprefix):]) bookmarks[name] = rev - except Exception: - pass + except Exception: + pass return bookmarks diff -r d3712209921d -r b66e3ca0b90c hgext/convert/gnuarch.py --- a/hgext/convert/gnuarch.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/gnuarch.py Tue Oct 20 15:59:10 2015 -0500 @@ -8,7 +8,7 @@ from common import NoRepo, commandline, commit, converter_source from mercurial.i18n import _ -from mercurial import encoding, util +from mercurial import encoding, util, error import os, shutil, tempfile, stat from email.Parser import Parser @@ -42,7 +42,7 @@ if util.findexe('tla'): self.execmd = 'tla' else: - raise util.Abort(_('cannot find a GNU Arch tool')) + raise error.Abort(_('cannot find a GNU Arch tool')) commandline.__init__(self, ui, self.execmd) @@ -135,7 +135,7 @@ def getfile(self, name, rev): if rev != self.lastrev: - raise util.Abort(_('internal calling inconsistency')) + raise error.Abort(_('internal calling inconsistency')) if not os.path.lexists(os.path.join(self.tmppath, name)): return None, None @@ -144,7 +144,7 @@ def getchanges(self, rev, full): if full: - raise util.Abort(_("convert from arch do not support --full")) + raise error.Abort(_("convert from arch does not support --full")) self._update(rev) changes = [] copies = {} @@ -287,7 +287,7 @@ self.changes[rev].continuationof = self.recode( catlog['Continuation-of']) except Exception: - raise util.Abort(_('could not parse cat-log of %s') % rev) + raise error.Abort(_('could not parse cat-log of %s') % rev) def _parsechangeset(self, data, rev): for l in data: diff -r d3712209921d -r b66e3ca0b90c hgext/convert/hg.py --- a/hgext/convert/hg.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/hg.py Tue Oct 20 15:59:10 2015 -0500 @@ -23,6 +23,7 @@ from mercurial.node import bin, hex, nullid from mercurial import hg, util, context, bookmarks, error, scmutil, exchange from mercurial import phases +from mercurial import merge as mergemod from common import NoRepo, commit, converter_source, converter_sink, mapfile @@ -176,14 +177,58 @@ return fp.getvalue() + def _calculatemergedfiles(self, source, p1ctx, p2ctx): + """Calculates the files from p2 that we need to pull in when merging p1 + and p2, given that the merge is coming from the given source. + + This prevents us from losing files that only exist in the target p2 and + that don't come from the source repo (like if you're merging multiple + repositories together). + """ + anc = [p1ctx.ancestor(p2ctx)] + # Calculate what files are coming from p2 + actions, diverge, rename = mergemod.calculateupdates( + self.repo, p1ctx, p2ctx, anc, + True, # branchmerge + True, # force + False, # partial + False, # acceptremote + False, # followcopies + ) + + for file, (action, info, msg) in actions.iteritems(): + if source.targetfilebelongstosource(file): + # If the file belongs to the source repo, ignore the p2 + # since it will be covered by the existing fileset. + continue + + # If the file requires actual merging, abort. We don't have enough + # context to resolve merges correctly. + if action in ['m', 'dm', 'cd', 'dc']: + raise error.Abort(_("unable to convert merge commit " + "since target parents do not merge cleanly (file " + "%s, parents %s and %s)") % (file, p1ctx, + p2ctx)) + elif action == 'k': + # 'keep' means nothing changed from p1 + continue + else: + # Any other change means we want to take the p2 version + yield file + def putcommit(self, files, copies, parents, commit, source, revmap, full, cleanp2): files = dict(files) def getfilectx(repo, memctx, f): - if p2ctx and f in cleanp2 and f not in copies: + if p2ctx and f in p2files and f not in copies: self.ui.debug('reusing %s from p2\n' % f) - return p2ctx[f] + try: + return p2ctx[f] + except error.ManifestLookupError: + # If the file doesn't exist in p2, then we're syncing a + # delete, so just return None. + return None try: v = files[f] except KeyError: @@ -255,6 +300,7 @@ while parents: p1 = p2 p2 = parents.pop(0) + p1ctx = self.repo[p1] p2ctx = None if p2 != nullid: p2ctx = self.repo[p2] @@ -262,6 +308,13 @@ if full: fileset.update(self.repo[p1]) fileset.update(self.repo[p2]) + + if p2ctx: + p2files = set(cleanp2) + for file in self._calculatemergedfiles(source, p1ctx, p2ctx): + p2files.add(file) + fileset.add(file) + ctx = context.memctx(self.repo, (p1, p2), text, fileset, getfilectx, commit.author, commit.date, extra) @@ -370,7 +423,7 @@ def hascommitforsplicemap(self, rev): if rev not in self.repo and self.clonebranches: - raise util.Abort(_('revision %s not found in destination ' + raise error.Abort(_('revision %s not found in destination ' 'repository (lookups with clonebranches=true ' 'are not implemented)') % rev) return rev in self.repo @@ -378,9 +431,6 @@ class mercurial_source(converter_source): def __init__(self, ui, path, revs=None): converter_source.__init__(self, ui, path, revs) - if revs and len(revs) > 1: - raise util.Abort(_("mercurial source does not support specifying " - "multiple revisions")) self.ignoreerrors = ui.configbool('convert', 'hg.ignoreerrors', False) self.ignored = set() self.saverev = ui.configbool('convert', 'hg.saverev', False) @@ -405,7 +455,7 @@ try: startnode = self.repo.lookup(startnode) except error.RepoError: - raise util.Abort(_('%s is not a valid start revision') + raise error.Abort(_('%s is not a valid start revision') % startnode) startrev = self.repo.changelog.rev(startnode) children = {startnode: 1} @@ -415,12 +465,12 @@ else: self.keep = util.always if revs: - self._heads = [self.repo[revs[0]].node()] + self._heads = [self.repo[r].node() for r in revs] else: self._heads = self.repo.heads() else: if revs or startnode is not None: - raise util.Abort(_('hg.revs cannot be combined with ' + raise error.Abort(_('hg.revs cannot be combined with ' 'hg.startrev or --rev')) nodes = set() parents = set() diff -r d3712209921d -r b66e3ca0b90c hgext/convert/monotone.py --- a/hgext/convert/monotone.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/monotone.py Tue Oct 20 15:59:10 2015 -0500 @@ -7,7 +7,7 @@ # GNU General Public License version 2 or any later version. import os, re -from mercurial import util +from mercurial import util, error from common import NoRepo, commit, converter_source, checktool from common import commandline from mercurial.i18n import _ @@ -16,7 +16,7 @@ def __init__(self, ui, path=None, revs=None): converter_source.__init__(self, ui, path, revs) if revs and len(revs) > 1: - raise util.Abort(_('monotone source does not support specifying ' + raise error.Abort(_('monotone source does not support specifying ' 'multiple revs')) commandline.__init__(self, ui, 'mtn') @@ -110,34 +110,34 @@ while read != ':': read = self.mtnreadfp.read(1) if not read: - raise util.Abort(_('bad mtn packet - no end of commandnbr')) + raise error.Abort(_('bad mtn packet - no end of commandnbr')) commandnbr += read commandnbr = commandnbr[:-1] stream = self.mtnreadfp.read(1) if stream not in 'mewptl': - raise util.Abort(_('bad mtn packet - bad stream type %s') % stream) + raise error.Abort(_('bad mtn packet - bad stream type %s') % stream) read = self.mtnreadfp.read(1) if read != ':': - raise util.Abort(_('bad mtn packet - no divider before size')) + raise error.Abort(_('bad mtn packet - no divider before size')) read = None lengthstr = '' while read != ':': read = self.mtnreadfp.read(1) if not read: - raise util.Abort(_('bad mtn packet - no end of packet size')) + raise error.Abort(_('bad mtn packet - no end of packet size')) lengthstr += read try: length = long(lengthstr[:-1]) except TypeError: - raise util.Abort(_('bad mtn packet - bad packet size %s') + raise error.Abort(_('bad mtn packet - bad packet size %s') % lengthstr) read = self.mtnreadfp.read(length) if len(read) != length: - raise util.Abort(_("bad mtn packet - unable to read full packet " + raise error.Abort(_("bad mtn packet - unable to read full packet " "read %s of %s") % (len(read), length)) return (commandnbr, stream, length, read) @@ -152,7 +152,7 @@ if stream == 'l': # End of command if output != '0': - raise util.Abort(_("mtn command '%s' returned %s") % + raise error.Abort(_("mtn command '%s' returned %s") % (command, output)) break elif stream in 'ew': @@ -229,7 +229,8 @@ def getchanges(self, rev, full): if full: - raise util.Abort(_("convert from monotone do not support --full")) + raise error.Abort(_("convert from monotone does not support " + "--full")) revision = self.mtnrun("get_revision", rev).split("\n\n") files = {} ignoremove = {} @@ -330,7 +331,7 @@ versionstr = self.mtnrunsingle("interface_version") version = float(versionstr) except Exception: - raise util.Abort(_("unable to determine mtn automate interface " + raise error.Abort(_("unable to determine mtn automate interface " "version")) if version >= 12.0: @@ -344,12 +345,12 @@ # read the headers read = self.mtnreadfp.readline() if read != 'format-version: 2\n': - raise util.Abort(_('mtn automate stdio header unexpected: %s') + raise error.Abort(_('mtn automate stdio header unexpected: %s') % read) while read != '\n': read = self.mtnreadfp.readline() if not read: - raise util.Abort(_("failed to reach end of mtn automate " + raise error.Abort(_("failed to reach end of mtn automate " "stdio headers")) else: self.ui.debug("mtn automate version %s - not using automate stdio " diff -r d3712209921d -r b66e3ca0b90c hgext/convert/p4.py --- a/hgext/convert/p4.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/p4.py Tue Oct 20 15:59:10 2015 -0500 @@ -5,7 +5,7 @@ # This software may be used and distributed according to the terms of the # GNU General Public License version 2 or any later version. -from mercurial import util +from mercurial import util, error from mercurial.i18n import _ from common import commit, converter_source, checktool, NoRepo @@ -70,7 +70,7 @@ self.re_keywords_old = re.compile("\$(Id|Header):[^$\n]*\$") if revs and len(revs) > 1: - raise util.Abort(_("p4 source does not support specifying " + raise error.Abort(_("p4 source does not support specifying " "multiple revisions")) self._parse(ui, path) @@ -277,7 +277,7 @@ def getchanges(self, rev, full): if full: - raise util.Abort(_("convert from p4 do not support --full")) + raise error.Abort(_("convert from p4 does not support --full")) return self.files[rev], self.copies[rev], set() def getcommit(self, rev): diff -r d3712209921d -r b66e3ca0b90c hgext/convert/subversion.py --- a/hgext/convert/subversion.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/convert/subversion.py Tue Oct 20 15:59:10 2015 -0500 @@ -6,7 +6,7 @@ import xml.dom.minidom import cPickle as pickle -from mercurial import strutil, scmutil, util, encoding +from mercurial import strutil, scmutil, util, encoding, error from mercurial.i18n import _ propertycache = util.propertycache @@ -141,7 +141,7 @@ avoid memory collection issues. """ if svn is None: - raise util.Abort(_('debugsvnlog could not load Subversion python ' + raise error.Abort(_('debugsvnlog could not load Subversion python ' 'bindings')) util.setbinary(sys.stdin) @@ -159,14 +159,14 @@ try: entry = pickle.load(self._stdout) except EOFError: - raise util.Abort(_('Mercurial failed to run itself, check' + raise error.Abort(_('Mercurial failed to run itself, check' ' hg executable is in PATH')) try: orig_paths, revnum, author, date, message = entry except (TypeError, ValueError): if entry is None: break - raise util.Abort(_("log stream exception '%s'") % entry) + raise error.Abort(_("log stream exception '%s'") % entry) yield entry def close(self): @@ -327,12 +327,12 @@ if revs: if len(revs) > 1: - raise util.Abort(_('subversion source does not support ' + raise error.Abort(_('subversion source does not support ' 'specifying multiple revisions')) try: latest = int(revs[0]) except ValueError: - raise util.Abort(_('svn: revision %s is not an integer') % + raise error.Abort(_('svn: revision %s is not an integer') % revs[0]) self.trunkname = self.ui.config('convert', 'svn.trunk', @@ -343,7 +343,7 @@ if self.startrev < 0: self.startrev = 0 except ValueError: - raise util.Abort(_('svn: start revision %s is not an integer') + raise error.Abort(_('svn: start revision %s is not an integer') % self.startrev) try: @@ -351,7 +351,7 @@ except SvnPathNotFound: self.head = None if not self.head: - raise util.Abort(_('no revision found in module %s') + raise error.Abort(_('no revision found in module %s') % self.module) self.last_changed = self.revnum(self.head) @@ -396,8 +396,8 @@ # we are converting from inside this directory return None if cfgpath: - raise util.Abort(_('expected %s to be at %r, but not found') - % (name, path)) + raise error.Abort(_('expected %s to be at %r, but not found' + ) % (name, path)) return None self.ui.note(_('found %s at %r\n') % (name, path)) return path @@ -415,7 +415,7 @@ self.module += '/' + trunk self.head = self.latest(self.module, self.last_changed) if not self.head: - raise util.Abort(_('no revision found in module %s') + raise error.Abort(_('no revision found in module %s') % self.module) # First head in the list is the module's head @@ -442,11 +442,11 @@ if self.startrev and self.heads: if len(self.heads) > 1: - raise util.Abort(_('svn: start revision is not supported ' + raise error.Abort(_('svn: start revision is not supported ' 'with more than one branch')) revnum = self.revnum(self.heads[0]) if revnum < self.startrev: - raise util.Abort( + raise error.Abort( _('svn: no revision found after start revision %d') % self.startrev) @@ -502,7 +502,7 @@ stop = revnum + 1 self._fetch_revisions(revnum, stop) if rev not in self.commits: - raise util.Abort(_('svn: revision %s not found') % revnum) + raise error.Abort(_('svn: revision %s not found') % revnum) revcommit = self.commits[rev] # caller caches the result, so free it here to release memory del self.commits[rev] @@ -513,7 +513,7 @@ if not re.match(r'svn:[0-9a-f]{8,8}-[0-9a-f]{4,4}-' '[0-9a-f]{4,4}-[0-9a-f]{4,4}-[0-9a-f]' '{12,12}(.*)\@[0-9]+$',revstr): - raise util.Abort(_('%s entry %s is not a valid revision' + raise error.Abort(_('%s entry %s is not a valid revision' ' identifier') % (mapname, revstr)) def numcommits(self): @@ -951,7 +951,7 @@ except SubversionException as xxx_todo_changeme: (inst, num) = xxx_todo_changeme.args if num == svn.core.SVN_ERR_FS_NO_SUCH_REVISION: - raise util.Abort(_('svn: branch has no revision %s') + raise error.Abort(_('svn: branch has no revision %s') % to_revnum) raise @@ -1052,7 +1052,7 @@ try: stdin.close() except IOError: - raise util.Abort(_('Mercurial failed to run itself, check' + raise error.Abort(_('Mercurial failed to run itself, check' ' hg executable is in PATH')) return logstream(stdout) @@ -1302,7 +1302,7 @@ return parents[0] self.ui.warn(_('unexpected svn output:\n')) self.ui.warn(output) - raise util.Abort(_('unable to cope with svn output')) + raise error.Abort(_('unable to cope with svn output')) if commit.rev: self.run('propset', 'hg:convert-rev', commit.rev, revprop=True, revision=rev) @@ -1329,6 +1329,6 @@ # repository and childmap would not list all revisions. Too bad. if rev in self.childmap: return True - raise util.Abort(_('splice map revision %s not found in subversion ' + raise error.Abort(_('splice map revision %s not found in subversion ' 'child map (revision lookups are not implemented)') % rev) diff -r d3712209921d -r b66e3ca0b90c hgext/eol.py --- a/hgext/eol.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/eol.py Tue Oct 20 15:59:10 2015 -0500 @@ -23,7 +23,7 @@ ``native`` is an alias for checking out in the platform's default line ending: ``LF`` on Unix (including Mac OS X) and ``CRLF`` on Windows. Note that ``BIN`` (do nothing to line endings) is Mercurial's -default behaviour; it is only needed if you need to override a later, +default behavior; it is only needed if you need to override a later, more general pattern. The optional ``[repository]`` section specifies the line endings to @@ -247,7 +247,7 @@ for node, target, f in failed: msgs.append(_(" %s in %s should not have %s line endings") % (f, node, eols[target])) - raise util.Abort(_("end-of-line check failed:\n") + "\n".join(msgs)) + raise error.Abort(_("end-of-line check failed:\n") + "\n".join(msgs)) def checkallhook(ui, repo, node, hooktype, **kwargs): """verify that files have expected EOLs""" @@ -333,7 +333,7 @@ # so ignore the error. pass - def commitctx(self, ctx, error=False): + def commitctx(self, ctx, haserror=False): for f in sorted(ctx.added() + ctx.modified()): if not self._eolfile(f): continue @@ -347,8 +347,8 @@ # have all non-binary files taken care of. continue if inconsistenteol(data): - raise util.Abort(_("inconsistent newline style " + raise error.Abort(_("inconsistent newline style " "in %s\n") % f) - return super(eolrepo, self).commitctx(ctx, error) + return super(eolrepo, self).commitctx(ctx, haserror) repo.__class__ = eolrepo repo._hgcleardirstate() diff -r d3712209921d -r b66e3ca0b90c hgext/extdiff.py --- a/hgext/extdiff.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/extdiff.py Tue Oct 20 15:59:10 2015 -0500 @@ -63,7 +63,7 @@ from mercurial.i18n import _ from mercurial.node import short, nullid from mercurial import cmdutil, scmutil, util, commands, encoding, filemerge -from mercurial import archival +from mercurial import archival, error import os, shlex, shutil, tempfile, re cmdtable = {} @@ -127,7 +127,7 @@ if revs and change: msg = _('cannot specify --rev and --change at the same time') - raise util.Abort(msg) + raise error.Abort(msg) elif change: node2 = scmutil.revsingle(repo, change, None).node() node1a, node1b = repo.changelog.parents(node2) @@ -146,72 +146,94 @@ subrepos=opts.get('subrepos') matcher = scmutil.match(repo[node2], pats, opts) - mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher, - listsubrepos=subrepos)[:3]) - if do3way: - mod_b, add_b, rem_b = map(set, repo.status(node1b, node2, matcher, - listsubrepos=subrepos)[:3]) + + if opts.get('patch'): + if subrepos: + raise error.Abort(_('--patch cannot be used with --subrepos')) + if node2 is None: + raise error.Abort(_('--patch requires two revisions')) else: - mod_b, add_b, rem_b = set(), set(), set() - modadd = mod_a | add_a | mod_b | add_b - common = modadd | rem_a | rem_b - if not common: - return 0 + mod_a, add_a, rem_a = map(set, repo.status(node1a, node2, matcher, + listsubrepos=subrepos)[:3]) + if do3way: + mod_b, add_b, rem_b = map(set, + repo.status(node1b, node2, matcher, + listsubrepos=subrepos)[:3]) + else: + mod_b, add_b, rem_b = set(), set(), set() + modadd = mod_a | add_a | mod_b | add_b + common = modadd | rem_a | rem_b + if not common: + return 0 tmproot = tempfile.mkdtemp(prefix='extdiff.') try: - # Always make a copy of node1a (and node1b, if applicable) - dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) - dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[0] - rev1a = '@%d' % repo[node1a].rev() - if do3way: - dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) - dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot, + if not opts.get('patch'): + # Always make a copy of node1a (and node1b, if applicable) + dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a) + dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[0] - rev1b = '@%d' % repo[node1b].rev() - else: - dir1b = None - rev1b = '' + rev1a = '@%d' % repo[node1a].rev() + if do3way: + dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b) + dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot, + subrepos)[0] + rev1b = '@%d' % repo[node1b].rev() + else: + dir1b = None + rev1b = '' - fns_and_mtime = [] + fns_and_mtime = [] - # If node2 in not the wc or there is >1 change, copy it - dir2root = '' - rev2 = '' - if node2: - dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0] - rev2 = '@%d' % repo[node2].rev() - elif len(common) > 1: - #we only actually need to get the files to copy back to - #the working dir in this case (because the other cases - #are: diffing 2 revisions or single file -- in which case - #the file is already directly passed to the diff tool). - dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot, - subrepos) - else: - # This lets the diff tool open the changed file directly - dir2 = '' - dir2root = repo.root + # If node2 in not the wc or there is >1 change, copy it + dir2root = '' + rev2 = '' + if node2: + dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0] + rev2 = '@%d' % repo[node2].rev() + elif len(common) > 1: + #we only actually need to get the files to copy back to + #the working dir in this case (because the other cases + #are: diffing 2 revisions or single file -- in which case + #the file is already directly passed to the diff tool). + dir2, fns_and_mtime = snapshot(ui, repo, modadd, None, tmproot, + subrepos) + else: + # This lets the diff tool open the changed file directly + dir2 = '' + dir2root = repo.root + + label1a = rev1a + label1b = rev1b + label2 = rev2 - label1a = rev1a - label1b = rev1b - label2 = rev2 - - # If only one change, diff the files instead of the directories - # Handle bogus modifies correctly by checking if the files exist - if len(common) == 1: - common_file = util.localpath(common.pop()) - dir1a = os.path.join(tmproot, dir1a, common_file) - label1a = common_file + rev1a - if not os.path.isfile(dir1a): - dir1a = os.devnull - if do3way: - dir1b = os.path.join(tmproot, dir1b, common_file) - label1b = common_file + rev1b - if not os.path.isfile(dir1b): - dir1b = os.devnull - dir2 = os.path.join(dir2root, dir2, common_file) - label2 = common_file + rev2 + # If only one change, diff the files instead of the directories + # Handle bogus modifies correctly by checking if the files exist + if len(common) == 1: + common_file = util.localpath(common.pop()) + dir1a = os.path.join(tmproot, dir1a, common_file) + label1a = common_file + rev1a + if not os.path.isfile(dir1a): + dir1a = os.devnull + if do3way: + dir1b = os.path.join(tmproot, dir1b, common_file) + label1b = common_file + rev1b + if not os.path.isfile(dir1b): + dir1b = os.devnull + dir2 = os.path.join(dir2root, dir2, common_file) + label2 = common_file + rev2 + else: + template = 'hg-%h.patch' + cmdutil.export(repo, [repo[node1a].rev(), repo[node2].rev()], + template=repo.vfs.reljoin(tmproot, template), + match=matcher) + label1a = cmdutil.makefilename(repo, template, node1a) + label2 = cmdutil.makefilename(repo, template, node2) + dir1a = repo.vfs.reljoin(tmproot, label1a) + dir2 = repo.vfs.reljoin(tmproot, label2) + dir1b = None + label1b = None + fns_and_mtime = [] # Function to quote file/dir names in the argument string. # When not operating in 3-way mode, an empty string is @@ -255,6 +277,7 @@ _('pass option to comparison program'), _('OPT')), ('r', 'rev', [], _('revision'), _('REV')), ('c', 'change', '', _('change made by revision'), _('REV')), + ('', 'patch', None, _('compare patches for two revisions')) ] + commands.walkopts + commands.subrepoopts, _('hg extdiff [OPT]... [FILE]...'), inferrepo=True) diff -r d3712209921d -r b66e3ca0b90c hgext/factotum.py --- a/hgext/factotum.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/factotum.py Tue Oct 20 15:59:10 2015 -0500 @@ -47,7 +47,7 @@ from mercurial.i18n import _ from mercurial.url import passwordmgr -from mercurial import httpconnection, util +from mercurial import httpconnection, error import os, urllib2 ERRMAX = 128 @@ -56,7 +56,7 @@ def auth_getkey(self, params): if not self.ui.interactive(): - raise util.Abort(_('factotum not interactive')) + raise error.Abort(_('factotum not interactive')) if 'user=' not in params: params = '%s user?' % params params = '%s !password?' % params @@ -77,10 +77,10 @@ if passwd.endswith("'"): passwd = passwd[1:-1].replace("''", "'") else: - raise util.Abort(_('malformed password string')) + raise error.Abort(_('malformed password string')) return (user, passwd) except (OSError, IOError): - raise util.Abort(_('factotum not responding')) + raise error.Abort(_('factotum not responding')) finally: os.close(fd) getkey(self, params) diff -r d3712209921d -r b66e3ca0b90c hgext/fetch.py --- a/hgext/fetch.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/fetch.py Tue Oct 20 15:59:10 2015 -0500 @@ -60,7 +60,7 @@ except error.RepoLookupError: branchnode = None if parent != branchnode: - raise util.Abort(_('working directory not at branch tip'), + raise error.Abort(_('working directory not at branch tip'), hint=_('use "hg update" to check out branch tip')) wlock = lock = None @@ -73,7 +73,7 @@ bheads = repo.branchheads(branch) bheads = [head for head in bheads if len(repo[head].children()) == 0] if len(bheads) > 1: - raise util.Abort(_('multiple heads in this branch ' + raise error.Abort(_('multiple heads in this branch ' '(use "hg heads ." and "hg merge" to merge)')) other = hg.peer(repo, opts, ui.expandpath(source)) @@ -86,7 +86,7 @@ except error.CapabilityError: err = _("other repository doesn't support revision lookup, " "so a rev cannot be specified.") - raise util.Abort(err) + raise error.Abort(err) # Are there any changes at all? modheads = exchange.pull(repo, other, heads=revs).cgresult diff -r d3712209921d -r b66e3ca0b90c hgext/gpg.py --- a/hgext/gpg.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/gpg.py Tue Oct 20 15:59:10 2015 -0500 @@ -6,7 +6,7 @@ '''commands to sign and verify changesets''' import os, tempfile, binascii -from mercurial import util, commands, match, cmdutil +from mercurial import util, commands, match, cmdutil, error from mercurial import node as hgnode from mercurial.i18n import _ @@ -237,7 +237,7 @@ nodes = [node for node in repo.dirstate.parents() if node != hgnode.nullid] if len(nodes) > 1: - raise util.Abort(_('uncommitted merge - please provide a ' + raise error.Abort(_('uncommitted merge - please provide a ' 'specific revision')) if not nodes: nodes = [repo.changelog.tip()] @@ -250,7 +250,7 @@ data = node2txt(repo, n, sigver) sig = mygpg.sign(data) if not sig: - raise util.Abort(_("error while signing")) + raise error.Abort(_("error while signing")) sig = binascii.b2a_base64(sig) sig = sig.replace("\n", "") sigmessage += "%s %s %s\n" % (hexnode, sigver, sig) @@ -263,7 +263,7 @@ if not opts["force"]: msigs = match.exact(repo.root, '', ['.hgsigs']) if any(repo.status(match=msigs, unknown=True, ignored=True)): - raise util.Abort(_("working copy of .hgsigs is changed "), + raise error.Abort(_("working copy of .hgsigs is changed "), hint=_("please commit .hgsigs manually")) sigsfile = repo.wfile(".hgsigs", "ab") @@ -287,7 +287,7 @@ repo.commit(message, opts['user'], opts['date'], match=msigs, editor=editor) except ValueError as inst: - raise util.Abort(str(inst)) + raise error.Abort(str(inst)) def shortkey(ui, key): if len(key) != 16: @@ -301,4 +301,4 @@ if ver == "0": return "%s\n" % hgnode.hex(node) else: - raise util.Abort(_("unknown signature version")) + raise error.Abort(_("unknown signature version")) diff -r d3712209921d -r b66e3ca0b90c hgext/hgcia.py --- a/hgext/hgcia.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/hgcia.py Tue Oct 20 15:59:10 2015 -0500 @@ -43,7 +43,7 @@ from mercurial.i18n import _ from mercurial.node import bin, short -from mercurial import cmdutil, patch, util, mail +from mercurial import cmdutil, patch, util, mail, error import email.Parser import socket, xmlrpclib @@ -233,7 +233,7 @@ srv = xmlrpclib.Server(self.ciaurl) res = srv.hub.deliver(msg) if res is not True and res != 'queued.': - raise util.Abort(_('%s returned an error: %s') % + raise error.Abort(_('%s returned an error: %s') % (self.ciaurl, res)) def sendemail(self, address, data): @@ -259,7 +259,7 @@ ui.write(msg) elif cia.ciaurl.startswith('mailto:'): if not cia.emailfrom: - raise util.Abort(_('email.from must be defined when ' + raise error.Abort(_('email.from must be defined when ' 'sending by email')) cia.sendemail(cia.ciaurl[7:], msg) else: diff -r d3712209921d -r b66e3ca0b90c hgext/highlight/__init__.py --- a/hgext/highlight/__init__.py Thu Oct 08 23:24:38 2015 +0900 +++ b/hgext/highlight/__init__.py Tue Oct 20 15:59:10 2015 -0500 @@ -13,23 +13,40 @@ It depends on the Pygments syntax highlighting library: http://pygments.org/ -There is a single configuration option:: +There are the following configuration options:: [web] - pygments_style =