diff --git a/git/index/base.py b/git/index/base.py index cda08de25..dd8f9aa2e 100644 --- a/git/index/base.py +++ b/git/index/base.py @@ -4,6 +4,7 @@ # This module is part of GitPython and is released under # the BSD License: http://www.opensource.org/licenses/bsd-license.php +from contextlib import ExitStack import datetime import glob from io import BytesIO @@ -352,27 +353,22 @@ def from_tree(cls, repo: "Repo", *treeish: Treeish, **kwargs: Any) -> "IndexFile # tmp file created in git home directory to be sure renaming # works - /tmp/ dirs could be on another device - tmp_index = tempfile.mktemp("", "", repo.git_dir) - arg_list.append("--index-output=%s" % tmp_index) - arg_list.extend(treeish) - - # move current index out of the way - otherwise the merge may fail - # as it considers existing entries. moving it essentially clears the index. - # Unfortunately there is no 'soft' way to do it. - # The TemporaryFileSwap assure the original file get put back - if repo.git_dir: - index_handler = TemporaryFileSwap(join_path_native(repo.git_dir, "index")) - try: + with ExitStack() as stack: + tmp_index = stack.enter_context(tempfile.NamedTemporaryFile(dir=repo.git_dir)) + arg_list.append("--index-output=%s" % tmp_index.name) + arg_list.extend(treeish) + + # move current index out of the way - otherwise the merge may fail + # as it considers existing entries. moving it essentially clears the index. + # Unfortunately there is no 'soft' way to do it. + # The TemporaryFileSwap assure the original file get put back + + stack.enter_context(TemporaryFileSwap(join_path_native(repo.git_dir, "index"))) repo.git.read_tree(*arg_list, **kwargs) - index = cls(repo, tmp_index) + index = cls(repo, tmp_index.name) index.entries # force it to read the file as we will delete the temp-file - del index_handler # release as soon as possible - finally: - if osp.exists(tmp_index): - os.remove(tmp_index) - # END index merge handling - - return index + return index + # END index merge handling # UTILITIES @unbare_repo @@ -1156,7 +1152,6 @@ def checkout( unknown_lines = [] def handle_stderr(proc: "Popen[bytes]", iter_checked_out_files: Iterable[PathLike]) -> None: - stderr_IO = proc.stderr if not stderr_IO: return None # return early if stderr empty diff --git a/git/index/util.py b/git/index/util.py index bfc7fadd6..6cf838f3b 100644 --- a/git/index/util.py +++ b/git/index/util.py @@ -3,6 +3,7 @@ import os import struct import tempfile +from types import TracebackType from git.compat import is_win @@ -11,7 +12,7 @@ # typing ---------------------------------------------------------------------- -from typing import Any, Callable, TYPE_CHECKING +from typing import Any, Callable, TYPE_CHECKING, Optional, Type from git.types import PathLike, _T @@ -47,12 +48,21 @@ def __init__(self, file_path: PathLike) -> None: except OSError: pass - def __del__(self) -> None: + def __enter__(self) -> "TemporaryFileSwap": + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> bool: if osp.isfile(self.tmp_file_path): if is_win and osp.exists(self.file_path): os.remove(self.file_path) os.rename(self.tmp_file_path, self.file_path) - # END temp file exists + + return False # { Decorators