Bug 1463834 - vendored hglib, updated to python-hglib draft
authorSofia Carrillo <scarrillo@mozilla.com>
Thu, 31 May 2018 18:04:54 -0700
changeset 802554 5725472c79c2725c2925116ada8111e5d29e3822
parent 802528 42880a726964a0bd66e2f636931e8322eae86ef7
push id111906
push userbmo:scarrillo@mozilla.com
push dateFri, 01 Jun 2018 01:06:19 +0000
bugs1463834
milestone62.0a1
Bug 1463834 - vendored hglib, updated to python-hglib
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