Skip to content

Commit a05e49d

Browse files
committed
test_repo works
1 parent 60e5413 commit a05e49d

File tree

13 files changed

+106
-45
lines changed

13 files changed

+106
-45
lines changed

doc/source/changes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ Changelog
66
========================
77
* Internally, hexadecimal SHA1 are treated as ascii encoded strings. Binary SHA1 are treated as bytes.
88
* Id attribute of Commit objects is now `hexsha`, instead of `binsha`. The latter makes no sense in python 3 and I see no application of it anyway besides its artificial usage in test cases.
9+
* **IMPORTANT**: If you were using the config_writer(), you implicitly relied on __del__ to work as expected to flush changes. To be sure changes are flushed under PY3, you will have to call the new `release()` method to trigger a flush. For some reason, __del__ is not called necessarily anymore when a symbol goes out of scope.
910

1011
0.3.3
1112
=====

git/cmd.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
from git.compat import (
2323
text_type,
2424
string_types,
25-
defenc
25+
defenc,
26+
PY3
2627
)
2728

2829
execute_kwargs = ('istream', 'with_keep_cwd', 'with_extended_output',
@@ -372,8 +373,8 @@ def execute(self, command,
372373

373374
# Wait for the process to return
374375
status = 0
375-
stdout_value = ''
376-
stderr_value = ''
376+
stdout_value = b''
377+
stderr_value = b''
377378
try:
378379
if output_stream is None:
379380
stdout_value, stderr_value = proc.communicate()
@@ -388,7 +389,7 @@ def execute(self, command,
388389
stdout_value = output_stream
389390
stderr_value = proc.stderr.read()
390391
# strip trailing "\n"
391-
if stderr_value.endswith("\n"):
392+
if stderr_value.endswith(b"\n"):
392393
stderr_value = stderr_value[:-1]
393394
status = proc.wait()
394395
# END stdout handling
@@ -444,15 +445,17 @@ def transform_kwargs(self, split_single_char_options=False, **kwargs):
444445
@classmethod
445446
def __unpack_args(cls, arg_list):
446447
if not isinstance(arg_list, (list, tuple)):
447-
if isinstance(arg_list, text_type):
448+
# This is just required for unicode conversion, as subprocess can't handle it
449+
# However, in any other case, passing strings (usually utf-8 encoded) is totally fine
450+
if not PY3 and isinstance(arg_list, unicode):
448451
return [arg_list.encode(defenc)]
449452
return [str(arg_list)]
450453

451454
outlist = list()
452455
for arg in arg_list:
453456
if isinstance(arg_list, (list, tuple)):
454457
outlist.extend(cls.__unpack_args(arg))
455-
elif isinstance(arg_list, text_type):
458+
elif not PY3 and isinstance(arg_list, unicode):
456459
outlist.append(arg_list.encode(defenc))
457460
# END recursion
458461
else:
@@ -509,8 +512,8 @@ def _call_process(self, method, *args, **kwargs):
509512

510513
# Prepare the argument list
511514
opt_args = self.transform_kwargs(**kwargs)
512-
513515
ext_args = self.__unpack_args([a for a in args if a is not None])
516+
514517
args = opt_args + ext_args
515518

516519
def make_call():

git/config.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,7 @@ def __del__(self):
103103
# Yes, for some reason, we have to call it explicitly for it to work in PY3 !
104104
# Apparently __del__ doesn't get call anymore if refcount becomes 0
105105
# Ridiculous ... .
106-
self._config.__del__()
107-
# del self._config
106+
self._config.release()
108107

109108
def __getattr__(self, attr):
110109
if attr in self._valid_attrs_:
@@ -121,6 +120,10 @@ def config(self):
121120
"""return: Configparser instance we constrain"""
122121
return self._config
123122

123+
def release(self):
124+
"""Equivalent to GitConfigParser.release(), which is called on our underlying parser instance"""
125+
return self._config.release()
126+
124127

125128
class GitConfigParser(with_metaclass(MetaParserBuilder, cp.RawConfigParser, object)):
126129

@@ -198,6 +201,13 @@ def __init__(self, file_or_files, read_only=True):
198201

199202
def __del__(self):
200203
"""Write pending changes if required and release locks"""
204+
# NOTE: only consistent in PY2
205+
self.release()
206+
207+
def release(self):
208+
"""Flush changes and release the configuration write lock. This instance must not be used anymore afterwards.
209+
In Python 3, it's required to explicitly release locks and flush changes, as __del__ is not called
210+
deterministically anymore."""
201211
# checking for the lock here makes sure we do not raise during write()
202212
# in case an invalid parser was created who could not get a lock
203213
if self.read_only or (self._lock and not self._lock._has_lock()):

git/exc.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
from gitdb.exc import * # NOQA
99

10+
from git.compat import defenc
11+
1012

1113
class InvalidGitRepositoryError(Exception):
1214

@@ -32,9 +34,9 @@ def __str__(self):
3234
ret = "'%s' returned with exit code %i" % \
3335
(' '.join(str(i) for i in self.command), self.status)
3436
if self.stderr:
35-
ret += "\nstderr: '%s'" % self.stderr
37+
ret += "\nstderr: '%s'" % self.stderr.decode(defenc)
3638
if self.stdout:
37-
ret += "\nstdout: '%s'" % self.stdout
39+
ret += "\nstdout: '%s'" % self.stdout.decode(defenc)
3840
return ret
3941

4042

git/objects/submodule/base.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,10 @@
1717
rmtree
1818
)
1919

20-
from git.config import SectionConstraint
20+
from git.config import (
21+
SectionConstraint,
22+
cp
23+
)
2124
from git.exc import (
2225
InvalidGitRepositoryError,
2326
NoSuchPathError
@@ -302,6 +305,7 @@ def add(cls, repo, name, path, url=None, branch=None, no_checkout=False):
302305
writer.set_value(cls.k_head_option, br.path)
303306
sm._branch_path = br.path
304307
# END handle path
308+
writer.release()
305309
del(writer)
306310

307311
# we deliberatly assume that our head matches our index !
@@ -419,7 +423,9 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress=
419423
# the default implementation will be offended and not update the repository
420424
# Maybe this is a good way to assure it doesn't get into our way, but
421425
# we want to stay backwards compatible too ... . Its so redundant !
422-
self.repo.config_writer().set_value(sm_section(self.name), 'url', self.url)
426+
writer = self.repo.config_writer()
427+
writer.set_value(sm_section(self.name), 'url', self.url)
428+
writer.release()
423429
# END handle dry_run
424430
# END handle initalization
425431

@@ -576,6 +582,7 @@ def move(self, module_path, configuration=True, module=True):
576582
writer = self.config_writer(index=index) # auto-write
577583
writer.set_value('path', module_path)
578584
self.path = module_path
585+
writer.release()
579586
del(writer)
580587
# END handle configuration flag
581588
except Exception:
@@ -700,8 +707,12 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False):
700707

701708
# now git config - need the config intact, otherwise we can't query
702709
# inforamtion anymore
703-
self.repo.config_writer().remove_section(sm_section(self.name))
704-
self.config_writer().remove_section()
710+
writer = self.repo.config_writer()
711+
writer.remove_section(sm_section(self.name))
712+
writer.release()
713+
writer = self.config_writer()
714+
writer.remove_section()
715+
writer.release()
705716
# END delete configuration
706717

707718
# void our data not to delay invalid access
@@ -800,14 +811,18 @@ def exists(self):
800811
"""
801812
:return: True if the submodule exists, False otherwise. Please note that
802813
a submodule may exist (in the .gitmodules file) even though its module
803-
doesn't exist"""
814+
doesn't exist on disk"""
804815
# keep attributes for later, and restore them if we have no valid data
805816
# this way we do not actually alter the state of the object
806817
loc = locals()
807818
for attr in self._cache_attrs:
808-
if hasattr(self, attr):
809-
loc[attr] = getattr(self, attr)
810-
# END if we have the attribute cache
819+
try:
820+
if hasattr(self, attr):
821+
loc[attr] = getattr(self, attr)
822+
# END if we have the attribute cache
823+
except cp.NoSectionError:
824+
# on PY3, this can happen apparently ... don't know why this doesn't happen on PY2
825+
pass
811826
# END for each attr
812827
self._clear_cache()
813828

git/refs/head.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ def set_tracking_branch(self, remote_reference):
148148
writer.set_value(self.k_config_remote, remote_reference.remote_name)
149149
writer.set_value(self.k_config_remote_ref, Head.to_full_path(remote_reference.remote_head))
150150
# END handle ref value
151+
writer.release()
151152

152153
return self
153154

git/repo/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ def untracked_files(self):
551551
prefix = "?? "
552552
untracked_files = list()
553553
for line in proc.stdout:
554+
line = line.decode(defenc)
554555
if not line.startswith(prefix):
555556
continue
556557
filename = line[len(prefix):].rstrip('\n')
@@ -735,7 +736,7 @@ def _clone(cls, git, url, path, odb_default_type, progress, **kwargs):
735736
writer = repo.remotes[0].config_writer
736737
writer.set_value('url', repo.remotes[0].url.replace("\\\\", "\\").replace("\\", "/"))
737738
# PY3: be sure cleanup is performed and lock is released
738-
del writer
739+
writer.release()
739740
# END handle remote repo
740741
return repo
741742

@@ -767,7 +768,7 @@ def clone_from(cls, url, to_path, progress=None, **kwargs):
767768

768769
def archive(self, ostream, treeish=None, prefix=None, **kwargs):
769770
"""Archive the tree at the given revision.
770-
:parm ostream: file compatible stream object to which the archive will be written
771+
:parm ostream: file compatible stream object to which the archive will be written as bytes
771772
:parm treeish: is the treeish name/id, defaults to active branch
772773
:parm prefix: is the optional prefix to prepend to each filename in the archive
773774
:parm kwargs:

git/repo/fun.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ def to_commit(obj):
150150
def rev_parse(repo, rev):
151151
"""
152152
:return: Object at the given revision, either Commit, Tag, Tree or Blob
153-
:param rev: git-rev-parse compatible revision specification, please see
153+
:param rev: git-rev-parse compatible revision specification as string, please see
154154
http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html
155155
for details
156156
:note: Currently there is no access to the rev-log, rev-specs may only contain

git/test/lib/helper.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ def remote_repo_creator(self):
179179
pass
180180
crw.set(section, "receivepack", True)
181181
# release lock
182+
crw.release()
182183
del(crw)
183184

184185
# initialize the remote - first do it as local remote and pull, then

git/test/test_index.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ def test_index_mutation(self, rw_repo):
382382
writer = rw_repo.config_writer()
383383
writer.set_value("user", "name", uname)
384384
writer.set_value("user", "email", umail)
385+
writer.release()
385386

386387
# remove all of the files, provide a wild mix of paths, BaseIndexEntries,
387388
# IndexEntries

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy