diff options
-rw-r--r-- | AUTHORS | 1 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | git/cmd.py | 2 | ||||
-rw-r--r-- | git/config.py | 41 | ||||
-rw-r--r-- | git/diff.py | 3 | ||||
-rw-r--r-- | git/remote.py | 4 | ||||
-rw-r--r-- | git/test/test_remote.py | 4 | ||||
-rw-r--r-- | git/test/test_repo.py | 14 |
8 files changed, 61 insertions, 9 deletions
@@ -36,5 +36,6 @@ Contributors are: -Arthur Milchior <arthur _at_ milchior.fr> -Anil Khatri <anil.soccer.khatri _at_ gmail.com> -JJ Graham <thetwoj _at_ gmail.com> +-Ben Thayer <ben _at_ benthayer.com> Portions derived from other open source works and are clearly marked. @@ -180,6 +180,7 @@ gpg --edit-key 88710E60 * [Loki](https://github.com/Neo23x0/Loki) * [Omniwallet](https://github.com/OmniLayer/omniwallet) * [GitViper](https://github.com/BeayemX/GitViper) +* [Git Gud](https://github.com/bthayer2365/git-gud) ### LICENSE @@ -401,7 +401,7 @@ class Git(LazyMixin): :raise GitCommandError: if the return status is not 0""" if stderr is None: stderr = b'' - stderr = force_bytes(stderr) + stderr = force_bytes(data=stderr, encoding='utf-8') status = self.proc.wait() diff --git a/git/config.py b/git/config.py index edd5750b..762069c7 100644 --- a/git/config.py +++ b/git/config.py @@ -20,7 +20,8 @@ from git.compat import ( defenc, force_text, with_metaclass, - PY3 + PY3, + is_win, ) from git.util import LockFile @@ -40,6 +41,10 @@ __all__ = ('GitConfigParser', 'SectionConstraint') log = logging.getLogger('git.config') log.addHandler(logging.NullHandler()) +# invariants +# represents the configuration level of a configuration file +CONFIG_LEVELS = ("system", "user", "global", "repository") + class MetaParserBuilder(abc.ABCMeta): @@ -191,6 +196,26 @@ class _OMD(OrderedDict): return [(k, self.getall(k)) for k in self] +def get_config_path(config_level): + + # we do not support an absolute path of the gitconfig on windows , + # use the global config instead + if is_win and config_level == "system": + config_level = "global" + + if config_level == "system": + return "/etc/gitconfig" + elif config_level == "user": + config_home = os.environ.get("XDG_CONFIG_HOME") or osp.join(os.environ.get("HOME", '~'), ".config") + return osp.normpath(osp.expanduser(osp.join(config_home, "git", "config"))) + elif config_level == "global": + return osp.normpath(osp.expanduser("~/.gitconfig")) + elif config_level == "repository": + raise ValueError("No repo to get repository configuration from. Use Repo._get_config_path") + + raise ValueError("Invalid configuration level: %r" % config_level) + + class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, object)): """Implements specifics required to read git style configuration files. @@ -229,7 +254,7 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje # list of RawConfigParser methods able to change the instance _mutating_methods_ = ("add_section", "remove_section", "remove_option", "set") - def __init__(self, file_or_files, read_only=True, merge_includes=True): + def __init__(self, file_or_files=None, read_only=True, merge_includes=True, config_level=None): """Initialize a configuration reader to read the given file_or_files and to possibly allow changes to it by setting read_only False @@ -251,7 +276,17 @@ class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, obje if not hasattr(self, '_proxies'): self._proxies = self._dict() - self._file_or_files = file_or_files + if file_or_files is not None: + self._file_or_files = file_or_files + else: + if config_level is None: + if read_only: + self._file_or_files = [get_config_path(f) for f in CONFIG_LEVELS if f != 'repository'] + else: + raise ValueError("No configuration level or configuration files specified") + else: + self._file_or_files = [get_config_path(config_level)] + self._read_only = read_only self._dirty = False self._is_initialized = False diff --git a/git/diff.py b/git/diff.py index 897228a7..7a06f3a1 100644 --- a/git/diff.py +++ b/git/diff.py @@ -283,7 +283,8 @@ class Diff(object): if repo and a_rawpath: for submodule in repo.submodules: if submodule.path == a_rawpath.decode("utf-8"): - repo = submodule.module() + if submodule.module_exists(): + repo = submodule.module() break if a_blob_id is None or a_blob_id == self.NULL_HEX_SHA: diff --git a/git/remote.py b/git/remote.py index 23337a9c..05d7d0db 100644 --- a/git/remote.py +++ b/git/remote.py @@ -717,7 +717,7 @@ class Remote(LazyMixin, Iterable): # read the lines manually as it will use carriage returns between the messages # to override the previous one. This is why we read the bytes manually progress_handler = progress.new_message_handler() - output = IterableList('name') + output = [] def stdout_handler(line): try: @@ -833,7 +833,7 @@ class Remote(LazyMixin, Iterable): :note: No further progress information is returned after push returns. :param kwargs: Additional arguments to be passed to git-push :return: - IterableList(PushInfo, ...) iterable list of PushInfo instances, each + list(PushInfo, ...) list of PushInfo instances, each one informing about an individual head which had been updated on the remote side. If the push contains rejected heads, these will have the PushInfo.ERROR bit set diff --git a/git/test/test_remote.py b/git/test/test_remote.py index 95898f12..3ef47472 100644 --- a/git/test/test_remote.py +++ b/git/test/test_remote.py @@ -31,7 +31,7 @@ from git.test.lib import ( GIT_DAEMON_PORT, assert_raises ) -from git.util import IterableList, rmtree, HIDE_WINDOWS_FREEZE_ERRORS +from git.util import rmtree, HIDE_WINDOWS_FREEZE_ERRORS import os.path as osp @@ -325,7 +325,7 @@ class TestRemote(TestBase): self._commit_random_file(rw_repo) progress = TestRemoteProgress() res = remote.push(lhead.reference, progress) - self.assertIsInstance(res, IterableList) + self.assertIsInstance(res, list) self._do_test_push_result(res, remote) progress.make_assertion() diff --git a/git/test/test_repo.py b/git/test/test_repo.py index de1e951a..c59203ed 100644 --- a/git/test/test_repo.py +++ b/git/test/test_repo.py @@ -245,6 +245,20 @@ class TestRepo(TestBase): assert_equal(cloned.config_reader().get_value('core', 'filemode'), False) assert_equal(cloned.config_reader().get_value('submodule "repo"', 'update'), 'checkout') + def test_clone_from_with_path_contains_unicode(self): + with tempfile.TemporaryDirectory() as tmpdir: + unicode_dir_name = '\u0394' + path_with_unicode = os.path.join(tmpdir, unicode_dir_name) + os.makedirs(path_with_unicode) + + try: + Repo.clone_from( + url=self._small_repo_url(), + to_path=path_with_unicode, + ) + except UnicodeEncodeError: + self.fail('Raised UnicodeEncodeError') + @with_rw_repo('HEAD') def test_max_chunk_size(self, repo): class TestOutputStream(object): |