121 lines
3.4 KiB
Python
121 lines
3.4 KiB
Python
# This module is part of GitPython and is released under the
|
|
# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/
|
|
|
|
__all__ = [
|
|
"sm_section",
|
|
"sm_name",
|
|
"mkhead",
|
|
"find_first_remote_branch",
|
|
"SubmoduleConfigParser",
|
|
]
|
|
|
|
from io import BytesIO
|
|
import weakref
|
|
|
|
import git
|
|
from git.config import GitConfigParser
|
|
from git.exc import InvalidGitRepositoryError
|
|
|
|
# typing -----------------------------------------------------------------------
|
|
|
|
from typing import Any, Sequence, TYPE_CHECKING, Union
|
|
|
|
from git.types import PathLike
|
|
|
|
if TYPE_CHECKING:
|
|
from weakref import ReferenceType
|
|
|
|
from git.refs import Head, RemoteReference
|
|
from git.remote import Remote
|
|
from git.repo import Repo
|
|
|
|
from .base import Submodule
|
|
|
|
# { Utilities
|
|
|
|
|
|
def sm_section(name: str) -> str:
|
|
""":return: Section title used in ``.gitmodules`` configuration file"""
|
|
return f'submodule "{name}"'
|
|
|
|
|
|
def sm_name(section: str) -> str:
|
|
""":return: Name of the submodule as parsed from the section name"""
|
|
section = section.strip()
|
|
return section[11:-1]
|
|
|
|
|
|
def mkhead(repo: "Repo", path: PathLike) -> "Head":
|
|
""":return: New branch/head instance"""
|
|
return git.Head(repo, git.Head.to_full_path(path))
|
|
|
|
|
|
def find_first_remote_branch(remotes: Sequence["Remote"], branch_name: str) -> "RemoteReference":
|
|
"""Find the remote branch matching the name of the given branch or raise
|
|
:exc:`~git.exc.InvalidGitRepositoryError`."""
|
|
for remote in remotes:
|
|
try:
|
|
return remote.refs[branch_name]
|
|
except IndexError:
|
|
continue
|
|
# END exception handling
|
|
# END for remote
|
|
raise InvalidGitRepositoryError("Didn't find remote branch '%r' in any of the given remotes" % branch_name)
|
|
|
|
|
|
# } END utilities
|
|
|
|
# { Classes
|
|
|
|
|
|
class SubmoduleConfigParser(GitConfigParser):
|
|
"""Catches calls to :meth:`~git.config.GitConfigParser.write`, and updates the
|
|
``.gitmodules`` blob in the index with the new data, if we have written into a
|
|
stream.
|
|
|
|
Otherwise it would add the local file to the index to make it correspond with the
|
|
working tree. Additionally, the cache must be cleared.
|
|
|
|
Please note that no mutating method will work in bare mode.
|
|
"""
|
|
|
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
self._smref: Union["ReferenceType[Submodule]", None] = None
|
|
self._index = None
|
|
self._auto_write = True
|
|
super().__init__(*args, **kwargs)
|
|
|
|
# { Interface
|
|
def set_submodule(self, submodule: "Submodule") -> None:
|
|
"""Set this instance's submodule. It must be called before the first write
|
|
operation begins."""
|
|
self._smref = weakref.ref(submodule)
|
|
|
|
def flush_to_index(self) -> None:
|
|
"""Flush changes in our configuration file to the index."""
|
|
assert self._smref is not None
|
|
# Should always have a file here.
|
|
assert not isinstance(self._file_or_files, BytesIO)
|
|
|
|
sm = self._smref()
|
|
if sm is not None:
|
|
index = self._index
|
|
if index is None:
|
|
index = sm.repo.index
|
|
# END handle index
|
|
index.add([sm.k_modules_file], write=self._auto_write)
|
|
sm._clear_cache()
|
|
# END handle weakref
|
|
|
|
# } END interface
|
|
|
|
# { Overridden Methods
|
|
def write(self) -> None: # type: ignore[override]
|
|
rval: None = super().write()
|
|
self.flush_to_index()
|
|
return rval
|
|
|
|
# END overridden methods
|
|
|
|
|
|
# } END classes
|