Browse Source

New upstream version 0.19.6

Jelmer Vernooij 6 years ago
parent
commit
fc889588c6
11 changed files with 167 additions and 34 deletions
  1. 9 0
      .travis.yml
  2. 6 0
      AUTHORS
  3. 15 1
      NEWS
  4. 1 1
      PKG-INFO
  5. 1 1
      dulwich.egg-info/PKG-INFO
  6. 1 1
      dulwich/__init__.py
  7. 1 4
      dulwich/client.py
  8. 6 1
      dulwich/index.py
  9. 17 10
      dulwich/porcelain.py
  10. 109 14
      dulwich/tests/test_porcelain.py
  11. 1 1
      setup.py

+ 9 - 0
.travis.yml

@@ -22,6 +22,15 @@ matrix:
       env: TEST_REQUIRE=fastimport
     - python: 3.3
       env: TEST_REQUIRE=fastimport
+    - python: 3.7
+      env: TEST_REQUIRE=fastimport
+      dist: xenial
+      sudo: true
+    - python: 3.8-dev
+      env: TEST_REQUIRE=fastimport
+      dist: xenial
+      sudo: true
+      
 
 install:
   - travis_retry pip install -U pip coverage codecov flake8 $TEST_REQUIRE

+ 6 - 0
AUTHORS

@@ -138,5 +138,11 @@ Alistair Broomhead <alistair.broomhead@gmail.com>
 Marcel Schnirring <mschnirring@marcel-schnirring.de>
 Adam Bradley <adam_bradley@brown.edu>
 Filipp Frizzy <filipp.s.frizzy@gmail.com>
+Romain Keramitas <r.keramitas@gmail.com>
+semyon-slepov <semyon.slepov@schibsted.com>
+Daniel M. Capella <polyzen@users.noreply.github.com>
+grun <grunseid@gmail.com>
+Sylvia van Os <sylvia@hackerchick.me>
+Boris Feld <lothiraldan@gmail.com>
 
 If you contributed but are missing from this list, please send me an e-mail.

+ 15 - 1
NEWS

@@ -1,4 +1,18 @@
-0.19.5	2018-08-08
+0.19.6	2018-08-11
+
+ BUG FIXES
+
+  * Fix support for custom transport arguments in ``dulwich.porcelain.clone``.
+    (Semyon Slepov)
+
+  * Fix compatibility with Python 3.8 (Jelmer Vernooij, Daniel M. Capella)
+
+  * Fix some corner cases in ``path_to_tree_path``. (Romain Keramitas)
+
+  * Support paths as bytestrings in various places in ``dulwich.index``
+    (Jelmer Vernooij)
+
+0.19.5	2018-07-08
 
  IMPROVEMENTS
 

+ 1 - 1
PKG-INFO

@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: dulwich
-Version: 0.19.5
+Version: 0.19.6
 Summary: [![Build Status](https://travis-ci.org/dulwich/dulwich.png?branch=master)](https://travis-ci.org/dulwich/dulwich)
 [![Windows Build status](https://ci.appveyor.com/api/projects/status/mob7g4vnrfvvoweb?svg=true)](https://ci.appveyor.com/project/jelmer/dulwich/branch/master)
 

+ 1 - 1
dulwich.egg-info/PKG-INFO

@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: dulwich
-Version: 0.19.5
+Version: 0.19.6
 Summary: [![Build Status](https://travis-ci.org/dulwich/dulwich.png?branch=master)](https://travis-ci.org/dulwich/dulwich)
 [![Windows Build status](https://ci.appveyor.com/api/projects/status/mob7g4vnrfvvoweb?svg=true)](https://ci.appveyor.com/project/jelmer/dulwich/branch/master)
 

+ 1 - 1
dulwich/__init__.py

@@ -22,4 +22,4 @@
 
 """Python implementation of the Git file formats and protocols."""
 
-__version__ = (0, 19, 5)
+__version__ = (0, 19, 6)

+ 1 - 4
dulwich/client.py

@@ -54,10 +54,8 @@ except ImportError:
     from urllib.parse import unquote as urlunquote
 
 try:
-    import urllib2
     import urlparse
 except ImportError:
-    import urllib.request as urllib2
     import urllib.parse as urlparse
 
 import dulwich
@@ -1353,7 +1351,6 @@ class HttpGitClient(GitClient):
 
     @classmethod
     def from_parsedurl(cls, parsedurl, **kwargs):
-        auth, host = urllib2.splituser(parsedurl.netloc)
         password = parsedurl.password
         if password is not None:
             password = urlunquote(password)
@@ -1361,7 +1358,7 @@ class HttpGitClient(GitClient):
         if username is not None:
             username = urlunquote(username)
         # TODO(jelmer): This also strips the username
-        parsedurl = parsedurl._replace(netloc=host)
+        parsedurl = parsedurl._replace(netloc=parsedurl.hostname)
         return cls(urlparse.urlunparse(parsedurl),
                    password=password, username=username, **kwargs)
 

+ 6 - 1
dulwich/index.py

@@ -590,6 +590,10 @@ def read_submodule_head(path):
     """
     from dulwich.errors import NotGitRepository
     from dulwich.repo import Repo
+    # Repo currently expects a "str", so decode if necessary.
+    # TODO(jelmer): Perhaps move this into Repo() ?
+    if not isinstance(path, str):
+        path = path.decode(sys.getfilesystemencoding())
     try:
         repo = Repo(path)
     except NotGitRepository:
@@ -690,12 +694,13 @@ def index_entry_from_path(path, object_store=None):
         save new blobs in
     :return: An index entry
     """
+    assert isinstance(path, bytes)
     try:
         st = os.lstat(path)
         blob = blob_from_path_and_stat(path, st)
     except EnvironmentError as e:
         if e.errno == errno.EISDIR:
-            if os.path.exists(os.path.join(path, '.git')):
+            if os.path.exists(os.path.join(path, b'.git')):
                 head = read_submodule_head(path)
                 if head is None:
                     return None

+ 17 - 10
dulwich/porcelain.py

@@ -174,16 +174,21 @@ def open_repo_closing(path_or_repo):
 
 
 def path_to_tree_path(repopath, path):
-    """Convert a path to a path usable in e.g. an index.
+    """Convert a path to a path usable in an index, e.g. bytes and relative to
+    the repository root.
 
-    :param repo: Repository
-    :param path: A path
+    :param repopath: Repository path, absolute or relative to the cwd
+    :param path: A path, absolute or relative to the cwd
     :return: A path formatted for use in e.g. an index
     """
-    os.path.relpath(path, repopath)
-    if os.path.sep != '/':
-        path = path.replace(os.path.sep, '/')
-    return path.encode(sys.getfilesystemencoding())
+    if not isinstance(path, bytes):
+        path = path.encode(sys.getfilesystemencoding())
+    if not isinstance(repopath, bytes):
+        repopath = repopath.encode(sys.getfilesystemencoding())
+    treepath = os.path.relpath(path, repopath)
+    if treepath.startswith(b'..'):
+        raise ValueError('Path not in repo')
+    return treepath
 
 
 def archive(repo, committish=None, outstream=default_bytes_out_stream,
@@ -321,7 +326,9 @@ def clone(source, target=None, bare=False, checkout=None,
 
     reflog_message = b'clone: from ' + source.encode('utf-8')
     try:
-        fetch_result = fetch(r, source, origin, message=reflog_message)
+        fetch_result = fetch(
+            r, source, origin, errstream=errstream, message=reflog_message,
+            **kwargs)
         target_config = r.get_config()
         if not isinstance(source, bytes):
             source = source.encode(DEFAULT_ENCODING)
@@ -1188,10 +1195,10 @@ def check_ignore(repo, paths, no_index=False):
         index = r.open_index()
         ignore_manager = IgnoreFilterManager.from_repo(r)
         for path in paths:
-            if os.path.isabs(path):
-                path = os.path.relpath(path, r.path)
             if not no_index and path_to_tree_path(r.path, path) in index:
                 continue
+            if os.path.isabs(path):
+                path = os.path.relpath(path, r.path)
             if ignore_manager.is_ignored(path):
                 yield path
 

+ 109 - 14
dulwich/tests/test_porcelain.py

@@ -827,7 +827,7 @@ class StatusTests(PorcelainTestCase):
             results.staged)
         self.assertEqual([], results.unstaged)
 
-    def test_status(self):
+    def test_status_base(self):
         """Integration test for `status` functionality."""
 
         # Commit a dummy file then modify it
@@ -859,6 +859,41 @@ class StatusTests(PorcelainTestCase):
                          filename_add.encode('ascii'))
         self.assertEqual(results.unstaged, [b'foo'])
 
+    def test_status_all(self):
+        del_path = os.path.join(self.repo.path, 'foo')
+        mod_path = os.path.join(self.repo.path, 'bar')
+        add_path = os.path.join(self.repo.path, 'baz')
+        us_path = os.path.join(self.repo.path, 'blye')
+        ut_path = os.path.join(self.repo.path, 'blyat')
+        with open(del_path, 'w') as f:
+            f.write('origstuff')
+        with open(mod_path, 'w') as f:
+            f.write('origstuff')
+        with open(us_path, 'w') as f:
+            f.write('origstuff')
+        porcelain.add(repo=self.repo.path, paths=[del_path, mod_path, us_path])
+        porcelain.commit(repo=self.repo.path, message=b'test status',
+                         author=b'author <email>',
+                         committer=b'committer <email>')
+        porcelain.remove(self.repo.path, [del_path])
+        with open(add_path, 'w') as f:
+            f.write('origstuff')
+        with open(mod_path, 'w') as f:
+            f.write('more_origstuff')
+        with open(us_path, 'w') as f:
+            f.write('more_origstuff')
+        porcelain.add(repo=self.repo.path, paths=[add_path, mod_path])
+        with open(us_path, 'w') as f:
+            f.write('\norigstuff')
+        with open(ut_path, 'w') as f:
+            f.write('origstuff')
+        results = porcelain.status(self.repo.path)
+        self.assertDictEqual(
+            {'add': [b'baz'], 'delete': [b'foo'], 'modify': [b'bar']},
+            results.staged)
+        self.assertListEqual(results.unstaged, [b'blye'])
+        self.assertListEqual(results.untracked, ['blyat'])
+
     def test_get_tree_changes_add(self):
         """Unit test for get_tree_changes add."""
 
@@ -1283,27 +1318,48 @@ class CheckIgnoreTests(PorcelainTestCase):
 
     def test_check_ignored(self):
         with open(os.path.join(self.repo.path, '.gitignore'), 'w') as f:
-            f.write("foo")
-        with open(os.path.join(self.repo.path, 'foo'), 'w') as f:
-            f.write("BAR")
-        with open(os.path.join(self.repo.path, 'bar'), 'w') as f:
-            f.write("BAR")
+            f.write('foo')
+        foo_path = os.path.join(self.repo.path, 'foo')
+        with open(foo_path, 'w') as f:
+            f.write('BAR')
+        bar_path = os.path.join(self.repo.path, 'bar')
+        with open(bar_path, 'w') as f:
+            f.write('BAR')
         self.assertEqual(
             ['foo'],
-            list(porcelain.check_ignore(self.repo, ['foo'])))
-        self.assertEqual([], list(porcelain.check_ignore(self.repo, ['bar'])))
+            list(porcelain.check_ignore(self.repo, [foo_path])))
+        self.assertEqual(
+            [], list(porcelain.check_ignore(self.repo, [bar_path])))
 
-    def test_check_added(self):
-        with open(os.path.join(self.repo.path, 'foo'), 'w') as f:
-            f.write("BAR")
+    def test_check_added_abs(self):
+        path = os.path.join(self.repo.path, 'foo')
+        with open(path, 'w') as f:
+            f.write('BAR')
         self.repo.stage(['foo'])
         with open(os.path.join(self.repo.path, '.gitignore'), 'w') as f:
-            f.write("foo\n")
+            f.write('foo\n')
         self.assertEqual(
-            [], list(porcelain.check_ignore(self.repo, ['foo'])))
+            [], list(porcelain.check_ignore(self.repo, [path])))
         self.assertEqual(
             ['foo'],
-            list(porcelain.check_ignore(self.repo, ['foo'], no_index=True)))
+            list(porcelain.check_ignore(self.repo, [path], no_index=True)))
+
+    def test_check_added_rel(self):
+        with open(os.path.join(self.repo.path, 'foo'), 'w') as f:
+            f.write('BAR')
+        self.repo.stage(['foo'])
+        with open(os.path.join(self.repo.path, '.gitignore'), 'w') as f:
+            f.write('foo\n')
+        cwd = os.getcwd()
+        os.mkdir(os.path.join(self.repo.path, 'bar'))
+        os.chdir(os.path.join(self.repo.path, 'bar'))
+        try:
+            self.assertEqual(
+                list(porcelain.check_ignore(self.repo, ['../foo'])), [])
+            self.assertEqual(['../foo'], list(
+               porcelain.check_ignore(self.repo, ['../foo'], no_index=True)))
+        finally:
+            os.chdir(cwd)
 
 
 class UpdateHeadTests(PorcelainTestCase):
@@ -1431,3 +1487,42 @@ class DescribeTests(PorcelainTestCase):
         self.assertEqual(
                 'tryme-1-g{}'.format(sha[:7].decode('ascii')),
                 porcelain.describe(self.repo.path))
+
+
+class HelperTests(PorcelainTestCase):
+    def test_path_to_tree_path_base(self):
+        self.assertEqual(
+            b'bar', porcelain.path_to_tree_path('/home/foo', '/home/foo/bar'))
+        self.assertEqual(b'bar', porcelain.path_to_tree_path('.', './bar'))
+        self.assertEqual(b'bar', porcelain.path_to_tree_path('.', 'bar'))
+        cwd = os.getcwd()
+        self.assertEqual(
+            b'bar', porcelain.path_to_tree_path('.', os.path.join(cwd, 'bar')))
+        self.assertEqual(b'bar', porcelain.path_to_tree_path(cwd, 'bar'))
+
+    def test_path_to_tree_path_syntax(self):
+        self.assertEqual(b'bar', porcelain.path_to_tree_path(b'.', './bar'))
+        self.assertEqual(b'bar', porcelain.path_to_tree_path('.', b'./bar'))
+        self.assertEqual(b'bar', porcelain.path_to_tree_path(b'.', b'./bar'))
+
+    def test_path_to_tree_path_error(self):
+        with self.assertRaises(ValueError):
+            porcelain.path_to_tree_path('/home/foo/', '/home/bar/baz')
+
+    def test_path_to_tree_path_rel(self):
+        cwd = os.getcwd()
+        os.mkdir(os.path.join(self.repo.path, 'foo'))
+        os.mkdir(os.path.join(self.repo.path, 'foo/bar'))
+        try:
+            os.chdir(os.path.join(self.repo.path, 'foo/bar'))
+            self.assertEqual(b'bar/baz', porcelain.path_to_tree_path(
+                '..', 'baz'))
+            self.assertEqual(b'bar/baz', porcelain.path_to_tree_path(
+                os.path.join(os.getcwd(), '..'),
+                os.path.join(os.getcwd(), 'baz')))
+            self.assertEqual(b'bar/baz', porcelain.path_to_tree_path(
+                '..', os.path.join(os.getcwd(), 'baz')))
+            self.assertEqual(b'bar/baz', porcelain.path_to_tree_path(
+                os.path.join(os.getcwd(), '..'), 'baz'))
+        finally:
+            os.chdir(cwd)

+ 1 - 1
setup.py

@@ -14,7 +14,7 @@ from distutils.core import Distribution
 import os
 import sys
 
-dulwich_version_string = '0.19.5'
+dulwich_version_string = '0.19.6'
 
 include_dirs = []
 # Windows MSVC support