summaryrefslogtreecommitdiff
path: root/git/index/base.py
diff options
context:
space:
mode:
authorYobmod <yobmod@gmail.com>2021-05-15 22:53:20 +0100
committerYobmod <yobmod@gmail.com>2021-05-15 22:53:20 +0100
commit96364599258e7e036298dd5737918bde346ec195 (patch)
tree3cc7d316cb4cb052b0b40ee1f68e2d443814348b /git/index/base.py
parent33346b25c3a4fb5ea37202d88d6a6c66379099c5 (diff)
downloadgitpython-96364599258e7e036298dd5737918bde346ec195.tar.gz
Add initial types to IndexFile .init() to _to_relative_path()
Diffstat (limited to 'git/index/base.py')
-rw-r--r--git/index/base.py122
1 files changed, 72 insertions, 50 deletions
diff --git a/git/index/base.py b/git/index/base.py
index 5b3667ac..4dcfb30d 100644
--- a/git/index/base.py
+++ b/git/index/base.py
@@ -63,6 +63,19 @@ from .util import (
git_working_dir
)
+# typing -----------------------------------------------------------------------------
+
+from typing import Any, Callable, Dict, IO, Iterator, List, Sequence, TYPE_CHECKING, Tuple, Union
+
+from git.types import PathLike, TBD
+
+if TYPE_CHECKING:
+ from subprocess import Popen
+ from git.repo import Repo
+
+StageType = int
+Treeish = Union[Tree, Commit, bytes]
+
__all__ = ('IndexFile', 'CheckoutError')
@@ -93,7 +106,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
_VERSION = 2 # latest version we support
S_IFGITLINK = S_IFGITLINK # a submodule
- def __init__(self, repo, file_path=None):
+ def __init__(self, repo: 'Repo', file_path: PathLike = None) -> None:
"""Initialize this Index instance, optionally from the given ``file_path``.
If no file_path is given, we will be created from the current index file.
@@ -102,9 +115,9 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
self.repo = repo
self.version = self._VERSION
self._extension_data = b''
- self._file_path = file_path or self._index_path()
+ self._file_path = file_path or self._index_path() # type: PathLike
- def _set_cache_(self, attr):
+ def _set_cache_(self, attr: str) -> None:
if attr == "entries":
# read the current index
# try memory map for speed
@@ -115,8 +128,8 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
ok = True
except OSError:
# in new repositories, there may be no index, which means we are empty
- self.entries = {}
- return
+ self.entries = {} # type: Dict[Tuple[PathLike, StageType], IndexEntry]
+ return None
finally:
if not ok:
lfd.rollback()
@@ -133,15 +146,18 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
else:
super(IndexFile, self)._set_cache_(attr)
- def _index_path(self):
- return join_path_native(self.repo.git_dir, "index")
+ def _index_path(self) -> PathLike:
+ if self.repo.git_dir:
+ return join_path_native(self.repo.git_dir, "index")
+ else:
+ raise GitCommandError("No git directory given to join index path")
@property
- def path(self):
+ def path(self) -> PathLike:
""" :return: Path to the index file we are representing """
return self._file_path
- def _delete_entries_cache(self):
+ def _delete_entries_cache(self) -> None:
"""Safely clear the entries cache so it can be recreated"""
try:
del(self.entries)
@@ -152,18 +168,18 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
#{ Serializable Interface
- def _deserialize(self, stream):
+ def _deserialize(self, stream: IO) -> 'IndexFile':
"""Initialize this instance with index values read from the given stream"""
self.version, self.entries, self._extension_data, _conten_sha = read_cache(stream)
return self
- def _entries_sorted(self):
+ def _entries_sorted(self) -> List[TBD]:
""":return: list of entries, in a sorted fashion, first by path, then by stage"""
return sorted(self.entries.values(), key=lambda e: (e.path, e.stage))
- def _serialize(self, stream, ignore_extension_data=False):
+ def _serialize(self, stream: IO, ignore_extension_data: bool = False) -> 'IndexFile':
entries = self._entries_sorted()
- extension_data = self._extension_data
+ extension_data = self._extension_data # type: Union[None, bytes]
if ignore_extension_data:
extension_data = None
write_cache(entries, stream, extension_data)
@@ -171,7 +187,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
#} END serializable interface
- def write(self, file_path=None, ignore_extension_data=False):
+ def write(self, file_path: Union[None, PathLike] = None, ignore_extension_data: bool = False) -> None:
"""Write the current state to our file path or to the given one
:param file_path:
@@ -191,7 +207,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
Alternatively, use IndexFile.write_tree() to handle this case
automatically
- :return: self"""
+ :return: self # does it? or returns None?"""
# make sure we have our entries read before getting a write lock
# else it would be done when streaming. This can happen
# if one doesn't change the index, but writes it right away
@@ -215,7 +231,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
@post_clear_cache
@default_index
- def merge_tree(self, rhs, base=None):
+ def merge_tree(self, rhs: Treeish, base: Union[None, Treeish] = None) -> 'IndexFile':
"""Merge the given rhs treeish into the current index, possibly taking
a common base treeish into account.
@@ -242,7 +258,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
# -i : ignore working tree status
# --aggressive : handle more merge cases
# -m : do an actual merge
- args = ["--aggressive", "-i", "-m"]
+ args = ["--aggressive", "-i", "-m"] # type: List[Union[Treeish, str]]
if base is not None:
args.append(base)
args.append(rhs)
@@ -251,7 +267,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
return self
@classmethod
- def new(cls, repo, *tree_sha):
+ def new(cls, repo: 'Repo', *tree_sha: bytes) -> 'IndexFile':
""" Merge the given treeish revisions into a new index which is returned.
This method behaves like git-read-tree --aggressive when doing the merge.
@@ -275,7 +291,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
return inst
@classmethod
- def from_tree(cls, repo, *treeish, **kwargs):
+ def from_tree(cls, repo: 'Repo', *treeish: Treeish, **kwargs: Any) -> 'IndexFile':
"""Merge the given treeish revisions into a new index which is returned.
The original index will remain unaltered
@@ -312,7 +328,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
if len(treeish) == 0 or len(treeish) > 3:
raise ValueError("Please specify between 1 and 3 treeish, got %i" % len(treeish))
- arg_list = []
+ arg_list = [] # type: List[Union[Treeish, str]]
# ignore that working tree and index possibly are out of date
if len(treeish) > 1:
# drop unmerged entries when reading our index and merging
@@ -331,7 +347,8 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
# 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
- index_handler = TemporaryFileSwap(join_path_native(repo.git_dir, 'index'))
+ if repo.git_dir:
+ index_handler = TemporaryFileSwap(join_path_native(repo.git_dir, 'index'))
try:
repo.git.read_tree(*arg_list, **kwargs)
index = cls(repo, tmp_index)
@@ -346,7 +363,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
# UTILITIES
@unbare_repo
- def _iter_expand_paths(self, paths):
+ def _iter_expand_paths(self, paths: Sequence[PathLike]) -> Iterator[PathLike]:
"""Expand the directories in list of paths to the corresponding paths accordingly,
Note: git will add items multiple times even if a glob overlapped
@@ -354,10 +371,10 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
times - we respect that and do not prune"""
def raise_exc(e):
raise e
- r = self.repo.working_tree_dir
+ r = str(self.repo.working_tree_dir)
rs = r + os.sep
for path in paths:
- abs_path = path
+ abs_path = str(path)
if not osp.isabs(abs_path):
abs_path = osp.join(r, path)
# END make absolute path
@@ -374,7 +391,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
# end check symlink
# if the path is not already pointing to an existing file, resolve globs if possible
- if not os.path.exists(path) and ('?' in path or '*' in path or '[' in path):
+ if not os.path.exists(abs_path) and ('?' in abs_path or '*' in abs_path or '[' in abs_path):
resolved_paths = glob.glob(abs_path)
# not abs_path in resolved_paths:
# a glob() resolving to the same path we are feeding it with
@@ -396,12 +413,12 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
# END for each subdirectory
except OSError:
# was a file or something that could not be iterated
- yield path.replace(rs, '')
+ yield abs_path.replace(rs, '')
# END path exception handling
# END for each path
- def _write_path_to_stdin(self, proc, filepath, item, fmakeexc, fprogress,
- read_from_stdout=True):
+ def _write_path_to_stdin(self, proc: 'Popen', filepath: PathLike, item, fmakeexc, fprogress,
+ read_from_stdout: bool = True) -> Union[None, str]:
"""Write path to proc.stdin and make sure it processes the item, including progress.
:return: stdout string
@@ -417,20 +434,24 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
we will close stdin to break the pipe."""
fprogress(filepath, False, item)
- rval = None
- try:
- proc.stdin.write(("%s\n" % filepath).encode(defenc))
- except IOError as e:
- # pipe broke, usually because some error happened
- raise fmakeexc() from e
- # END write exception handling
- proc.stdin.flush()
- if read_from_stdout:
+ rval = None # type: Union[None, str]
+
+ if proc.stdin is not None:
+ try:
+ proc.stdin.write(("%s\n" % filepath).encode(defenc))
+ except IOError as e:
+ # pipe broke, usually because some error happened
+ raise fmakeexc() from e
+ # END write exception handling
+ proc.stdin.flush()
+
+ if read_from_stdout and proc.stdout is not None:
rval = proc.stdout.readline().strip()
fprogress(filepath, True, item)
return rval
- def iter_blobs(self, predicate=lambda t: True):
+ def iter_blobs(self, predicate: Callable[[Tuple[StageType, Blob]], bool] = lambda t: True
+ ) -> Iterator[Tuple[StageType, Blob]]:
"""
:return: Iterator yielding tuples of Blob objects and stages, tuple(stage, Blob)
@@ -446,12 +467,13 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
yield output
# END for each entry
- def unmerged_blobs(self):
+ def unmerged_blobs(self) -> Dict[PathLike, List[Tuple[StageType, Blob]]]:
"""
:return:
Iterator yielding dict(path : list( tuple( stage, Blob, ...))), being
a dictionary associating a path in the index with a list containing
sorted stage/blob pairs
+ ##### Does it return iterator? or just the Dict?
:note:
Blobs that have been removed in one side simply do not exist in the
@@ -459,7 +481,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
are at stage 3 will not have a stage 3 entry.
"""
is_unmerged_blob = lambda t: t[0] != 0
- path_map = {}
+ path_map = {} # type: Dict[PathLike, List[Tuple[TBD, Blob]]]
for stage, blob in self.iter_blobs(is_unmerged_blob):
path_map.setdefault(blob.path, []).append((stage, blob))
# END for each unmerged blob
@@ -468,10 +490,10 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
return path_map
@classmethod
- def entry_key(cls, *entry):
- return entry_key(*entry)
+ def entry_key(cls, entry: Union[Tuple[BaseIndexEntry], Tuple[PathLike, StageType]]) -> Tuple[PathLike, StageType]:
+ return entry_key(entry)
- def resolve_blobs(self, iter_blobs):
+ def resolve_blobs(self, iter_blobs: Iterator[Blob]) -> 'IndexFile':
"""Resolve the blobs given in blob iterator. This will effectively remove the
index entries of the respective path at all non-null stages and add the given
blob as new stage null blob.
@@ -489,9 +511,9 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
for blob in iter_blobs:
stage_null_key = (blob.path, 0)
if stage_null_key in self.entries:
- raise ValueError("Path %r already exists at stage 0" % blob.path)
+ raise ValueError("Path %r already exists at stage 0" % str(blob.path))
# END assert blob is not stage 0 already
-
+
# delete all possible stages
for stage in (1, 2, 3):
try:
@@ -506,7 +528,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
return self
- def update(self):
+ def update(self) -> 'IndexFile':
"""Reread the contents of our index file, discarding all cached information
we might have.
@@ -517,7 +539,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
# allows to lazily reread on demand
return self
- def write_tree(self):
+ def write_tree(self) -> Tree:
"""Writes this index to a corresponding Tree object into the repository's
object database and return it.
@@ -542,7 +564,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
root_tree._cache = tree_items
return root_tree
- def _process_diff_args(self, args):
+ def _process_diff_args(self, args: Any) -> List[Any]:
try:
args.pop(args.index(self))
except IndexError:
@@ -550,14 +572,14 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable):
# END remove self
return args
- def _to_relative_path(self, path):
+ def _to_relative_path(self, path: PathLike) -> PathLike:
""":return: Version of path relative to our git directory or raise ValueError
if it is not within our git direcotory"""
if not osp.isabs(path):
return path
if self.repo.bare:
raise InvalidGitRepositoryError("require non-bare repository")
- if not path.startswith(self.repo.working_tree_dir):
+ if not str(path).startswith(str(self.repo.working_tree_dir)):
raise ValueError("Absolute path %r is not in git repository at %r" % (path, self.repo.working_tree_dir))
return os.path.relpath(path, self.repo.working_tree_dir)