aboutsummaryrefslogtreecommitdiff
path: root/git
diff options
context:
space:
mode:
Diffstat (limited to 'git')
-rw-r--r--git/cmd.py9
-rw-r--r--git/config.py6
-rw-r--r--git/objects/commit.py2
-rw-r--r--git/test/fixtures/.gitconfig3
-rw-r--r--git/test/lib/helper.py10
-rw-r--r--git/test/test_config.py15
-rw-r--r--git/test/test_docs.py2
-rw-r--r--git/test/test_remote.py5
-rw-r--r--git/util.py7
9 files changed, 41 insertions, 18 deletions
diff --git a/git/cmd.py b/git/cmd.py
index 429046be..87e482d8 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -530,7 +530,7 @@ class Git(LazyMixin):
* output_stream if extended_output = False
* tuple(int(status), output_stream, str(stderr)) if extended_output = True
- Note git is executed with LC_MESSAGES="C" to ensure consitent
+ Note git is executed with LC_MESSAGES="C" to ensure consistent
output regardless of system language.
:raise GitCommandError:
@@ -549,7 +549,12 @@ class Git(LazyMixin):
# Start the process
env = os.environ.copy()
- env["LC_MESSAGES"] = "C"
+ # Attempt to force all output to plain ascii english, which is what some parsing code
+ # may expect.
+ # According to stackoverflow (http://goo.gl/l74GC8), we are setting LANGUAGE as well
+ # just to be sure.
+ env["LANGUAGE"] = "C"
+ env["LC_ALL"] = "C"
env.update(self._environment)
if sys.platform == 'win32':
diff --git a/git/config.py b/git/config.py
index 38dd1b44..a6a25c7b 100644
--- a/git/config.py
+++ b/git/config.py
@@ -81,6 +81,7 @@ def set_dirty_and_flush_changes(non_const_func):
def flush_changes(self, *args, **kwargs):
rval = non_const_func(self, *args, **kwargs)
+ self._dirty = True
self.write()
return rval
# END wrapper method
@@ -190,6 +191,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
self._file_or_files = file_or_files
self._read_only = read_only
+ self._dirty = False
self._is_initialized = False
self._merge_includes = merge_includes
self._lock = None
@@ -304,7 +306,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
if mo:
# We might just have handled the last line, which could contain a quotation we want to remove
optname, vi, optval = mo.group('option', 'vi', 'value')
- if vi in ('=', ':') and ';' in optval:
+ if vi in ('=', ':') and ';' in optval and not optval.strip().startswith('"'):
pos = optval.find(';')
if pos != -1 and optval[pos - 1].isspace():
optval = optval[:pos]
@@ -433,6 +435,8 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje
:raise IOError: if this is a read-only writer instance or if we could not obtain
a file lock"""
self._assure_writable("write")
+ if not self._dirty:
+ return
if isinstance(self._file_or_files, (list, tuple)):
raise AssertionError("Cannot write back if there is not exactly a single file to write to, have %i files"
diff --git a/git/objects/commit.py b/git/objects/commit.py
index f13760fd..ac381cd9 100644
--- a/git/objects/commit.py
+++ b/git/objects/commit.py
@@ -445,7 +445,7 @@ class Commit(base.Object, Iterable, Diffable, Traversable, Serializable):
next_line = readline()
while next_line.startswith(b'mergetag '):
next_line = readline()
- while next_line.startswith(' '):
+ while next_line.startswith(b' '):
next_line = readline()
# end skip mergetags
diff --git a/git/test/fixtures/.gitconfig b/git/test/fixtures/.gitconfig
new file mode 100644
index 00000000..6a0459f6
--- /dev/null
+++ b/git/test/fixtures/.gitconfig
@@ -0,0 +1,3 @@
+[alias]
+ rbi = "!g() { git rebase -i origin/${1:-master} ; } ; g"
+ expush = "!f() { git branch -f tmp ; { git rbi $1 && git push ; } ; git reset --hard tmp ; git rebase origin/${1:-master}; } ; f" \ No newline at end of file
diff --git a/git/test/lib/helper.py b/git/test/lib/helper.py
index 541b972d..8be2881c 100644
--- a/git/test/lib/helper.py
+++ b/git/test/lib/helper.py
@@ -18,10 +18,11 @@ from git.compat import string_types
osp = os.path.dirname
GIT_REPO = os.environ.get("GIT_PYTHON_TEST_GIT_REPO_BASE", osp(osp(osp(osp(__file__)))))
+GIT_DAEMON_PORT = os.environ.get("GIT_PYTHON_TEST_GIT_DAEMON_PORT", "9418")
__all__ = (
'fixture_path', 'fixture', 'absolute_project_path', 'StringProcessAdapter',
- 'with_rw_repo', 'with_rw_and_rw_remote_repo', 'TestBase', 'TestCase', 'GIT_REPO'
+ 'with_rw_repo', 'with_rw_and_rw_remote_repo', 'TestBase', 'TestCase', 'GIT_REPO', 'GIT_DAEMON_PORT'
)
#{ Routines
@@ -193,14 +194,15 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
# by the user, not by us
d_remote = Remote.create(rw_repo, "daemon_origin", remote_repo_dir)
d_remote.fetch()
- remote_repo_url = "git://localhost%s" % remote_repo_dir
+ remote_repo_url = "git://localhost:%s%s" % (GIT_DAEMON_PORT, remote_repo_dir)
d_remote.config_writer.set('url', remote_repo_url)
temp_dir = osp(_mktemp())
# On windows, this will fail ... we deal with failures anyway and default to telling the user to do it
try:
- gd = Git().daemon(temp_dir, enable='receive-pack', as_process=True)
+ gd = Git().daemon(temp_dir, enable='receive-pack', listen='127.0.0.1', port=GIT_DAEMON_PORT,
+ as_process=True)
# yes, I know ... fortunately, this is always going to work if sleep time is just large enough
time.sleep(0.5)
except Exception:
@@ -223,6 +225,8 @@ def with_rw_and_rw_remote_repo(working_tree_ref):
raise AssertionError(msg)
else:
msg = 'Please start a git-daemon to run this test, execute: git daemon --enable=receive-pack "%s"'
+ msg += 'You can also run the daemon on a different port by passing --port=<port>'
+ msg += 'and setting the environment variable GIT_PYTHON_TEST_GIT_DAEMON_PORT to <port>'
msg %= temp_dir
raise AssertionError(msg)
# END make assertion
diff --git a/git/test/test_config.py b/git/test/test_config.py
index fc2b87b6..7758a094 100644
--- a/git/test/test_config.py
+++ b/git/test/test_config.py
@@ -18,7 +18,6 @@ from git.compat import (
)
import io
import os
-from copy import copy
from git.config import cp
@@ -30,21 +29,18 @@ class TestBase(TestCase):
sio.name = file_path
return sio
- def _parsers_equal_or_raise(self, lhs, rhs):
- pass
-
def test_read_write(self):
# writer must create the exact same file as the one read before
for filename in ("git_config", "git_config_global"):
file_obj = self._to_memcache(fixture_path(filename))
- file_obj_orig = copy(file_obj)
w_config = GitConfigParser(file_obj, read_only=False)
w_config.read() # enforce reading
assert w_config._sections
w_config.write() # enforce writing
# we stripped lines when reading, so the results differ
- assert file_obj.getvalue() and file_obj.getvalue() != file_obj_orig.getvalue()
+ assert file_obj.getvalue()
+ self.assertEqual(file_obj.getvalue(), self._to_memcache(fixture_path(filename)).getvalue())
# creating an additional config writer must fail due to exclusive access
self.failUnlessRaises(IOError, GitConfigParser, file_obj, read_only=False)
@@ -207,3 +203,10 @@ class TestBase(TestCase):
assert not cw.has_section('core')
assert len(cw.items(nn)) == 4
cw.release()
+
+ def test_complex_aliases(self):
+ file_obj = self._to_memcache(fixture_path('.gitconfig'))
+ w_config = GitConfigParser(file_obj, read_only=False)
+ self.assertEqual(w_config.get('alias', 'rbi'), '"!g() { git rebase -i origin/${1:-master} ; } ; g"')
+ w_config.release()
+ self.assertEqual(file_obj.getvalue(), self._to_memcache(fixture_path('.gitconfig')).getvalue())
diff --git a/git/test/test_docs.py b/git/test/test_docs.py
index 586f0ce4..5b8aa817 100644
--- a/git/test/test_docs.py
+++ b/git/test/test_docs.py
@@ -94,7 +94,7 @@ class Tutorials(TestBase):
# [11-test_init_repo_object]
assert now.commit.message != past.commit.message
# You can read objects directly through binary streams, no working tree required
- assert (now.commit.tree / 'VERSION').data_stream.read().decode('ascii').startswith('0')
+ assert (now.commit.tree / 'VERSION').data_stream.read().decode('ascii').startswith('1')
# You can traverse trees as well to handle all contained files of a particular commit
file_count = 0
diff --git a/git/test/test_remote.py b/git/test/test_remote.py
index c419ecee..af854988 100644
--- a/git/test/test_remote.py
+++ b/git/test/test_remote.py
@@ -8,7 +8,8 @@ from git.test.lib import (
TestBase,
with_rw_repo,
with_rw_and_rw_remote_repo,
- fixture
+ fixture,
+ GIT_DAEMON_PORT
)
from git import (
RemoteProgress,
@@ -250,7 +251,7 @@ class TestRemote(TestBase):
# must clone with a local path for the repo implementation not to freak out
# as it wants local paths only ( which I can understand )
other_repo = remote_repo.clone(other_repo_dir, shared=False)
- remote_repo_url = "git://localhost%s" % remote_repo.git_dir
+ remote_repo_url = "git://localhost:%s%s" % (GIT_DAEMON_PORT, remote_repo.git_dir)
# put origin to git-url
other_origin = other_repo.remotes.origin
diff --git a/git/util.py b/git/util.py
index 1147cb53..fb459da1 100644
--- a/git/util.py
+++ b/git/util.py
@@ -164,8 +164,9 @@ class RemoteProgress(object):
Handler providing an interface to parse progress information emitted by git-push
and git-fetch and to dispatch callbacks allowing subclasses to react to the progress.
"""
- _num_op_codes = 7
- BEGIN, END, COUNTING, COMPRESSING, WRITING, RECEIVING, RESOLVING = [1 << x for x in range(_num_op_codes)]
+ _num_op_codes = 8
+ BEGIN, END, COUNTING, COMPRESSING, WRITING, RECEIVING, RESOLVING, FINDING_SOURCES = \
+ [1 << x for x in range(_num_op_codes)]
STAGE_MASK = BEGIN | END
OP_MASK = ~STAGE_MASK
@@ -227,6 +228,8 @@ class RemoteProgress(object):
op_code |= self.RECEIVING
elif op_name == 'Resolving deltas':
op_code |= self.RESOLVING
+ elif op_name == 'Finding sources':
+ op_code |= self.FINDING_SOURCES
else:
# Note: On windows it can happen that partial lines are sent
# Hence we get something like "CompreReceiving objects", which is