Skip to content

Commit 0181a40

Browse files
authored
Merge pull request #555 from ankostis/cntxtmman
Retrofit `repo` class as context-man to cleanup global mman on repo-delete
2 parents 88732b6 + f858c44 commit 0181a40

File tree

4 files changed

+45
-23
lines changed

4 files changed

+45
-23
lines changed

Diff for: git/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ def _init_externals():
4949
LockFile,
5050
BlockingLockFile,
5151
Stats,
52-
Actor
52+
Actor,
53+
rmtree,
5354
)
5455

5556
#} END imports

Diff for: git/cmd.py

+19-16
Original file line numberDiff line numberDiff line change
@@ -823,27 +823,30 @@ def _call_process(self, method, *args, **kwargs):
823823
is realized as non-existent
824824
825825
:param kwargs:
826-
is a dict of keyword arguments.
827-
This function accepts the same optional keyword arguments
828-
as execute().
829-
830-
``Examples``::
826+
It contains key-values for the following:
827+
- the :meth:`execute()` kwds, as listed in :var:`execute_kwargs`;
828+
- "command options" to be converted by :meth:`transform_kwargs()`;
829+
- the `'insert_kwargs_after'` key which its value must match one of ``*args``,
830+
and any cmd-options will be appended after the matched arg.
831+
832+
Examples::
833+
831834
git.rev_list('master', max_count=10, header=True)
835+
836+
turns into::
837+
838+
git rev-list max-count 10 --header master
832839
833840
:return: Same as ``execute``"""
834841
# Handle optional arguments prior to calling transform_kwargs
835842
# otherwise these'll end up in args, which is bad.
836-
_kwargs = dict()
837-
for kwarg in execute_kwargs:
838-
try:
839-
_kwargs[kwarg] = kwargs.pop(kwarg)
840-
except KeyError:
841-
pass
843+
exec_kwargs = dict((k, v) for k, v in kwargs.items() if k in execute_kwargs)
844+
opts_kwargs = dict((k, v) for k, v in kwargs.items() if k not in execute_kwargs)
842845

843-
insert_after_this_arg = kwargs.pop('insert_kwargs_after', None)
846+
insert_after_this_arg = opts_kwargs.pop('insert_kwargs_after', None)
844847

845848
# Prepare the argument list
846-
opt_args = self.transform_kwargs(**kwargs)
849+
opt_args = self.transform_kwargs(**opts_kwargs)
847850
ext_args = self.__unpack_args([a for a in args if a is not None])
848851

849852
if insert_after_this_arg is None:
@@ -852,11 +855,11 @@ def _call_process(self, method, *args, **kwargs):
852855
try:
853856
index = ext_args.index(insert_after_this_arg)
854857
except ValueError:
855-
raise ValueError("Couldn't find argument '%s' in args %s to insert kwargs after"
858+
raise ValueError("Couldn't find argument '%s' in args %s to insert cmd options after"
856859
% (insert_after_this_arg, str(ext_args)))
857860
# end handle error
858861
args = ext_args[:index + 1] + opt_args + ext_args[index + 1:]
859-
# end handle kwargs
862+
# end handle opts_kwargs
860863

861864
call = [self.GIT_PYTHON_GIT_EXECUTABLE]
862865

@@ -871,7 +874,7 @@ def _call_process(self, method, *args, **kwargs):
871874
call.append(dashify(method))
872875
call.extend(args)
873876

874-
return self.execute(call, **_kwargs)
877+
return self.execute(call, **exec_kwargs)
875878

876879
def _parse_object_header(self, header_line):
877880
"""

Diff for: git/repo/base.py

+14
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import os.path as osp
3434

3535
from .fun import rev_parse, is_git_dir, find_submodule_git_dir, touch
36+
import gc
37+
import gitdb
3638

3739

3840
log = logging.getLogger(__name__)
@@ -177,9 +179,21 @@ def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=Fals
177179
args.append(self.git)
178180
self.odb = odbt(*args)
179181

182+
def __enter__(self):
183+
return self
184+
185+
def __exit__(self, exc_type, exc_value, traceback):
186+
self.close()
187+
180188
def __del__(self):
189+
self.close()
190+
191+
def close(self):
181192
if self.git:
182193
self.git.clear_cache()
194+
gc.collect()
195+
gitdb.util.mman.collect()
196+
gc.collect()
183197

184198
def __eq__(self, rhs):
185199
if isinstance(rhs, Repo):

Diff for: git/test/lib/helper.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,22 @@
77

88
import contextlib
99
from functools import wraps
10-
import sys
10+
import gc
1111
import io
1212
import logging
1313
import os
14+
import sys
1415
import tempfile
1516
import textwrap
1617
import time
1718

1819
from git.compat import string_types, is_win
1920
from git.util import rmtree, cwd
21+
import gitdb
2022

2123
import os.path as osp
24+
25+
2226
if sys.version_info[0:2] == (2, 6):
2327
import unittest2 as unittest
2428
else:
@@ -96,7 +100,6 @@ def wrapper(self):
96100
# a windows-only issue. In fact things should be deleted, as well as
97101
# memory maps closed, once objects go out of scope. For some reason
98102
# though this is not the case here unless we collect explicitly.
99-
import gc
100103
gc.collect()
101104
if not keep:
102105
rmtree(path)
@@ -144,9 +147,10 @@ def repo_creator(self):
144147
os.chdir(prev_cwd)
145148
rw_repo.git.clear_cache()
146149
rw_repo = None
147-
import gc
148-
gc.collect()
149150
if repo_dir is not None:
151+
gc.collect()
152+
gitdb.util.mman.collect()
153+
gc.collect()
150154
rmtree(repo_dir)
151155
# END rm test repo if possible
152156
# END cleanup
@@ -303,7 +307,8 @@ def remote_repo_creator(self):
303307
rw_daemon_repo.git.clear_cache()
304308
del rw_repo
305309
del rw_daemon_repo
306-
import gc
310+
gc.collect()
311+
gitdb.util.mman.collect()
307312
gc.collect()
308313
if rw_repo_dir:
309314
rmtree(rw_repo_dir)
@@ -357,7 +362,6 @@ def setUpClass(cls):
357362
each test type has its own repository
358363
"""
359364
from git import Repo
360-
import gc
361365
gc.collect()
362366
cls.rorepo = Repo(GIT_REPO)
363367

0 commit comments

Comments
 (0)