summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBarry Scott <barry@barrys-emacs.org>2016-06-06 09:27:20 +0100
committerBarry Scott <barry@barrys-emacs.org>2016-06-06 09:27:20 +0100
commit35658887753da7da9a32a297346fd4ee6e53d45c (patch)
tree64e857e2ea087d489369937e42ea7374d7e04e84
parent08a0fad2c9dcdfe0bbc980b8cd260b4be5582381 (diff)
parente0b21f454ea43a5f67bc4905c641d95f8b6d96fd (diff)
downloadgitpython-35658887753da7da9a32a297346fd4ee6e53d45c.tar.gz
Merge remote-tracking branch 'upstream/master' into pr-cmd-raise-with-stderr-on-error
-rw-r--r--README.md2
-rw-r--r--VERSION2
-rw-r--r--doc/source/changes.rst16
-rw-r--r--git/cmd.py2
-rw-r--r--git/diff.py17
-rw-r--r--git/objects/commit.py6
-rw-r--r--git/remote.py2
-rw-r--r--git/test/fixtures/commit_invalid_data6
-rw-r--r--git/test/fixtures/diff_patch_unsafe_paths7
-rw-r--r--git/test/test_commit.py7
-rw-r--r--git/test/test_diff.py13
-rw-r--r--git/test/test_docs.py9
-rwxr-xr-xsetup.py1
13 files changed, 71 insertions, 19 deletions
diff --git a/README.md b/README.md
index 220e8f35..b3c5c947 100644
--- a/README.md
+++ b/README.md
@@ -6,11 +6,13 @@ It provides abstractions of git objects for easy access of repository data, and
The object database implementation is optimized for handling large quantities of objects and large datasets, which is achieved by using low-level structures and data streaming.
+
### REQUIREMENTS
GitPython needs the `git` executable to be installed on the system and available in your `PATH` for most operations. If it is not in your `PATH`, you can help GitPython find it by setting the `GIT_PYTHON_GIT_EXECUTABLE=<path/to/git>` environment variable.
* Git (1.7.x or newer)
+* Python 2.7 to 3.5, while python 2.6 is supported on a *best-effort basis*.
The list of dependencies are listed in `./requirements.txt` and `./test-requirements.txt`. The installer takes care of installing them for you.
diff --git a/VERSION b/VERSION
index 50ffc5aa..a47ed0c4 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.0.3
+2.0.6dev0
diff --git a/doc/source/changes.rst b/doc/source/changes.rst
index 928675d0..9bf09065 100644
--- a/doc/source/changes.rst
+++ b/doc/source/changes.rst
@@ -2,9 +2,25 @@
Changelog
=========
+2.0.6 - Fixes
+=============
+
+* Fix: TypeError about passing keyword argument to string decode() on
+ Python 2.6.
+
+2.0.5 - Fixes
+=============
+
+* Fix: parser of fetch info lines choked on some legitimate lines
+
2.0.4 - Fixes
=============
+* Fix: parser of commit object data is now robust against cases where
+ commit object contains invalid bytes. The invalid characters are now
+ replaced rather than choked on.
+* Fix: non-ASCII paths are now properly decoded and returned in
+ ``.diff()`` output
* Fix: `RemoteProgress` will now strip the ', ' prefix or suffix from messages.
* API: Remote.[fetch|push|pull](...) methods now allow the ``progress`` argument to
be a callable. This saves you from creating a custom type with usually just one
diff --git a/git/cmd.py b/git/cmd.py
index e3b39bda..fb00869c 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -287,7 +287,7 @@ class Git(LazyMixin):
return
# can be that nothing really exists anymore ...
- if os is None:
+ if os is None or os.kill is None:
return
# try to kill it
diff --git a/git/diff.py b/git/diff.py
index 44a65017..9073767e 100644
--- a/git/diff.py
+++ b/git/diff.py
@@ -15,12 +15,23 @@ from git.compat import (
PY3
)
-
__all__ = ('Diffable', 'DiffIndex', 'Diff', 'NULL_TREE')
# Special object to compare against the empty tree in diffs
NULL_TREE = object()
+_octal_byte_re = re.compile(b'\\\\([0-9]{3})')
+
+
+def _octal_repl(matchobj):
+ value = matchobj.group(1)
+ value = int(value, 8)
+ if PY3:
+ value = bytes(bytearray((value,)))
+ else:
+ value = chr(value)
+ return value
+
def decode_path(path, has_ab_prefix=True):
if path == b'/dev/null':
@@ -32,6 +43,8 @@ def decode_path(path, has_ab_prefix=True):
.replace(b'\\"', b'"')
.replace(b'\\\\', b'\\'))
+ path = _octal_byte_re.sub(_octal_repl, path)
+
if has_ab_prefix:
assert path.startswith(b'a/') or path.startswith(b'b/')
path = path[2:]
@@ -337,7 +350,7 @@ class Diff(object):
:note: This property is deprecated, please use ``renamed_file`` instead.
"""
return self.renamed_file
-
+
@property
def renamed_file(self):
""":returns: True if the blob of our diff has been renamed
diff --git a/git/objects/commit.py b/git/objects/commit.py
index dc722f97..9e434c92 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -501,14 +501,14 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
try:
self.author, self.authored_date, self.author_tz_offset = \
- parse_actor_and_date(author_line.decode(self.encoding))
+ parse_actor_and_date(author_line.decode(self.encoding, 'replace'))
except UnicodeDecodeError:
log.error("Failed to decode author line '%s' using encoding %s", author_line, self.encoding,
exc_info=True)
try:
self.committer, self.committed_date, self.committer_tz_offset = \
- parse_actor_and_date(committer_line.decode(self.encoding))
+ parse_actor_and_date(committer_line.decode(self.encoding, 'replace'))
except UnicodeDecodeError:
log.error("Failed to decode committer line '%s' using encoding %s", committer_line, self.encoding,
exc_info=True)
@@ -518,7 +518,7 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
# The end of our message stream is marked with a newline that we strip
self.message = stream.read()
try:
- self.message = self.message.decode(self.encoding)
+ self.message = self.message.decode(self.encoding, 'replace')
except UnicodeDecodeError:
log.error("Failed to decode message '%s' using encoding %s", self.message, self.encoding, exc_info=True)
# END exception handling
diff --git a/git/remote.py b/git/remote.py
index ba51fe92..12a681b0 100644
--- a/git/remote.py
+++ b/git/remote.py
@@ -204,7 +204,7 @@ class FetchInfo(object):
NEW_TAG, NEW_HEAD, HEAD_UPTODATE, TAG_UPDATE, REJECTED, FORCED_UPDATE, \
FAST_FORWARD, ERROR = [1 << x for x in range(8)]
- re_fetch_result = re.compile("^\s*(.) (\[?[\w\s\.$@]+\]?)\s+(.+) -> ([/\w_\+\.\-$@#]+)( \(.*\)?$)?")
+ re_fetch_result = re.compile("^\s*(.) (\[?[\w\s\.$@]+\]?)\s+(.+) -> ([/\w_\+\.\-$@#()]+)( \(.*\)?$)?")
_flag_map = {'!': ERROR,
'+': FORCED_UPDATE,
diff --git a/git/test/fixtures/commit_invalid_data b/git/test/fixtures/commit_invalid_data
new file mode 100644
index 00000000..d112bf2d
--- /dev/null
+++ b/git/test/fixtures/commit_invalid_data
@@ -0,0 +1,6 @@
+tree 9f1a495d7d9692d24f5caedaa89f5c2c32d59368
+parent 492ace2ffce0e426ebeb55e364e987bcf024dd3b
+author E.Azer KoÃoÃoÃoculu <azer@kodfabrik.com> 1306710073 +0300
+committer E.Azer KoÃoÃoÃoculu <azer@kodfabrik.com> 1306710073 +0300
+
+add environjs
diff --git a/git/test/fixtures/diff_patch_unsafe_paths b/git/test/fixtures/diff_patch_unsafe_paths
index 14375f79..9ee6b834 100644
--- a/git/test/fixtures/diff_patch_unsafe_paths
+++ b/git/test/fixtures/diff_patch_unsafe_paths
@@ -61,6 +61,13 @@ index 0000000000000000000000000000000000000000..eaf5f7510320b6a327fb308379de2f94
+++ "b/path/¯\\_(ツ)_|¯"
@@ -0,0 +1 @@
+dummy content
+diff --git "a/path/\360\237\222\251.txt" "b/path/\360\237\222\251.txt"
+new file mode 100644
+index 0000000000000000000000000000000000000000..eaf5f7510320b6a327fb308379de2f94d8859a54
+--- /dev/null
++++ "b/path/\360\237\222\251.txt"
+@@ -0,0 +1 @@
++dummy content
diff --git a/a/with spaces b/b/with some spaces
similarity index 100%
rename from a/with spaces
diff --git a/git/test/test_commit.py b/git/test/test_commit.py
index 23b7154a..ea8cd9af 100644
--- a/git/test/test_commit.py
+++ b/git/test/test_commit.py
@@ -306,6 +306,13 @@ class TestCommit(TestBase):
# it appears
cmt.author.__repr__()
+ def test_invalid_commit(self):
+ cmt = self.rorepo.commit()
+ cmt._deserialize(open(fixture_path('commit_invalid_data'), 'rb'))
+
+ assert cmt.author.name == u'E.Azer Ko�o�o�oculu', cmt.author.name
+ assert cmt.author.email == 'azer@kodfabrik.com', cmt.author.email
+
def test_gpgsig(self):
cmt = self.rorepo.commit()
cmt._deserialize(open(fixture_path('commit_with_gpgsig'), 'rb'))
diff --git a/git/test/test_diff.py b/git/test/test_diff.py
index 1d7a4fda..8966351a 100644
--- a/git/test/test_diff.py
+++ b/git/test/test_diff.py
@@ -161,16 +161,17 @@ class TestDiff(TestBase):
self.assertEqual(res[6].b_path, u'path/with spaces')
self.assertEqual(res[7].b_path, u'path/with-question-mark?')
self.assertEqual(res[8].b_path, u'path/¯\\_(ツ)_|¯')
+ self.assertEqual(res[9].b_path, u'path/💩.txt')
# The "Moves"
# NOTE: The path prefixes a/ and b/ here are legit! We're actually
# verifying that it's not "a/a/" that shows up, see the fixture data.
- self.assertEqual(res[9].a_path, u'a/with spaces') # NOTE: path a/ here legit!
- self.assertEqual(res[9].b_path, u'b/with some spaces') # NOTE: path b/ here legit!
- self.assertEqual(res[10].a_path, u'a/ending in a space ')
- self.assertEqual(res[10].b_path, u'b/ending with space ')
- self.assertEqual(res[11].a_path, u'a/"with-quotes"')
- self.assertEqual(res[11].b_path, u'b/"with even more quotes"')
+ self.assertEqual(res[10].a_path, u'a/with spaces') # NOTE: path a/ here legit!
+ self.assertEqual(res[10].b_path, u'b/with some spaces') # NOTE: path b/ here legit!
+ self.assertEqual(res[11].a_path, u'a/ending in a space ')
+ self.assertEqual(res[11].b_path, u'b/ending with space ')
+ self.assertEqual(res[12].a_path, u'a/"with-quotes"')
+ self.assertEqual(res[12].b_path, u'b/"with even more quotes"')
def test_diff_patch_format(self):
# test all of the 'old' format diffs for completness - it should at least
diff --git a/git/test/test_docs.py b/git/test/test_docs.py
index 7b3b7474..8dc08559 100644
--- a/git/test/test_docs.py
+++ b/git/test/test_docs.py
@@ -11,7 +11,6 @@ from gitdb.test.lib import with_rw_directory
class Tutorials(TestBase):
-
@with_rw_directory
def test_init_repo_object(self, rw_dir):
# [1-test_init_repo_object]
@@ -165,7 +164,7 @@ class Tutorials(TestBase):
for sm in cloned_repo.submodules:
assert not sm.remove().exists() # after removal, the sm doesn't exist anymore
sm = cloned_repo.create_submodule('mysubrepo', 'path/to/subrepo', url=bare_repo.git_dir, branch='master')
-
+
# .gitmodules was written and added to the index, which is now being committed
cloned_repo.index.commit("Added submodule")
assert sm.exists() and sm.module_exists() # this submodule is defintely available
@@ -395,7 +394,7 @@ class Tutorials(TestBase):
hcommit.diff() # diff tree against index
hcommit.diff('HEAD~1') # diff tree against previous tree
hcommit.diff(None) # diff tree against working tree
-
+
index = repo.index
index.diff() # diff index against itself yielding empty diff
index.diff(None) # diff index against working copy
@@ -446,7 +445,7 @@ class Tutorials(TestBase):
sm = sms[0]
assert sm.name == 'gitdb' # git-python has gitdb as single submodule ...
assert sm.children()[0].name == 'smmap' # ... which has smmap as single submodule
-
+
# The module is the repository referenced by the submodule
assert sm.module_exists() # the module is available, which doesn't have to be the case.
assert sm.module().working_tree_dir.endswith('gitdb')
@@ -458,7 +457,7 @@ class Tutorials(TestBase):
assert sm.config_reader().get_value('path') == sm.path
assert len(sm.children()) == 1 # query the submodule hierarchy
# ![1-test_submodules]
-
+
@with_rw_directory
def test_add_file_and_commit(self, rw_dir):
import git
diff --git a/setup.py b/setup.py
index 2df910e0..05c12b8f 100755
--- a/setup.py
+++ b/setup.py
@@ -110,6 +110,7 @@ GitPython is a python library used to interact with Git repositories""",
"Operating System :: MacOS :: MacOS X",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
+ "Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.3",