Bug 1463834 - vendored hglib, updated to python-hglib r=davehunt
authorSofia Carrillo <scarrillo@mozilla.com>
Thu, 31 May 2018 18:04:54 -0700
changeset 475288 4146b1ddbb34d890b76e47584c93232171180fee
parent 475287 f16a2472bcb54d35e3bb63fe7ea80053e0d9fcc9
child 475289 aeea710872fef737c3a4fcef9925fe7c18058f21
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdavehunt
bugs1463834
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1463834 - vendored hglib, updated to python-hglib r=davehunt
Pipfile
Pipfile.lock
build/virtualenv_packages.txt
third_party/python/hglib/LICENSE
third_party/python/hglib/hglib/__init__.py
third_party/python/hglib/hglib/client.py
third_party/python/hglib/hglib/context.py
third_party/python/hglib/hglib/error.py
third_party/python/hglib/hglib/merge.py
third_party/python/hglib/hglib/templates.py
third_party/python/hglib/hglib/util.py
third_party/python/hglib/setup.py
third_party/python/py/.hgtags
third_party/python/python-hglib/.hgignore
third_party/python/python-hglib/LICENSE
third_party/python/python-hglib/Makefile
third_party/python/python-hglib/PKG-INFO
third_party/python/python-hglib/README
third_party/python/python-hglib/examples/stats.py
third_party/python/python-hglib/hglib/__init__.py
third_party/python/python-hglib/hglib/client.py
third_party/python/python-hglib/hglib/context.py
third_party/python/python-hglib/hglib/error.py
third_party/python/python-hglib/hglib/merge.py
third_party/python/python-hglib/hglib/templates.py
third_party/python/python-hglib/hglib/util.py
third_party/python/python-hglib/setup.py
third_party/python/python-hglib/test.py
third_party/python/python-hglib/tests/__init__.py
third_party/python/python-hglib/tests/common.py
third_party/python/python-hglib/tests/test-annotate.py
third_party/python/python-hglib/tests/test-bookmarks.py
third_party/python/python-hglib/tests/test-branch.py
third_party/python/python-hglib/tests/test-branches.py
third_party/python/python-hglib/tests/test-bundle.py
third_party/python/python-hglib/tests/test-commit.py
third_party/python/python-hglib/tests/test-config.py
third_party/python/python-hglib/tests/test-copy.py
third_party/python/python-hglib/tests/test-diff.py
third_party/python/python-hglib/tests/test-encoding.py
third_party/python/python-hglib/tests/test-forget.py
third_party/python/python-hglib/tests/test-grep.py
third_party/python/python-hglib/tests/test-heads.py
third_party/python/python-hglib/tests/test-hglib.py
third_party/python/python-hglib/tests/test-import.py
third_party/python/python-hglib/tests/test-init.py
third_party/python/python-hglib/tests/test-log.py
third_party/python/python-hglib/tests/test-manifest.py
third_party/python/python-hglib/tests/test-merge.py
third_party/python/python-hglib/tests/test-move.py
third_party/python/python-hglib/tests/test-outgoing-incoming.py
third_party/python/python-hglib/tests/test-parents.py
third_party/python/python-hglib/tests/test-paths.py
third_party/python/python-hglib/tests/test-pull.py
third_party/python/python-hglib/tests/test-push.py
third_party/python/python-hglib/tests/test-remove.py
third_party/python/python-hglib/tests/test-resolve.py
third_party/python/python-hglib/tests/test-status.py
third_party/python/python-hglib/tests/test-summary.py
third_party/python/python-hglib/tests/test-tags.py
third_party/python/python-hglib/tests/test-update.py
third_party/python/python-hglib/tests/with_hg.py
--- a/Pipfile
+++ b/Pipfile
@@ -7,11 +7,12 @@ name = "pypi"
 
 [packages]
 pipenv = "==2018.5.18"
 virtualenv = "==15.2.0"
 six = "==1.10.0"
 attrs = "==18.1.0"
 pytest = "==3.2.5"
 jsmin = "==2.1.0"
+python-hglib = "==2.4"
 
 [requires]
 python_version = "2.7"
--- a/Pipfile.lock
+++ b/Pipfile.lock
@@ -1,12 +1,12 @@
 {
     "_meta": {
         "hash": {
-            "sha256": "706dd858cb4e07dbccf7f3e6f129ac5b50c9906bcd6083e4fb09e9869b379d5e"
+            "sha256": "695978bb529a1cffb6f329519ce6fe68adbee73d9f05595dbefb2b9d0ebe4177"
         },
         "pipfile-spec": 6,
         "requires": {
             "python_version": "2.7"
         },
         "sources": [
             {
                 "name": "pypi",
@@ -56,16 +56,23 @@
         "pytest": {
             "hashes": [
                 "sha256:241d7e7798d79192a123ceaf64c602b4d233eacf6d6e42ae27caa97f498b7dc6",
                 "sha256:6d5bd4f7113b444c55a3bbb5c738a3dd80d43563d063fc42dcb0aaefbdd78b81"
             ],
             "index": "pypi",
             "version": "==3.2.5"
         },
+        "python-hglib": {
+            "hashes": [
+                "sha256:693d6ed92a6566e78802c7a03c256cda33d08c63ad3f00fcfa11379b184b9462"
+            ],
+            "index": "pypi",
+            "version": "==2.4"
+        },
         "six": {
             "hashes": [
                 "sha256:0ff78c403d9bccf5a425a6d31a12aa6b47f1c21ca4dc2573a7e2f32a97335eb1",
                 "sha256:105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a"
             ],
             "index": "pypi",
             "version": "==1.10.0"
         },
--- a/build/virtualenv_packages.txt
+++ b/build/virtualenv_packages.txt
@@ -9,17 +9,17 @@ mozilla.pth:python/l10n
 mozilla.pth:third_party/python/attrs/src
 mozilla.pth:third_party/python/blessings
 mozilla.pth:third_party/python/compare-locales
 mozilla.pth:third_party/python/configobj
 mozilla.pth:third_party/python/cram
 mozilla.pth:third_party/python/dlmanager
 mozilla.pth:third_party/python/fluent
 mozilla.pth:third_party/python/futures
-mozilla.pth:third_party/python/hglib
+mozilla.pth:third_party/python/python-hglib
 mozilla.pth:third_party/python/jsmin
 optional:setup.py:third_party/python/psutil:build_ext:--inplace
 mozilla.pth:third_party/python/psutil
 mozilla.pth:third_party/python/pylru
 mozilla.pth:third_party/python/which
 mozilla.pth:third_party/python/pystache
 mozilla.pth:third_party/python/pyyaml/lib
 mozilla.pth:third_party/python/requests
new file mode 100644
--- /dev/null
+++ b/third_party/python/py/.hgtags
@@ -0,0 +1,68 @@
+52c6d9e78777a5a34e813123997dfc614a1a4767 1.0.0b3
+1c7aaa8c61f3b0945921a9acc7beb184201aed4b 1.0.0b4
+1c7aaa8c61f3b0945921a9acc7beb184201aed4b 1.0.0b4
+0000000000000000000000000000000000000000 1.0.0b4
+0000000000000000000000000000000000000000 1.0.0b4
+8cd6eb91eba313b012d6e568f37d844dc0751f2e 1.0.0b4
+8cd6eb91eba313b012d6e568f37d844dc0751f2e 1.0.0b4
+0000000000000000000000000000000000000000 1.0.0b4
+2cc0507f117ffe721dff7ee026648cfce00ec92f 1.0.0b6
+86f1e1b6e49bf5882a809f11edd1dbb08162cdad 1.0.0b8
+86f1e1b6e49bf5882a809f11edd1dbb08162cdad 1.0.0b8
+c63f35c266cbb26dad6b87b5e115d65685adf448 1.0.0b8
+c63f35c266cbb26dad6b87b5e115d65685adf448 1.0.0b8
+0eaa0fdf2ba0163cf534dc2eff4ba2e5fc66c261 1.0.0b8
+e2a60653cb490aeed81bbbd83c070b99401c211c 1.0.0b9
+5ea0cdf7854c3d4278d36eda94a2b68483a0e211 1.0.0
+5ea0cdf7854c3d4278d36eda94a2b68483a0e211 1.0.0
+7acde360d94b6a2690ce3d03ff39301da84c0a2b 1.0.0
+6bd221981ac99103002c1cb94fede400d23a96a1 1.0.1
+4816e8b80602a3fd3a0a120333ad85fbe7d8bab4 1.0.2
+60c44bdbf093285dc69d5462d4dbb4acad325ca6 1.1.0
+319187fcda66714c5eb1353492babeec3d3c826f 1.1.1
+4fc5212f7626a56b9eb6437b5c673f56dd7eb942 1.2.0
+c143a8c8840a1c68570890c8ac6165bbf92fd3c6 1.2.1
+eafd3c256e8732dfb0a4d49d051b5b4339858926 1.3.0
+d5eacf390af74553227122b85e20345d47b2f9e6 1.3.1
+d5eacf390af74553227122b85e20345d47b2f9e6 1.3.1
+8b8e7c25a13cf863f01b2dd955978285ae9daf6a 1.3.1
+3bff44b188a7ec1af328d977b9d39b6757bb38df 1.3.2
+c59d3fa8681a5b5966b8375b16fccd64a3a8dbeb 1.3.3
+79ef6377705184c55633d456832eea318fedcf61 1.3.4
+79ef6377705184c55633d456832eea318fedcf61 1.3.4
+90fffd35373e9f125af233f78b19416f0938d841 1.3.4
+5346ab41b059c95a48cbe1e8a7bae96ce6e0da27 1.4.0
+1f3125cba7976538952be268f107c1d0c36c5ce8 1.4.1
+04ab22db4ff737cf31e91d75a0f5d7077f324167 1.4.2
+9950bf9d684a984d511795013421c89c5cf88bef 1.4.3
+d9951e3bdbc765e73835ae13012f6a074d13d8bf 1.4.4
+b827dd156a36753e32c7f3f15ce82d6fe9e356c8 1.4.6
+f15726f9e5a67cc6221c499affa4840e9d591763 1.4.7
+abfabd07a1d328f13c730e8a50d80d2e470afd3b 1.4.9
+7f37ee0aff9be4b839d6759cfee336f60e8393a4 1.4.10
+fe4593263efa10ea7ba014db6e3379e0b82368a2 1.4.11
+f07af25a26786e4825b5170e17ad693245cb3426 1.4.12
+d3730d84ba7eda92fd3469a3f63fd6d8cb22c975 1.4.13
+12c1ae8e7c5345721e9ec9f8e27b1e36c07f74dc 1.4.14
+12c1ae8e7c5345721e9ec9f8e27b1e36c07f74dc 1.4.14
+0000000000000000000000000000000000000000 1.4.14
+0000000000000000000000000000000000000000 1.4.14
+1497e2efd0f8c73a0e3d529debf0c489e4cd6cab 1.4.14
+e065014c1ce8ad110a381e9baaaa5d647ba7ac6b 1.4.15
+e9e5b38f53dc35b35aa1f9ee9a9be9bbd2d2c3b1 1.4.16
+c603503945f52b78522d96a423605cbc953236d3 1.4.17
+c59201105a29801cc858eb9160b7a19791b91a35 1.4.18
+284cc172e294d48edc840012e1451c32c3963d92 1.4.19
+a3e0626aa0c5aecf271367dc77e476ab216ea3c8 1.4.20
+5e48016c4a3af8e7358a1267d33d021e71765bed 1.4.21
+01ae2cfcc61c4fcb3aa5031349adb5b467c31018 1.4.23
+5ffd982f4dff60b588f309cd9bdc61036547282a 1.4.24
+dc9ffbcaf1f7d72e96be3f68c11deebb7e7193c5 1.4.25
+6de1a44bf75de7af4fcae947c235e9072bbdbb9a 1.4.26
+7d650ba2657890a2253c8c4a83f170febebd90fa 1.4.27
+7d650ba2657890a2253c8c4a83f170febebd90fa 1.4.27
+1810003dec63dd1b506a23849861fffa5bc3ba13 1.4.27
+ba08706f08ddea1b77a426f00dfe2bdc244345e8 1.4.28
+4e8054ada63f3327bcf759ae7cd36c7c8652bc9b 1.4.29
+366ab346610c6de8aaa7617e24011794b40236c6 1.4.30
+657380e439f9b7e04918cb162cb2e46388244b42 1.4.31
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/.hgignore
@@ -0,0 +1,12 @@
+syntax: glob
+
+dist
+MANIFEST
+MANIFEST.in
+*.pyc
+*.orig
+*.rej
+*~
+*.swp
+*.noseids
+build
rename from third_party/python/hglib/LICENSE
rename to third_party/python/python-hglib/LICENSE
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/Makefile
@@ -0,0 +1,17 @@
+PYTHON=python
+help:
+	@echo 'Commonly used make targets:'
+	@echo '  tests - run all tests in the automatic test suite'
+
+all: help
+
+.PHONY: tests
+
+MANIFEST.in:
+	hg manifest | sed -e 's/^/include /' > MANIFEST.in
+
+dist: MANIFEST.in
+	TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist
+
+tests:
+	$(PYTHON) test.py --with-doctest
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/PKG-INFO
@@ -0,0 +1,26 @@
+Metadata-Version: 1.1
+Name: python-hglib
+Version: 2.4
+Summary: Mercurial Python library
+Home-page: http://selenic.com/repo/python-hglib
+Author: Idan Kamara
+Author-email: idankk86@gmail.com
+License: MIT
+Description: python-hglib
+        ============
+        
+        python-hglib is a library with a fast, convenient interface to Mercurial.
+        It uses Mercurial's command server for communication with hg.
+        
+        Installation is standard:
+        
+          $ python setup.py install
+        
+Platform: UNKNOWN
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2.4
+Classifier: Programming Language :: Python :: 2.5
+Classifier: Programming Language :: Python :: 2.6
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/README
@@ -0,0 +1,9 @@
+python-hglib
+============
+
+python-hglib is a library with a fast, convenient interface to Mercurial.
+It uses Mercurial's command server for communication with hg.
+
+Installation is standard:
+
+  $ python setup.py install
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/examples/stats.py
@@ -0,0 +1,35 @@
+# stats - get stats on the given repo
+
+import sys
+import hglib
+
+# figure out what repo path to use
+repo = '.'
+if len(sys.argv) > 1:
+    repo = sys.argv[1]
+
+# connect to hg
+client = hglib.open(repo)
+
+# gather some stats
+revs = int(client.tip().rev)
+files = len(list(client.manifest()))
+heads = len(client.heads())
+branches = len(client.branches())
+tags = len(client.tags()) - 1 # don't count tip
+
+authors = {}
+for e in client.log():
+    authors[e.author] = True
+
+merges = 0
+for e in client.log(onlymerges=True):
+    merges += 1
+
+print "%d revisions" % revs
+print "%d merges" % merges
+print "%d files" % files
+print "%d heads" % heads
+print "%d branches" % branches
+print "%d tags" % tags
+print "%d authors" % len(authors)
rename from third_party/python/hglib/hglib/__init__.py
rename to third_party/python/python-hglib/hglib/__init__.py
rename from third_party/python/hglib/hglib/client.py
rename to third_party/python/python-hglib/hglib/client.py
rename from third_party/python/hglib/hglib/context.py
rename to third_party/python/python-hglib/hglib/context.py
rename from third_party/python/hglib/hglib/error.py
rename to third_party/python/python-hglib/hglib/error.py
rename from third_party/python/hglib/hglib/merge.py
rename to third_party/python/python-hglib/hglib/merge.py
rename from third_party/python/hglib/hglib/templates.py
rename to third_party/python/python-hglib/hglib/templates.py
rename from third_party/python/hglib/hglib/util.py
rename to third_party/python/python-hglib/hglib/util.py
rename from third_party/python/hglib/setup.py
rename to third_party/python/python-hglib/setup.py
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/test.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+import nose
+from tests import with_hg
+
+if __name__ == '__main__':
+    nose.main(addplugins=[with_hg.WithHgPlugin()])
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/__init__.py
@@ -0,0 +1,22 @@
+import os, tempfile, sys, shutil
+
+def setUp():
+    os.environ['LANG'] = os.environ['LC_ALL'] = os.environ['LANGUAGE'] = 'C'
+    os.environ["EMAIL"] = "Foo Bar <foo.bar@example.com>"
+    os.environ['CDPATH'] = ''
+    os.environ['COLUMNS'] = '80'
+    os.environ['GREP_OPTIONS'] = ''
+    os.environ['http_proxy'] = ''
+
+    os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
+    os.environ["HGMERGE"] = "internal:merge"
+    os.environ["HGUSER"]   = "test"
+    os.environ["HGENCODING"] = "ascii"
+    os.environ["HGENCODINGMODE"] = "strict"
+    tmpdir = tempfile.mkdtemp('', 'python-hglib.')
+    os.environ["HGTMP"] = os.path.realpath(tmpdir)
+    os.environ["HGRCPATH"] = os.pathsep
+
+def tearDown(self):
+    os.chdir('..')
+    shutil.rmtree(os.environ["HGTMP"])
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/common.py
@@ -0,0 +1,49 @@
+import os, sys, tempfile, shutil
+import unittest
+
+import hglib
+from hglib import client
+
+def resultappender(list):
+    def decorator(f):
+        def decorated(*args, **kwargs):
+            list.append(args[0])
+            return f(*args, **kwargs)
+        return decorated
+    return decorator
+
+class basetest(unittest.TestCase):
+    def setUp(self):
+        self._testtmp = os.environ["TESTTMP"] = os.environ["HOME"] = \
+            os.path.join(os.environ["HGTMP"], self.__class__.__name__)
+
+        self.clients = []
+        self._oldopen = hglib.client.hgclient.open
+        # hglib.open = resultappender(self.clients)(hglib.open)
+        c = hglib.client.hgclient
+        c.open = resultappender(self.clients)(c.open)
+
+        os.mkdir(self._testtmp)
+        os.chdir(self._testtmp)
+        # until we can run norepo commands in the cmdserver
+        os.system('hg init')
+        self.client = hglib.open()
+
+    def tearDown(self):
+        # on Windows we cannot rmtree before closing all instances
+        # because of used files
+        hglib.client.hgclient.open = self._oldopen
+        for client in self.clients:
+            if client.server is not None:
+                client.close()
+        os.chdir('..')
+        try:
+            shutil.rmtree(self._testtmp)
+        except AttributeError:
+            pass # if our setUp was overriden
+
+    def append(self, path, *args):
+        f = open(path, 'ab')
+        for a in args:
+            f.write(a.encode('latin-1'))
+        f.close()
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-annotate.py
@@ -0,0 +1,32 @@
+from tests import common
+from hglib.util import b
+
+class test_annotate(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a\n')
+        rev, node0 = self.client.commit(b('first'), addremove=True)
+        self.append('a', 'a\n')
+        rev, node1 = self.client.commit(b('second'))
+
+        self.assertEquals(list(self.client.annotate(b('a'))),
+                          [(b('0'), b('a')), (b('1'), b('a'))])
+        self.assertEquals(list(
+            self.client.annotate(
+                b('a'), user=True, file=True,
+                number=True, changeset=True, line=True, verbose=True)),
+                          [(b('test 0 ') + node0[:12] + b(' a:1'), b('a')),
+                           (b('test 1 ') + node1[:12] + b(' a:2'), b('a'))])
+
+    def test_files(self):
+        self.append('a', 'a\n')
+        rev, node0 = self.client.commit(b('first'), addremove=True)
+        self.append('b', 'b\n')
+        rev, node1 = self.client.commit(b('second'), addremove=True)
+        self.assertEquals(list(self.client.annotate([b('a'), b('b')])),
+                          [(b('0'), b('a')), (b('1'), b('b'))])
+
+    def test_two_colons(self):
+        self.append('a', 'a: b\n')
+        self.client.commit(b('first'), addremove=True)
+        self.assertEquals(list(self.client.annotate(b('a'))),
+                          [(b('0'), b('a: b'))])
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-bookmarks.py
@@ -0,0 +1,26 @@
+from tests import common
+from hglib.util import b
+
+class test_bookmarks(common.basetest):
+    def test_empty(self):
+        self.assertEquals(self.client.bookmarks(), ([], -1))
+
+    def test_basic(self):
+        self.append('a', 'a')
+        rev0, node0 = self.client.commit(b('first'), addremove=True)
+        self.append('a', 'a')
+        rev1, node1 = self.client.commit(b('second'))
+
+        self.client.bookmark(b('zero'), rev0)
+        self.assertEquals(self.client.bookmarks(),
+                          ([(b('zero'), rev0, node0[:12])], -1))
+
+        self.client.bookmark(b('one'), rev1)
+        self.assertEquals(self.client.bookmarks()[0],
+                          [(b('one'), rev1, node1[:12]),
+                           (b('zero'), rev0, node0[:12])])
+
+    #def test_spaces(self):
+    #    self.client.bookmark('s pace', self.rev0)
+    #    self.assertEquals(self.client.bookmarks(),
+    #                      ([('s pace', 0, self.rev0.node[:12])], -1))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-branch.py
@@ -0,0 +1,46 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_branch(common.basetest):
+    def test_empty(self):
+        self.assertEquals(self.client.branch(), b('default'))
+
+    def test_basic(self):
+        self.assertEquals(self.client.branch(b('foo')), b('foo'))
+        self.append('a', 'a')
+        rev, node = self.client.commit(b('first'), addremove=True)
+
+        rev = self.client.log(node)[0]
+
+        self.assertEquals(rev.branch, b('foo'))
+        self.assertEquals(self.client.branches(),
+                          [(rev.branch, int(rev.rev), rev.node[:12])])
+
+    def test_reset_with_name(self):
+        self.assertRaises(ValueError, self.client.branch, b('foo'), clean=True)
+
+    def test_reset(self):
+        self.client.branch(b('foo'))
+        self.assertEquals(self.client.branch(clean=True), b('default'))
+
+    def test_exists(self):
+        self.append('a', 'a')
+        self.client.commit(b('first'), addremove=True)
+        self.client.branch(b('foo'))
+        self.append('a', 'a')
+        self.client.commit(b('second'))
+        self.assertRaises(hglib.error.CommandError,
+                          self.client.branch, b('default'))
+
+    def test_force(self):
+        self.append('a', 'a')
+        self.client.commit(b('first'), addremove=True)
+        self.client.branch(b('foo'))
+        self.append('a', 'a')
+        self.client.commit(b('second'))
+
+        self.assertRaises(hglib.error.CommandError,
+                          self.client.branch, b('default'))
+        self.assertEquals(self.client.branch(b('default'), force=True),
+                          b('default'))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-branches.py
@@ -0,0 +1,25 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_branches(common.basetest):
+    def test_empty(self):
+        self.assertEquals(self.client.branches(), [])
+
+    def test_basic(self):
+        self.append('a', 'a')
+        rev0 = self.client.commit(b('first'), addremove=True)
+        self.client.branch(b('foo'))
+        self.append('a', 'a')
+        rev1 = self.client.commit(b('second'))
+        branches = self.client.branches()
+
+        expected = []
+        for r, n in (rev1, rev0):
+            r = self.client.log(r)[0]
+            expected.append((r.branch, int(r.rev), r.node[:12]))
+
+        self.assertEquals(branches, expected)
+
+    def test_active_closed(self):
+        pass
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-bundle.py
@@ -0,0 +1,18 @@
+from tests import common
+from hglib.util import b
+
+class test_bundle(common.basetest):
+    def test_no_changes(self):
+        self.append('a', 'a')
+        rev, node0 = self.client.commit(b('first'), addremove=True)
+        self.assertFalse(self.client.bundle(b('bundle'), destrepo=b('.')))
+
+    def test_basic(self):
+        self.append('a', 'a')
+        rev, node0 = self.client.commit(b('first'), addremove=True)
+        self.client.clone(dest=b('other'))
+
+        self.append('a', 'a')
+        rev, node1 = self.client.commit(b('second'))
+
+        self.assertTrue(self.client.bundle(b('bundle'), destrepo=b('other')))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-commit.py
@@ -0,0 +1,62 @@
+from tests import common
+import hglib, datetime
+from hglib.util import b
+
+class test_commit(common.basetest):
+    def test_user(self):
+        self.append('a', 'a')
+        rev, node = self.client.commit(b('first'), addremove=True,
+                                       user=b('foo'))
+        rev = self.client.log(node)[0]
+        self.assertEquals(rev.author, b('foo'))
+
+    def test_no_user(self):
+        self.append('a', 'a')
+        self.assertRaises(hglib.error.CommandError,
+                          self.client.commit, b('first'), user=b(''))
+
+    def test_close_branch(self):
+        self.append('a', 'a')
+        rev0, node0 = self.client.commit(b('first'), addremove=True)
+        self.client.branch(b('foo'))
+        self.append('a', 'a')
+        rev1, node1 = self.client.commit(b('second'))
+        revclose = self.client.commit(b('closing foo'), closebranch=True)
+        rev0, rev1, revclose = self.client.log([node0, node1, revclose[1]])
+
+        self.assertEquals(self.client.branches(),
+                          [(rev0.branch, int(rev0.rev), rev0.node[:12])])
+
+        self.assertEquals(self.client.branches(closed=True),
+                          [(revclose.branch, int(revclose.rev),
+                            revclose.node[:12]),
+                           (rev0.branch, int(rev0.rev), rev0.node[:12])])
+
+    def test_message_logfile(self):
+        self.assertRaises(ValueError, self.client.commit, b('foo'),
+                          logfile=b('bar'))
+        self.assertRaises(ValueError, self.client.commit)
+
+    def test_date(self):
+        self.append('a', 'a')
+        now = datetime.datetime.now().replace(microsecond=0)
+        rev0, node0 = self.client.commit(
+            b('first'), addremove=True,
+            date=now.isoformat(' ').encode('latin-1'))
+
+        self.assertEquals(now, self.client.tip().date)
+
+    def test_amend(self):
+        self.append('a', 'a')
+        now = datetime.datetime.now().replace(microsecond=0)
+        rev0, node0 = self.client.commit(
+            b('first'), addremove=True,
+            date=now.isoformat(' ').encode('latin-1'))
+
+        self.assertEquals(now, self.client.tip().date)
+
+        self.append('a', 'a')
+        rev1, node1 = self.client.commit(amend=True)
+        self.assertEquals(now, self.client.tip().date)
+        self.assertNotEquals(node0, node1)
+        self.assertEqual(1, len(self.client.log()))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-config.py
@@ -0,0 +1,37 @@
+from tests import common
+import os, hglib
+from hglib.util import b
+
+class test_config(common.basetest):
+    def setUp(self):
+        common.basetest.setUp(self)
+        f = open('.hg/hgrc', 'a')
+        f.write('[section]\nkey=value\n')
+        f.close()
+        self.client = hglib.open()
+
+    def test_basic(self):
+        config = self.client.config()
+
+        self.assertTrue(
+                (b('section'), b('key'), b('value')) in self.client.config())
+
+        self.assertTrue([(b('section'), b('key'), b('value'))],
+                        self.client.config(b('section')))
+        self.assertTrue([(b('section'), b('key'), b('value'))],
+                        self.client.config([b('section'), b('foo')]))
+        self.assertRaises(hglib.error.CommandError,
+                          self.client.config, [b('a.b'), b('foo')])
+
+    def test_show_source(self):
+        config = self.client.config(showsource=True)
+
+        self.assertTrue((os.path.abspath(b('.hg/hgrc')) + b(':2'),
+                         b('section'), b('key'), b('value')) in config)
+
+class test_config_arguments(common.basetest):
+    def test_basic(self):
+        client = hglib.open(configs=[b('diff.unified=5'), b('a.b=foo')])
+        self.assertEqual(client.config(b('a')), [(b('a'), b('b'), b('foo'))])
+        self.assertEqual(client.config(b('diff')),
+                         [(b('diff'), b('unified'), b('5'))])
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-copy.py
@@ -0,0 +1,23 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_copy(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a')
+        self.client.commit(b('first'), addremove=True)
+
+        self.assertTrue(self.client.copy(b('a'), b('b')))
+        self.assertEquals(self.client.status(), [(b('A'), b('b'))])
+        self.append('c', 'a')
+        self.assertTrue(self.client.copy(b('a'), b('c'), after=True))
+        self.assertEquals(self.client.status(),
+                          [(b('A'), b('b')), (b('A'), b('c'))])
+
+    # hg returns 0 even if there were warnings
+    #def test_warnings(self):
+    #    self.append('a', 'a')
+    #    self.client.commit('first', addremove=True)
+
+    #    self.assertTrue(self.client.copy('a', 'b'))
+    #    self.assertFalse(self.client.copy('a', 'b'))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-diff.py
@@ -0,0 +1,47 @@
+from tests import common
+from hglib.util import b
+
+class test_diff(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a\n')
+        self.client.add(b('a'))
+        diff1 = b("""diff -r 000000000000 a
+--- /dev/null
++++ b/a
+@@ -0,0 +1,1 @@
++a
+""")
+        self.assertEquals(diff1, self.client.diff(nodates=True))
+        self.assertEquals(diff1, self.client.diff([b('a')], nodates=True))
+        rev0, node0 = self.client.commit(b('first'))
+        diff2 = b("""diff -r 000000000000 -r """) + node0[:12] + b(""" a
+--- /dev/null
++++ b/a
+@@ -0,0 +1,1 @@
++a
+""")
+        self.assertEquals(diff2, self.client.diff(change=rev0, nodates=True))
+        self.append('a', 'a\n')
+        rev1, node1 = self.client.commit(b('second'))
+        diff3 = b("""diff -r """) + node0[:12] + b(""" a
+--- a/a
++++ b/a
+@@ -1,1 +1,2 @@
+ a
++a
+""")
+        self.assertEquals(diff3, self.client.diff(revs=[rev0], nodates=True))
+        diff4 = b("""diff -r """) + node0[:12] + b(" -r ") + node1[:12] + b(
+            """ a
+--- a/a
++++ b/a
+@@ -1,1 +1,2 @@
+ a
++a
+""")
+        self.assertEquals(diff4, self.client.diff(revs=[rev0, rev1],
+                                                  nodates=True))
+
+    def test_basic_plain(self):
+        open('.hg/hgrc', 'a').write('[defaults]\ndiff=--git\n')
+        self.test_basic()
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-encoding.py
@@ -0,0 +1,8 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_encoding(common.basetest):
+    def test_basic(self):
+        self.client = hglib.open(encoding='utf-8')
+        self.assertEquals(self.client.encoding, b('utf-8'))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-forget.py
@@ -0,0 +1,14 @@
+from tests import common
+from hglib.util import b
+
+class test_forget(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a')
+        self.client.add([b('a')])
+        self.assertTrue(self.client.forget(b('a')))
+
+    def test_warnings(self):
+        self.assertFalse(self.client.forget(b('a')))
+        self.append('a', 'a')
+        self.client.add([b('a')])
+        self.assertFalse(self.client.forget([b('a'), b('b')]))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-grep.py
@@ -0,0 +1,45 @@
+from tests import common
+from hglib.util import b
+
+class test_grep(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a\n')
+        self.append('b', 'ab\n')
+        self.client.commit(b('first'), addremove=True)
+
+        # no match
+        self.assertEquals(list(self.client.grep(b('c'))), [])
+
+        self.assertEquals(list(self.client.grep(b('a'))),
+                          [(b('a'), b('0'), b('a')), (b('b'), b('0'), b('ab'))])
+        self.assertEquals(list(self.client.grep(b('a'), b('a'))),
+                          [(b('a'), b('0'), b('a'))])
+
+        self.assertEquals(list(self.client.grep(b('b'))),
+                          [(b('b'), b('0'), b('ab'))])
+
+    def test_options(self):
+        self.append('a', 'a\n')
+        self.append('b', 'ab\n')
+        rev, node = self.client.commit(b('first'), addremove=True)
+
+        self.assertEquals([(b('a'), b('0'), b('+'), b('a')),
+                           (b('b'), b('0'), b('+'), b('ab'))],
+                          list(self.client.grep(b('a'), all=True)))
+
+        self.assertEquals([(b('a'), b('0')), (b('b'), b('0'))],
+                          list(self.client.grep(b('a'), fileswithmatches=True)))
+
+        self.assertEquals([(b('a'), b('0'), b('1'), b('a')),
+                           (b('b'), b('0'), b('1'), b('ab'))],
+                          list(self.client.grep(b('a'), line=True)))
+
+        self.assertEquals([(b('a'), b('0'), b('test'), b('a')),
+                           (b('b'), b('0'), b('test'), b('ab'))],
+                          list(self.client.grep(b('a'), user=True)))
+
+        self.assertEquals([(b('a'), b('0'), b('1'), b('+'), b('test')),
+                           (b('b'), b('0'), b('1'), b('+'), b('test'))],
+                          list(self.client.grep(b('a'), all=True, user=True,
+                                                line=True,
+                                                fileswithmatches=True)))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-heads.py
@@ -0,0 +1,17 @@
+from tests import common
+from hglib.util import b
+
+class test_heads(common.basetest):
+    def test_empty(self):
+        self.assertEquals(self.client.heads(), [])
+
+    def test_basic(self):
+        self.append('a', 'a')
+        rev, node0 = self.client.commit(b('first'), addremove=True)
+        self.assertEquals(self.client.heads(), [self.client.tip()])
+
+        self.client.branch(b('foo'))
+        self.append('a', 'a')
+        rev, node1 = self.client.commit(b('second'))
+
+        self.assertEquals(self.client.heads(node0, topological=True), [])
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-hglib.py
@@ -0,0 +1,25 @@
+from tests import common
+import hglib
+
+class test_hglib(common.basetest):
+    def setUp(self):
+        pass
+
+    def test_close_fds(self):
+        """A weird Python bug that has something to do to inherited file
+        descriptors, see http://bugs.python.org/issue12786
+        """
+        common.basetest.setUp(self)
+        client2 = hglib.open()
+        self.client.close()
+
+    def test_open_nonexistent(self):
+        # setup stuff necessary for basetest.tearDown()
+        self.clients = []
+        self._oldopen = hglib.client.hgclient.open
+        try:
+            self.clients.append(hglib.open('inexistent'))
+            # hg 3.5 can't report error (fixed by 7332bf4ae959)
+            #self.fail('ServerError not raised')
+        except hglib.error.ServerError as inst:
+            self.assertTrue('inexistent' in str(inst))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-import.py
@@ -0,0 +1,38 @@
+import os
+from tests import common
+from hglib.util import b, BytesIO
+
+patch = b("""
+# HG changeset patch
+# User test
+# Date 0 0
+# Node ID c103a3dec114d882c98382d684d8af798d09d857
+# Parent  0000000000000000000000000000000000000000
+1
+
+diff -r 000000000000 -r c103a3dec114 a
+--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
++++ b/a	Thu Jan 01 00:00:00 1970 +0000
+@@ -0,0 +1,1 @@
++1
+""")
+
+class test_import(common.basetest):
+    def test_basic_cstringio(self):
+        self.client.import_(BytesIO(patch))
+        self.assertEquals(self.client.cat([b('a')]), b('1\n'))
+
+    def test_basic_file(self):
+        f = open('patch', 'wb')
+        f.write(patch)
+        f.close()
+
+        # --no-commit
+        self.client.import_([b('patch')], nocommit=True)
+        self.assertEquals(open('a').read(), '1\n')
+
+        self.client.update(clean=True)
+        os.remove('a')
+
+        self.client.import_([b('patch')])
+        self.assertEquals(self.client.cat([b('a')]), b('1\n'))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-init.py
@@ -0,0 +1,15 @@
+from tests import common
+import hglib, shutil
+from hglib.util import b
+
+class test_init(common.basetest):
+    def test_exists(self):
+        self.assertRaises(hglib.error.CommandError, hglib.init)
+
+    def test_basic(self):
+        self.client.close()
+        self.client = None
+        shutil.rmtree('.hg')
+
+        self.client = hglib.init().open()
+        self.assertTrue(self.client.root().endswith(b('test_init')))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-log.py
@@ -0,0 +1,30 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_log(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a')
+        rev0, node0 = self.client.commit(b('first'), addremove=True)
+        self.append('a', 'a')
+        rev1, node1 = self.client.commit(b('second'))
+
+        revs = self.client.log()
+        revs.reverse()
+
+        self.assertTrue(len(revs) == 2)
+        self.assertEquals(revs[1].node, node1)
+
+        self.assertEquals(revs[0], self.client.log(b('0'))[0])
+        self.assertEquals(self.client.log(), self.client.log(files=[b('a')]))
+
+        self.assertEquals(self.client.log(), self.client.log(hidden=True))
+
+    # def test_errors(self):
+    #     self.assertRaisesRegexp(CommandError, 'abort: unknown revision',
+    #                             self.client.log, 'foo')
+    #     self.append('a', 'a')
+    #     self.client.commit('first', addremove=True)
+    #     self.assertRaisesRegexp(CommandError,
+    #                             'abort: unknown revision',
+    #                             self.client.log, 'bar')
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-manifest.py
@@ -0,0 +1,27 @@
+from tests import common
+import hglib, os, stat
+from hglib.util import b
+
+class test_manifest(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a')
+        files = [b('a')]
+        manifest = [(b('047b75c6d7a3ef6a2243bd0e99f94f6ea6683597'), b('644'),
+                     False, False, b('a'))]
+
+        if os.name == 'posix':
+            self.append('b', 'b')
+            os.chmod('b', os.stat('b')[0] | stat.S_IEXEC)
+            os.symlink('b', 'c')
+
+            files.extend([b('b'), b('c')])
+            manifest.extend([(b('62452855512f5b81522aa3895892760bb8da9f3f'),
+                              b('755'), True, False, b('b')),
+                             (b('62452855512f5b81522aa3895892760bb8da9f3f'),
+                              b('644'), False, True, b('c'))])
+
+        self.client.commit(b('first'), addremove=True)
+
+        self.assertEquals(list(self.client.manifest(all=True)), files)
+
+        self.assertEquals(list(self.client.manifest()), manifest)
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-merge.py
@@ -0,0 +1,78 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_merge(common.basetest):
+    def setUp(self):
+        common.basetest.setUp(self)
+
+        self.append('a', 'a')
+        rev, self.node0 = self.client.commit(b('first'), addremove=True)
+
+        self.append('a', 'a')
+        rev, self.node1 = self.client.commit(b('change'))
+
+    def test_basic(self):
+        self.client.update(self.node0)
+        self.append('b', 'a')
+        rev, node2 = self.client.commit(b('new file'), addremove=True)
+        self.client.merge(self.node1)
+        rev, node = self.client.commit(b('merge'))
+        diff = b("diff -r ") + node2[:12] + b(" -r ") + node[:12] + b(""" a
+--- a/a
++++ b/a
+@@ -1,1 +1,1 @@
+-a
+\ No newline at end of file
++aa
+\ No newline at end of file
+""")
+
+        self.assertEquals(diff, self.client.diff(change=node, nodates=True))
+
+    def test_merge_prompt_abort(self):
+        self.client.update(self.node0)
+        self.client.remove(b('a'))
+        self.client.commit(b('remove'))
+
+        self.assertRaises(hglib.error.CommandError, self.client.merge)
+
+    def test_merge_prompt_noninteractive(self):
+        self.client.update(self.node0)
+        self.client.remove(b('a'))
+        rev, node = self.client.commit(b('remove'))
+
+        if self.client.version >= (3, 7):
+            self.assertRaises(hglib.error.CommandError,
+                self.client.merge,
+                cb=hglib.merge.handlers.noninteractive)
+        else:
+            self.client.merge(cb=hglib.merge.handlers.noninteractive)
+
+        diff = b("diff -r ") + node[:12] + b(""" a
+--- /dev/null
++++ b/a
+@@ -0,0 +1,1 @@
++aa
+\ No newline at end of file
+""")
+        self.assertEquals(diff, self.client.diff(nodates=True))
+
+    def test_merge_prompt_cb(self):
+        self.client.update(self.node0)
+        self.client.remove(b('a'))
+        rev, node = self.client.commit(b('remove'))
+
+        def cb(output):
+            return b('c')
+
+        self.client.merge(cb=cb)
+
+        diff = b("diff -r ") + node[:12] + b(""" a
+--- /dev/null
++++ b/a
+@@ -0,0 +1,1 @@
++aa
+\ No newline at end of file
+""")
+        self.assertEquals(diff, self.client.diff(nodates=True))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-move.py
@@ -0,0 +1,16 @@
+import os
+from tests import common
+from hglib.util import b
+
+class test_move(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a')
+        self.client.add(b('a'))
+        self.assertTrue(self.client.move(b('a'), b('b')))
+
+    # hg returns 0 even if there were warnings
+    #def test_warnings(self):
+    #    self.append('a', 'a')
+    #    self.client.add('a')
+    #    os.mkdir('c')
+    #    self.assertFalse(self.client.move(['a', 'b'], 'c'))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-outgoing-incoming.py
@@ -0,0 +1,53 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_outgoing_incoming(common.basetest):
+    def test_no_path(self):
+        self.assertRaises(hglib.error.CommandError, self.client.incoming)
+
+    def test_empty(self):
+        self.client.clone(dest=b('other'))
+        self.other = hglib.open(b('other'))
+
+        self.assertEquals(self.other.incoming(), [])
+        self.assertEquals(self.other.outgoing(), [])
+
+    def test_basic(self):
+        self.append('a', 'a')
+        self.client.commit(b('first'), addremove=True)
+        self.append('a', 'a')
+        self.client.commit(b('second'))
+
+        self.client.clone(dest=b('other'))
+        other = hglib.open(b('other'))
+
+        self.assertEquals(self.client.log(), other.log())
+        self.assertEquals(self.client.outgoing(path=b('other')),
+                          other.incoming())
+
+        self.append('a', 'a')
+        rev, node = self.client.commit(b('third'))
+        out = self.client.outgoing(path=b('other'))
+
+        self.assertEquals(len(out), 1)
+        self.assertEquals(out[0].node, node)
+
+        self.assertEquals(out, other.incoming())
+
+    def test_bookmarks(self):
+        self.append('a', 'a')
+        self.client.commit(b('first'), addremove=True)
+        self.append('a', 'a')
+        self.client.commit(b('second'))
+
+        self.client.clone(dest=b('other'))
+        other = hglib.open(b('other'))
+
+        self.client.bookmark(b('bm1'), 1)
+
+        self.assertEquals(other.incoming(bookmarks=True),
+                          [(b('bm1'), self.client.tip().node[:12])])
+
+        self.assertEquals(self.client.outgoing(path=b('other'), bookmarks=True),
+                          [(b('bm1'), self.client.tip().node[:12])])
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-parents.py
@@ -0,0 +1,15 @@
+from tests import common
+from hglib.util import b
+
+class test_parents(common.basetest):
+    def test_noparents(self):
+        self.assertEquals(self.client.parents(), None)
+
+    def test_basic(self):
+        self.append('a', 'a')
+        rev, node = self.client.commit(b('first'), addremove=True)
+        self.assertEquals(node, self.client.parents()[0].node)
+        self.assertEquals(node, self.client.parents(file=b('a'))[0].node)
+
+    def test_two_parents(self):
+        pass
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-paths.py
@@ -0,0 +1,19 @@
+import os
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_paths(common.basetest):
+    def test_basic(self):
+        f = open('.hg/hgrc', 'a')
+        f.write('[paths]\nfoo = bar\n')
+        f.close()
+
+        # hgrc isn't watched for changes yet, have to reopen
+        self.client = hglib.open()
+        paths = self.client.paths()
+        self.assertEquals(len(paths), 1)
+        self.assertEquals(paths[b('foo')],
+                          os.path.abspath('bar').encode('latin-1'))
+        self.assertEquals(self.client.paths(b('foo')),
+                          os.path.abspath('bar').encode('latin-1'))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-pull.py
@@ -0,0 +1,31 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_pull(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a')
+        self.client.commit(b('first'), addremove=True)
+
+        self.client.clone(dest=b('other'))
+        other = hglib.open(b('other'))
+
+        self.append('a', 'a')
+        self.client.commit(b('second'))
+
+        self.assertTrue(other.pull())
+        self.assertEquals(self.client.log(), other.log())
+
+    def test_unresolved(self):
+        self.append('a', 'a')
+        self.client.commit(b('first'), addremove=True)
+
+        self.client.clone(dest=b('other'))
+        other = hglib.open(b('other'))
+
+        self.append('a', 'a')
+        self.client.commit(b('second'))
+
+        self.append('other/a', 'b')
+        self.assertFalse(other.pull(update=True))
+        self.assertTrue((b('M'), b('a')) in other.status())
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-push.py
@@ -0,0 +1,20 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_push(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a')
+        self.client.commit(b('first'), addremove=True)
+
+        self.client.clone(dest=b('other'))
+        other = hglib.open(b('other'))
+
+        # broken in hg, doesn't return 1 if nothing to push
+        #self.assertFalse(self.client.push('other'))
+
+        self.append('a', 'a')
+        self.client.commit(b('second'))
+
+        self.assertTrue(self.client.push(b('other')))
+        self.assertEquals(self.client.log(), other.log())
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-remove.py
@@ -0,0 +1,13 @@
+from tests import common
+from hglib.util import b
+
+class test_remove(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a')
+        self.client.commit(b('first'), addremove=True)
+        self.assertTrue(self.client.remove([b('a')]))
+
+    def test_warnings(self):
+        self.append('a', 'a')
+        self.client.commit(b('first'), addremove=True)
+        self.assertFalse(self.client.remove([b('a'), b('b')]))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-resolve.py
@@ -0,0 +1,33 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_resolve(common.basetest):
+    def setUp(self):
+        common.basetest.setUp(self)
+
+        self.append('a', 'a')
+        self.append('b', 'b')
+        rev, self.node0 = self.client.commit(b('first'), addremove=True)
+
+        self.append('a', 'a')
+        self.append('b', 'b')
+        rev, self.node1 = self.client.commit(b('second'))
+
+    def test_basic(self):
+        self.client.update(self.node0)
+        self.append('a', 'b')
+        self.append('b', 'a')
+        rev, self.node3 = self.client.commit(b('third'))
+
+        self.assertRaises(hglib.error.CommandError, self.client.merge,
+                          self.node1)
+        self.assertRaises(hglib.error.CommandError,
+                          self.client.resolve, all=True)
+
+        self.assertEquals([(b('U'), b('a')), (b('U'), b('b'))],
+                          self.client.resolve(listfiles=True))
+
+        self.client.resolve(b('a'), mark=True)
+        self.assertEquals([(b('R'), b('a')), (b('U'), b('b'))],
+                          self.client.resolve(listfiles=True))
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-status.py
@@ -0,0 +1,50 @@
+import os
+from tests import common
+from hglib.util import b
+
+class test_status(common.basetest):
+    def test_empty(self):
+        self.assertEquals(self.client.status(), [])
+
+    def test_one_of_each(self):
+        self.append('.hgignore', 'ignored')
+        self.append('ignored', 'a')
+        self.append('clean', 'a')
+        self.append('modified', 'a')
+        self.append('removed', 'a')
+        self.append('missing', 'a')
+        self.client.commit(b('first'), addremove=True)
+        self.append('modified', 'a')
+        self.append('added', 'a')
+        self.client.add([b('added')])
+        os.remove('missing')
+        self.client.remove([b('removed')])
+        self.append('untracked')
+
+        l = [(b('M'), b('modified')),
+             (b('A'), b('added')),
+             (b('R'), b('removed')),
+             (b('C'), b('.hgignore')),
+             (b('C'), b('clean')),
+             (b('!'), b('missing')),
+             (b('?'), b('untracked')),
+             (b('I'), b('ignored'))]
+
+        st = self.client.status(all=True)
+
+        for i in l:
+            self.assertTrue(i in st)
+
+    def test_copy(self):
+        self.append('source', 'a')
+        self.client.commit(b('first'), addremove=True)
+        self.client.copy(b('source'), b('dest'))
+        l = [(b('A'), b('dest')), (b(' '), b('source'))]
+        self.assertEquals(self.client.status(copies=True), l)
+
+    def test_copy_origin_space(self):
+        self.append('s ource', 'a')
+        self.client.commit(b('first'), addremove=True)
+        self.client.copy(b('s ource'), b('dest'))
+        l = [(b('A'), b('dest')), (b(' '), b('s ource'))]
+        self.assertEquals(self.client.status(copies=True), l)
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-summary.py
@@ -0,0 +1,125 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_summary(common.basetest):
+    def test_empty(self):
+        d = {b('parent') : [(-1, b('000000000000'), b('tip'), None)],
+             b('branch') : b('default'),
+             b('commit') : True,
+             b('update') : 0}
+
+        self.assertEquals(self.client.summary(), d)
+
+    def test_basic(self):
+        self.append('a', 'a')
+        rev, node = self.client.commit(b('first'), addremove=True)
+
+        d = {b('parent') : [(0, node[:12], b('tip'), b('first'))],
+             b('branch') : b('default'),
+             b('commit') : True,
+             b('update') : 0}
+        if self.client.version >= (3, 5):
+            d[b('phases')] = b('1 draft')
+
+        self.assertEquals(self.client.summary(), d)
+
+    def test_commit_dirty(self):
+        self.append('a', 'a')
+        rev, node = self.client.commit(b('first'), addremove=True)
+        self.append('a', 'a')
+
+        d = {b('parent') : [(0, node[:12], b('tip'), b('first'))],
+             b('branch') : b('default'),
+             b('commit') : False,
+             b('update') : 0}
+        if self.client.version >= (3, 5):
+            d[b('phases')] = b('1 draft')
+
+        self.assertEquals(self.client.summary(), d)
+
+    def test_update(self):
+        self.append('a', 'a')
+        rev, node = self.client.commit(b('first'), addremove=True)
+        self.append('a', 'a')
+        self.client.commit(b('second'))
+        self.client.update(0)
+
+        d = {b('parent') : [(0, node[:12], None, b('first'))],
+             b('branch') : b('default'),
+             b('commit') : True,
+             b('update') : 1}
+        if self.client.version >= (3, 5):
+            d[b('phases')] = b('2 draft')
+
+        self.assertEquals(self.client.summary(), d)
+
+    def test_remote(self):
+        self.append('a', 'a')
+        rev, node = self.client.commit(b('first'), addremove=True)
+
+        self.client.clone(dest=b('other'))
+        other = hglib.open('other')
+
+        d = {b('parent') : [(0, node[:12], b('tip'), b('first'))],
+             b('branch') : b('default'),
+             b('commit') : True,
+             b('update') : 0,
+             b('remote') : (0, 0, 0, 0)}
+
+        self.assertEquals(other.summary(remote=True), d)
+
+        self.append('a', 'a')
+        self.client.commit(b('second'))
+
+        d[b('remote')] = (1, 0, 0, 0)
+        self.assertEquals(other.summary(remote=True), d)
+
+        self.client.bookmark(b('bm'))
+        d[b('remote')] = (1, 1, 0, 0)
+        self.assertEquals(other.summary(remote=True), d)
+
+        other.bookmark(b('bmother'))
+        d[b('remote')] = (1, 1, 0, 1)
+        if self.client.version < (2, 0, 0):
+            d[b('parent')] = [(0, node[:12], b('tip bmother'), b('first'))]
+        else:
+            d[b('bookmarks')] = b('*bmother')
+        self.assertEquals(other.summary(remote=True), d)
+
+        self.append('other/a', 'a')
+        rev, node = other.commit(b('second in other'))
+
+        d[b('remote')] = (1, 1, 1, 1)
+        if self.client.version < (2, 0, 0):
+            tags = b('tip bmother')
+        else:
+            tags = b('tip')
+        d[b('parent')] = [(1, node[:12], tags, b('second in other'))]
+        if self.client.version >= (3, 5):
+            d[b('phases')] = b('1 draft')
+
+        self.assertEquals(other.summary(remote=True), d)
+
+    def test_two_parents(self):
+        self.append('a', 'a')
+        rev0, node = self.client.commit(b('first'), addremove=True)
+
+        self.append('a', 'a')
+        rev1, node1 = self.client.commit(b('second'))
+
+        self.client.update(rev0)
+        self.append('b', 'a')
+        rev2, node2 = self.client.commit(b('third'), addremove=True)
+
+        self.client.merge(rev1)
+
+        d = {b('parent') : [(2, node2[:12], b('tip'), b('third')),
+                         (1, node1[:12], None, b('second'))],
+             b('branch') : b('default'),
+             b('commit') : False,
+             b('update') : 0}
+        if self.client.version >= (3, 5):
+            d[b('phases')] = b('3 draft')
+
+        self.assertEquals(self.client.summary(), d)
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-tags.py
@@ -0,0 +1,21 @@
+from tests import common
+import hglib
+from hglib.util import b
+
+class test_tags(common.basetest):
+    def test_basic(self):
+        self.append('a', 'a')
+        rev, node = self.client.commit(b('first'), addremove=True)
+        self.client.tag(b('my tag'))
+        self.client.tag(b('local tag'), rev=rev, local=True)
+
+        # filecache that was introduced in 2.0 makes us see the local tag, for
+        # now we have to reconnect
+        if self.client.version < (2, 0, 0):
+            self.client = hglib.open()
+
+        tags = self.client.tags()
+        self.assertEquals(tags,
+                          [(b('tip'), 1, self.client.tip().node[:12], False),
+                           (b('my tag'), 0, node[:12], False),
+                           (b('local tag'), 0, node[:12], True)])
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/test-update.py
@@ -0,0 +1,102 @@
+from tests import common
+from hglib import error
+from hglib.util import b, strtobytes
+
+class test_update(common.basetest):
+    def setUp(self):
+        common.basetest.setUp(self)
+        self.append('a', 'a')
+        self.rev0, self.node0 = self.client.commit(b('first'), addremove=True)
+        self.append('a', 'a')
+        self.rev1, self.node1 = self.client.commit(b('second'))
+
+    def test_basic(self):
+        u, m, r, ur = self.client.update(self.rev0)
+        self.assertEquals(u, 1)
+        self.assertEquals(m, 0)
+        self.assertEquals(r, 0)
+        self.assertEquals(ur, 0)
+
+    def test_unresolved(self):
+        self.client.update(self.rev0)
+        self.append('a', 'b')
+        u, m, r, ur = self.client.update()
+        self.assertEquals(u, 0)
+        self.assertEquals(m, 0)
+        self.assertEquals(r, 0)
+        self.assertEquals(ur, 1)
+        self.assertTrue((b('M'), b('a')) in self.client.status())
+
+    def test_merge(self):
+        self.append('a', '\n\n\n\nb')
+        rev2, node2 = self.client.commit(b('third'))
+        self.append('a', 'b')
+        self.client.commit(b('fourth'))
+        self.client.update(rev2)
+        old = open('a').read()
+        f = open('a', 'wb')
+        f.write(b('a') + old.encode('latin-1'))
+        f.close()
+        u, m, r, ur = self.client.update()
+        self.assertEquals(u, 0)
+        self.assertEquals(m, 1)
+        self.assertEquals(r, 0)
+        self.assertEquals(ur, 0)
+        self.assertEquals(self.client.status(), [(b('M'), b('a'))])
+
+    def test_tip(self):
+        self.client.update(self.rev0)
+        u, m, r, ur = self.client.update()
+        self.assertEquals(u, 1)
+        self.assertEquals(self.client.parents()[0].node, self.node1)
+
+        self.client.update(self.rev0)
+        self.append('a', 'b')
+        rev2, node2 = self.client.commit(b('new head'))
+        self.client.update(self.rev0)
+
+        self.client.update()
+        self.assertEquals(self.client.parents()[0].node, node2)
+
+    def test_check_clean(self):
+        self.assertRaises(ValueError, self.client.update, clean=True,
+                          check=True)
+
+    def test_clean(self):
+        old = open('a').read()
+        self.append('a', 'b')
+        self.assertRaises(error.CommandError, self.client.update, check=True)
+
+        u, m, r, ur = self.client.update(clean=True)
+        self.assertEquals(u, 1)
+        self.assertEquals(old, open('a').read())
+
+    def test_basic_plain(self):
+        f = open('.hg/hgrc', 'a')
+        f.write('[defaults]\nupdate=-v\n')
+        f.close()
+        self.test_basic()
+
+    def disabled_largefiles(self):
+        # we don't run reposetup after a session has started, so this
+        # test is broken
+        import os
+        f = open('.hg/hgrc', 'a')
+        f.write('[extensions]\nlargefiles=\n')
+        f.close()
+        self.append('b', 'a')
+        try:
+            self.client.rawcommand([b('add'), b('b'), b('--large')])
+        except error.CommandError:
+            return
+
+        rev2, node2 = self.client.commit(b('third'))
+        # Go back to 0
+        self.client.rawcommand([b('update'), strtobytes(self.rev0)],
+                                # Keep the 'changed' version
+                               prompt=lambda s, d: 'c\n')
+        u, m, r, ur = self.client.update(rev2, clean=True)
+        self.assertEquals(u, 2)
+        self.assertEquals(m, 0)
+        self.assertEquals(r, 0)
+        self.assertEquals(ur, 0)
new file mode 100644
--- /dev/null
+++ b/third_party/python/python-hglib/tests/with_hg.py
@@ -0,0 +1,33 @@
+import os
+from nose.plugins import Plugin
+
+class WithHgPlugin(Plugin):
+    name = 'with-hg'
+    enabled = False
+
+    def options(self, parser, env):
+        Plugin.options(self, parser, env)
+        parser.add_option('--with-hg',
+                          action='store',
+                          type='string',
+                          metavar='HG',
+                          dest='with_hg',
+                          help='test using specified hg script.')
+
+    def configure(self, options, conf):
+        Plugin.configure(self, options, conf)
+        if options.with_hg:
+            self.enabled = True
+            self.hgpath = os.path.realpath(options.with_hg)
+
+    def begin(self):
+        import hglib
+
+        p = hglib.util.popen([self.hgpath, 'version'])
+        p.communicate()
+
+        if p.returncode:
+            raise ValueError("custom hg %r doesn't look like Mercurial"
+                             % self.hgpath)
+
+        hglib.HGPATH = self.hgpath