summaryrefslogtreecommitdiff
path: root/git/objects/submodule/base.py
diff options
context:
space:
mode:
authorSebastian Thiel <sebastian.thiel@icloud.com>2022-05-18 07:43:53 +0800
committerSebastian Thiel <sebastian.thiel@icloud.com>2022-05-18 07:43:53 +0800
commit21ec529987d10e0010badd37f8da3274167d436f (patch)
treea3394cfe902ce7edd07c89420c21c13274a2d295 /git/objects/submodule/base.py
parentb30720ee4d9762a03eae4fa7cfa4b0190d81784d (diff)
downloadgitpython-21ec529987d10e0010badd37f8da3274167d436f.tar.gz
Run everything through 'black'
That way people who use it won't be deterred, while it unifies style everywhere.
Diffstat (limited to 'git/objects/submodule/base.py')
-rw-r--r--git/objects/submodule/base.py536
1 files changed, 368 insertions, 168 deletions
diff --git a/git/objects/submodule/base.py b/git/objects/submodule/base.py
index f7820455..84a34206 100644
--- a/git/objects/submodule/base.py
+++ b/git/objects/submodule/base.py
@@ -11,16 +11,12 @@ from git.compat import (
defenc,
is_win,
)
-from git.config import (
- SectionConstraint,
- GitConfigParser,
- cp
-)
+from git.config import SectionConstraint, GitConfigParser, cp
from git.exc import (
InvalidGitRepositoryError,
NoSuchPathError,
RepositoryDirtyError,
- BadName
+ BadName,
)
from git.objects.base import IndexObject, Object
from git.objects.util import TraversableIterableObj
@@ -31,7 +27,7 @@ from git.util import (
RemoteProgress,
rmtree,
unbare_repo,
- IterableList
+ IterableList,
)
from git.util import HIDE_WINDOWS_KNOWN_ERRORS
@@ -42,7 +38,7 @@ from .util import (
sm_name,
sm_section,
SubmoduleConfigParser,
- find_first_remote_branch
+ find_first_remote_branch,
)
@@ -63,7 +59,7 @@ if TYPE_CHECKING:
__all__ = ["Submodule", "UpdateProgress"]
-log = logging.getLogger('git.objects.submodule.base')
+log = logging.getLogger("git.objects.submodule.base")
log.addHandler(logging.NullHandler())
@@ -71,7 +67,11 @@ class UpdateProgress(RemoteProgress):
"""Class providing detailed progress information to the caller who should
derive from it and implement the ``update(...)`` message"""
- CLONE, FETCH, UPDWKTREE = [1 << x for x in range(RemoteProgress._num_op_codes, RemoteProgress._num_op_codes + 3)]
+
+ CLONE, FETCH, UPDWKTREE = [
+ 1 << x
+ for x in range(RemoteProgress._num_op_codes, RemoteProgress._num_op_codes + 3)
+ ]
_num_op_codes: int = RemoteProgress._num_op_codes + 3
__slots__ = ()
@@ -98,25 +98,30 @@ class Submodule(IndexObject, TraversableIterableObj):
All methods work in bare and non-bare repositories."""
_id_attribute_ = "name"
- k_modules_file = '.gitmodules'
- k_head_option = 'branch'
- k_head_default = 'master'
- k_default_mode = stat.S_IFDIR | stat.S_IFLNK # submodules are directories with link-status
+ k_modules_file = ".gitmodules"
+ k_head_option = "branch"
+ k_head_default = "master"
+ k_default_mode = (
+ stat.S_IFDIR | stat.S_IFLNK
+ ) # submodules are directories with link-status
# this is a bogus type for base class compatibility
- type: Literal['submodule'] = 'submodule' # type: ignore
-
- __slots__ = ('_parent_commit', '_url', '_branch_path', '_name', '__weakref__')
- _cache_attrs = ('path', '_url', '_branch_path')
-
- def __init__(self, repo: 'Repo', binsha: bytes,
- mode: Union[int, None] = None,
- path: Union[PathLike, None] = None,
- name: Union[str, None] = None,
- parent_commit: Union[Commit_ish, None] = None,
- url: Union[str, None] = None,
- branch_path: Union[PathLike, None] = None
- ) -> None:
+ type: Literal["submodule"] = "submodule" # type: ignore
+
+ __slots__ = ("_parent_commit", "_url", "_branch_path", "_name", "__weakref__")
+ _cache_attrs = ("path", "_url", "_branch_path")
+
+ def __init__(
+ self,
+ repo: "Repo",
+ binsha: bytes,
+ mode: Union[int, None] = None,
+ path: Union[PathLike, None] = None,
+ name: Union[str, None] = None,
+ parent_commit: Union[Commit_ish, None] = None,
+ url: Union[str, None] = None,
+ branch_path: Union[PathLike, None] = None,
+ ) -> None:
"""Initialize this instance with its attributes. We only document the ones
that differ from ``IndexObject``
@@ -137,32 +142,38 @@ class Submodule(IndexObject, TraversableIterableObj):
self._name = name
def _set_cache_(self, attr: str) -> None:
- if attr in ('path', '_url', '_branch_path'):
+ if attr in ("path", "_url", "_branch_path"):
reader: SectionConstraint = self.config_reader()
# default submodule values
try:
- self.path = reader.get('path')
+ self.path = reader.get("path")
except cp.NoSectionError as e:
if self.repo.working_tree_dir is not None:
- raise ValueError("This submodule instance does not exist anymore in '%s' file"
- % osp.join(self.repo.working_tree_dir, '.gitmodules')) from e
+ raise ValueError(
+ "This submodule instance does not exist anymore in '%s' file"
+ % osp.join(self.repo.working_tree_dir, ".gitmodules")
+ ) from e
# end
- self._url = reader.get('url')
+ self._url = reader.get("url")
# git-python extension values - optional
- self._branch_path = reader.get_value(self.k_head_option, git.Head.to_full_path(self.k_head_default))
- elif attr == '_name':
- raise AttributeError("Cannot retrieve the name of a submodule if it was not set initially")
+ self._branch_path = reader.get_value(
+ self.k_head_option, git.Head.to_full_path(self.k_head_default)
+ )
+ elif attr == "_name":
+ raise AttributeError(
+ "Cannot retrieve the name of a submodule if it was not set initially"
+ )
else:
super(Submodule, self)._set_cache_(attr)
# END handle attribute name
@classmethod
- def _get_intermediate_items(cls, item: 'Submodule') -> IterableList['Submodule']:
+ def _get_intermediate_items(cls, item: "Submodule") -> IterableList["Submodule"]:
""":return: all the submodules of our module repository"""
try:
return cls.list_items(item.module())
except InvalidGitRepositoryError:
- return IterableList('')
+ return IterableList("")
# END handle intermediate items
@classmethod
@@ -188,13 +199,18 @@ class Submodule(IndexObject, TraversableIterableObj):
return self._name
def __repr__(self) -> str:
- return "git.%s(name=%s, path=%s, url=%s, branch_path=%s)"\
- % (type(self).__name__, self._name, self.path, self.url, self.branch_path)
+ return "git.%s(name=%s, path=%s, url=%s, branch_path=%s)" % (
+ type(self).__name__,
+ self._name,
+ self.path,
+ self.url,
+ self.branch_path,
+ )
@classmethod
- def _config_parser(cls, repo: 'Repo',
- parent_commit: Union[Commit_ish, None],
- read_only: bool) -> SubmoduleConfigParser:
+ def _config_parser(
+ cls, repo: "Repo", parent_commit: Union[Commit_ish, None], read_only: bool
+ ) -> SubmoduleConfigParser:
""":return: Config Parser constrained to our submodule in read or write mode
:raise IOError: If the .gitmodules file cannot be found, either locally or in the repository
at the given parent commit. Otherwise the exception would be delayed until the first
@@ -211,17 +227,23 @@ class Submodule(IndexObject, TraversableIterableObj):
if not repo.bare and parent_matches_head and repo.working_tree_dir:
fp_module = osp.join(repo.working_tree_dir, cls.k_modules_file)
else:
- assert parent_commit is not None, "need valid parent_commit in bare repositories"
+ assert (
+ parent_commit is not None
+ ), "need valid parent_commit in bare repositories"
try:
fp_module = cls._sio_modules(parent_commit)
except KeyError as e:
- raise IOError("Could not find %s file in the tree of parent commit %s" %
- (cls.k_modules_file, parent_commit)) from e
+ raise IOError(
+ "Could not find %s file in the tree of parent commit %s"
+ % (cls.k_modules_file, parent_commit)
+ ) from e
# END handle exceptions
# END handle non-bare working tree
if not read_only and (repo.bare or not parent_matches_head):
- raise ValueError("Cannot write blobs of 'historical' submodule configurations")
+ raise ValueError(
+ "Cannot write blobs of 'historical' submodule configurations"
+ )
# END handle writes of historical submodules
return SubmoduleConfigParser(fp_module, read_only=read_only)
@@ -246,7 +268,7 @@ class Submodule(IndexObject, TraversableIterableObj):
def _config_parser_constrained(self, read_only: bool) -> SectionConstraint:
""":return: Config Parser constrained to our submodule in read or write mode"""
try:
- pc: Union['Commit_ish', None] = self.parent_commit
+ pc: Union["Commit_ish", None] = self.parent_commit
except ValueError:
pc = None
# end handle empty parent repository
@@ -255,16 +277,20 @@ class Submodule(IndexObject, TraversableIterableObj):
return SectionConstraint(parser, sm_section(self.name))
@classmethod
- def _module_abspath(cls, parent_repo: 'Repo', path: PathLike, name: str) -> PathLike:
+ def _module_abspath(
+ cls, parent_repo: "Repo", path: PathLike, name: str
+ ) -> PathLike:
if cls._need_gitfile_submodules(parent_repo.git):
- return osp.join(parent_repo.git_dir, 'modules', name)
+ return osp.join(parent_repo.git_dir, "modules", name)
if parent_repo.working_tree_dir:
return osp.join(parent_repo.working_tree_dir, path)
raise NotADirectoryError()
# end
@classmethod
- def _clone_repo(cls, repo: 'Repo', url: str, path: PathLike, name: str, **kwargs: Any) -> 'Repo':
+ def _clone_repo(
+ cls, repo: "Repo", url: str, path: PathLike, name: str, **kwargs: Any
+ ) -> "Repo":
""":return: Repo instance of newly cloned repository
:param repo: our parent repository
:param url: url to clone from
@@ -274,7 +300,7 @@ class Submodule(IndexObject, TraversableIterableObj):
module_abspath = cls._module_abspath(repo, path, name)
module_checkout_path = module_abspath
if cls._need_gitfile_submodules(repo.git):
- kwargs['separate_git_dir'] = module_abspath
+ kwargs["separate_git_dir"] = module_abspath
module_abspath_dir = osp.dirname(module_abspath)
if not osp.isdir(module_abspath_dir):
os.makedirs(module_abspath_dir)
@@ -288,29 +314,36 @@ class Submodule(IndexObject, TraversableIterableObj):
return clone
@classmethod
- def _to_relative_path(cls, parent_repo: 'Repo', path: PathLike) -> PathLike:
+ def _to_relative_path(cls, parent_repo: "Repo", path: PathLike) -> PathLike:
""":return: a path guaranteed to be relative to the given parent - repository
:raise ValueError: if path is not contained in the parent repository's working tree"""
path = to_native_path_linux(path)
- if path.endswith('/'):
+ if path.endswith("/"):
path = path[:-1]
# END handle trailing slash
if osp.isabs(path) and parent_repo.working_tree_dir:
working_tree_linux = to_native_path_linux(parent_repo.working_tree_dir)
if not path.startswith(working_tree_linux):
- raise ValueError("Submodule checkout path '%s' needs to be within the parents repository at '%s'"
- % (working_tree_linux, path))
- path = path[len(working_tree_linux.rstrip('/')) + 1:]
+ raise ValueError(
+ "Submodule checkout path '%s' needs to be within the parents repository at '%s'"
+ % (working_tree_linux, path)
+ )
+ path = path[len(working_tree_linux.rstrip("/")) + 1 :]
if not path:
- raise ValueError("Absolute submodule path '%s' didn't yield a valid relative path" % path)
+ raise ValueError(
+ "Absolute submodule path '%s' didn't yield a valid relative path"
+ % path
+ )
# end verify converted relative path makes sense
# end convert to a relative path
return path
@classmethod
- def _write_git_file_and_module_config(cls, working_tree_dir: PathLike, module_abspath: PathLike) -> None:
+ def _write_git_file_and_module_config(
+ cls, working_tree_dir: PathLike, module_abspath: PathLike
+ ) -> None:
"""Writes a .git file containing a(preferably) relative path to the actual git module repository.
It is an error if the module_abspath cannot be made into a relative path, relative to the working_tree_dir
:note: will overwrite existing files !
@@ -320,26 +353,40 @@ class Submodule(IndexObject, TraversableIterableObj):
:param working_tree_dir: directory to write the .git file into
:param module_abspath: absolute path to the bare repository
"""
- git_file = osp.join(working_tree_dir, '.git')
+ git_file = osp.join(working_tree_dir, ".git")
rela_path = osp.relpath(module_abspath, start=working_tree_dir)
if is_win:
if osp.isfile(git_file):
os.remove(git_file)
- with open(git_file, 'wb') as fp:
+ with open(git_file, "wb") as fp:
fp.write(("gitdir: %s" % rela_path).encode(defenc))
- with GitConfigParser(osp.join(module_abspath, 'config'),
- read_only=False, merge_includes=False) as writer:
- writer.set_value('core', 'worktree',
- to_native_path_linux(osp.relpath(working_tree_dir, start=module_abspath)))
+ with GitConfigParser(
+ osp.join(module_abspath, "config"), read_only=False, merge_includes=False
+ ) as writer:
+ writer.set_value(
+ "core",
+ "worktree",
+ to_native_path_linux(
+ osp.relpath(working_tree_dir, start=module_abspath)
+ ),
+ )
- #{ Edit Interface
+ # { Edit Interface
@classmethod
- def add(cls, repo: 'Repo', name: str, path: PathLike, url: Union[str, None] = None,
- branch: Union[str, None] = None, no_checkout: bool = False, depth: Union[int, None] = None,
- env: Union[Mapping[str, str], None] = None, clone_multi_options: Union[Sequence[TBD], None] = None
- ) -> 'Submodule':
+ def add(
+ cls,
+ repo: "Repo",
+ name: str,
+ path: PathLike,
+ url: Union[str, None] = None,
+ branch: Union[str, None] = None,
+ no_checkout: bool = False,
+ depth: Union[int, None] = None,
+ env: Union[Mapping[str, str], None] = None,
+ clone_multi_options: Union[Sequence[TBD], None] = None,
+ ) -> "Submodule":
"""Add a new submodule to the given repository. This will alter the index
as well as the .gitmodules file, but will not create a new commit.
If the submodule already exists, no matter if the configuration differs
@@ -379,7 +426,9 @@ class Submodule(IndexObject, TraversableIterableObj):
update fails for instance"""
if repo.bare:
- raise InvalidGitRepositoryError("Cannot add submodules to bare repositories")
+ raise InvalidGitRepositoryError(
+ "Cannot add submodules to bare repositories"
+ )
# END handle bare repos
path = cls._to_relative_path(repo, path)
@@ -391,7 +440,14 @@ class Submodule(IndexObject, TraversableIterableObj):
# END assure url correctness
# INSTANTIATE INTERMEDIATE SM
- sm = cls(repo, cls.NULL_BIN_SHA, cls.k_default_mode, path, name, url='invalid-temporary')
+ sm = cls(
+ repo,
+ cls.NULL_BIN_SHA,
+ cls.k_default_mode,
+ path,
+ name,
+ url="invalid-temporary",
+ )
if sm.exists():
# reretrieve submodule from tree
try:
@@ -414,7 +470,9 @@ class Submodule(IndexObject, TraversableIterableObj):
if has_module and url is not None:
if url not in [r.url for r in sm.module().remotes]:
raise ValueError(
- "Specified URL '%s' does not match any remote url of the repository at '%s'" % (url, sm.abspath))
+ "Specified URL '%s' does not match any remote url of the repository at '%s'"
+ % (url, sm.abspath)
+ )
# END check url
# END verify urls match
@@ -422,29 +480,33 @@ class Submodule(IndexObject, TraversableIterableObj):
if url is None:
if not has_module:
- raise ValueError("A URL was not given and a repository did not exist at %s" % path)
+ raise ValueError(
+ "A URL was not given and a repository did not exist at %s" % path
+ )
# END check url
mrepo = sm.module()
# assert isinstance(mrepo, git.Repo)
urls = [r.url for r in mrepo.remotes]
if not urls:
- raise ValueError("Didn't find any remote url in repository at %s" % sm.abspath)
+ raise ValueError(
+ "Didn't find any remote url in repository at %s" % sm.abspath
+ )
# END verify we have url
url = urls[0]
else:
# clone new repo
- kwargs: Dict[str, Union[bool, int, str, Sequence[TBD]]] = {'n': no_checkout}
+ kwargs: Dict[str, Union[bool, int, str, Sequence[TBD]]] = {"n": no_checkout}
if not branch_is_default:
- kwargs['b'] = br.name
+ kwargs["b"] = br.name
# END setup checkout-branch
if depth:
if isinstance(depth, int):
- kwargs['depth'] = depth
+ kwargs["depth"] = depth
else:
raise ValueError("depth should be an integer")
if clone_multi_options:
- kwargs['multi_options'] = clone_multi_options
+ kwargs["multi_options"] = clone_multi_options
# _clone_repo(cls, repo, url, path, name, **kwargs):
mrepo = cls._clone_repo(repo, url, path, name, env=env, **kwargs)
@@ -460,13 +522,13 @@ class Submodule(IndexObject, TraversableIterableObj):
writer: Union[GitConfigParser, SectionConstraint]
with sm.repo.config_writer() as writer:
- writer.set_value(sm_section(name), 'url', url)
+ writer.set_value(sm_section(name), "url", url)
# update configuration and index
index = sm.repo.index
with sm.config_writer(index=index, write=False) as writer:
- writer.set_value('url', url)
- writer.set_value('path', path)
+ writer.set_value("url", url)
+ writer.set_value("path", path)
sm._url = url
if not branch_is_default:
@@ -481,10 +543,18 @@ class Submodule(IndexObject, TraversableIterableObj):
return sm
- def update(self, recursive: bool = False, init: bool = True, to_latest_revision: bool = False,
- progress: Union['UpdateProgress', None] = None, dry_run: bool = False,
- force: bool = False, keep_going: bool = False, env: Union[Mapping[str, str], None] = None,
- clone_multi_options: Union[Sequence[TBD], None] = None) -> 'Submodule':
+ def update(
+ self,
+ recursive: bool = False,
+ init: bool = True,
+ to_latest_revision: bool = False,
+ progress: Union["UpdateProgress", None] = None,
+ dry_run: bool = False,
+ force: bool = False,
+ keep_going: bool = False,
+ env: Union[Mapping[str, str], None] = None,
+ clone_multi_options: Union[Sequence[TBD], None] = None,
+ ) -> "Submodule":
"""Update the repository of this submodule to point to the checkout
we point at with the binsha of this instance.
@@ -527,7 +597,7 @@ class Submodule(IndexObject, TraversableIterableObj):
if progress is None:
progress = UpdateProgress()
# END handle progress
- prefix = ''
+ prefix = ""
if dry_run:
prefix = "DRY-RUN: "
# END handle prefix
@@ -550,17 +620,27 @@ class Submodule(IndexObject, TraversableIterableObj):
op |= BEGIN
# END handle start
- progress.update(op, i, len_rmts, prefix + "Fetching remote %s of submodule %r"
- % (remote, self.name))
- #===============================
+ progress.update(
+ op,
+ i,
+ len_rmts,
+ prefix
+ + "Fetching remote %s of submodule %r" % (remote, self.name),
+ )
+ # ===============================
if not dry_run:
remote.fetch(progress=progress)
# END handle dry-run
- #===============================
+ # ===============================
if i == len_rmts - 1:
op |= END
# END handle end
- progress.update(op, i, len_rmts, prefix + "Done fetching remote of submodule %r" % self.name)
+ progress.update(
+ op,
+ i,
+ len_rmts,
+ prefix + "Done fetching remote of submodule %r" % self.name,
+ )
# END fetch new data
except InvalidGitRepositoryError:
mrepo = None
@@ -574,27 +654,49 @@ class Submodule(IndexObject, TraversableIterableObj):
try:
os.rmdir(checkout_module_abspath)
except OSError as e:
- raise OSError("Module directory at %r does already exist and is non-empty"
- % checkout_module_abspath) from e
+ raise OSError(
+ "Module directory at %r does already exist and is non-empty"
+ % checkout_module_abspath
+ ) from e
# END handle OSError
# END handle directory removal
# don't check it out at first - nonetheless it will create a local
# branch according to the remote-HEAD if possible
- progress.update(BEGIN | CLONE, 0, 1, prefix + "Cloning url '%s' to '%s' in submodule %r" %
- (self.url, checkout_module_abspath, self.name))
+ progress.update(
+ BEGIN | CLONE,
+ 0,
+ 1,
+ prefix
+ + "Cloning url '%s' to '%s' in submodule %r"
+ % (self.url, checkout_module_abspath, self.name),
+ )
if not dry_run:
- mrepo = self._clone_repo(self.repo, self.url, self.path, self.name, n=True, env=env,
- multi_options=clone_multi_options)
+ mrepo = self._clone_repo(
+ self.repo,
+ self.url,
+ self.path,
+ self.name,
+ n=True,
+ env=env,
+ multi_options=clone_multi_options,
+ )
# END handle dry-run
- progress.update(END | CLONE, 0, 1, prefix + "Done cloning to %s" % checkout_module_abspath)
+ progress.update(
+ END | CLONE,
+ 0,
+ 1,
+ prefix + "Done cloning to %s" % checkout_module_abspath,
+ )
if not dry_run:
# see whether we have a valid branch to checkout
try:
- mrepo = cast('Repo', mrepo)
+ mrepo = cast("Repo", mrepo)
# find a remote which has our branch - we try to be flexible
- remote_branch = find_first_remote_branch(mrepo.remotes, self.branch_name)
+ remote_branch = find_first_remote_branch(
+ mrepo.remotes, self.branch_name
+ )
local_branch = mkhead(mrepo, self.branch_path)
# have a valid branch, but no checkout - make sure we can figure
@@ -603,10 +705,15 @@ class Submodule(IndexObject, TraversableIterableObj):
# END initial checkout + branch creation
# make sure HEAD is not detached
- mrepo.head.set_reference(local_branch, logmsg="submodule: attaching head to %s" % local_branch)
+ mrepo.head.set_reference(
+ local_branch,
+ logmsg="submodule: attaching head to %s" % local_branch,
+ )
mrepo.head.reference.set_tracking_branch(remote_branch)
except (IndexError, InvalidGitRepositoryError):
- log.warning("Failed to checkout tracking branch %s", self.branch_path)
+ log.warning(
+ "Failed to checkout tracking branch %s", self.branch_path
+ )
# END handle tracking branch
# NOTE: Have to write the repo config file as well, otherwise
@@ -614,7 +721,7 @@ class Submodule(IndexObject, TraversableIterableObj):
# Maybe this is a good way to assure it doesn't get into our way, but
# we want to stay backwards compatible too ... . Its so redundant !
with self.repo.config_writer() as writer:
- writer.set_value(sm_section(self.name), 'url', self.url)
+ writer.set_value(sm_section(self.name), "url", self.url)
# END handle dry_run
# END handle initialization
@@ -628,7 +735,10 @@ class Submodule(IndexObject, TraversableIterableObj):
# END handle dry_run
if mrepo is not None and to_latest_revision:
- msg_base = "Cannot update to latest revision in repository at %r as " % mrepo.working_dir
+ msg_base = (
+ "Cannot update to latest revision in repository at %r as "
+ % mrepo.working_dir
+ )
if not is_detached:
rref = mrepo.head.reference.tracking_branch()
if rref is not None:
@@ -636,8 +746,11 @@ class Submodule(IndexObject, TraversableIterableObj):
binsha = rcommit.binsha
hexsha = rcommit.hexsha
else:
- log.error("%s a tracking branch was not set for local branch '%s'",
- msg_base, mrepo.head.reference)
+ log.error(
+ "%s a tracking branch was not set for local branch '%s'",
+ msg_base,
+ mrepo.head.reference,
+ )
# END handle remote ref
else:
log.error("%s there was no local tracking branch", msg_base)
@@ -654,28 +767,47 @@ class Submodule(IndexObject, TraversableIterableObj):
may_reset = True
if mrepo.head.commit.binsha != self.NULL_BIN_SHA:
base_commit = mrepo.merge_base(mrepo.head.commit, hexsha)
- if len(base_commit) == 0 or (base_commit[0] is not None and base_commit[0].hexsha == hexsha):
+ if len(base_commit) == 0 or (
+ base_commit[0] is not None and base_commit[0].hexsha == hexsha
+ ):
if force:
msg = "Will force checkout or reset on local branch that is possibly in the future of"
msg += "the commit it will be checked out to, effectively 'forgetting' new commits"
log.debug(msg)
else:
msg = "Skipping %s on branch '%s' of submodule repo '%s' as it contains un-pushed commits"
- msg %= (is_detached and "checkout" or "reset", mrepo.head, mrepo)
+ msg %= (
+ is_detached and "checkout" or "reset",
+ mrepo.head,
+ mrepo,
+ )
log.info(msg)
may_reset = False
# end handle force
# end handle if we are in the future
- if may_reset and not force and mrepo.is_dirty(index=True, working_tree=True, untracked_files=True):
- raise RepositoryDirtyError(mrepo, "Cannot reset a dirty repository")
+ if (
+ may_reset
+ and not force
+ and mrepo.is_dirty(
+ index=True, working_tree=True, untracked_files=True
+ )
+ ):
+ raise RepositoryDirtyError(
+ mrepo, "Cannot reset a dirty repository"
+ )
# end handle force and dirty state
# end handle empty repo
# end verify future/past
- progress.update(BEGIN | UPDWKTREE, 0, 1, prefix +
- "Updating working tree at %s for submodule %r to revision %s"
- % (self.path, self.name, hexsha))
+ progress.update(
+ BEGIN | UPDWKTREE,
+ 0,
+ 1,
+ prefix
+ + "Updating working tree at %s for submodule %r to revision %s"
+ % (self.path, self.name, hexsha),
+ )
if not dry_run and may_reset:
if is_detached:
@@ -688,8 +820,12 @@ class Submodule(IndexObject, TraversableIterableObj):
mrepo.head.reset(hexsha, index=True, working_tree=True)
# END handle checkout
# if we may reset/checkout
- progress.update(END | UPDWKTREE, 0, 1, prefix + "Done updating working tree for submodule %r"
- % self.name)
+ progress.update(
+ END | UPDWKTREE,
+ 0,
+ 1,
+ prefix + "Done updating working tree for submodule %r" % self.name,
+ )
# END update to new commit only if needed
except Exception as err:
if not keep_going:
@@ -703,8 +839,15 @@ class Submodule(IndexObject, TraversableIterableObj):
# in dry_run mode, the module might not exist
if mrepo is not None:
for submodule in self.iter_items(self.module()):
- submodule.update(recursive, init, to_latest_revision, progress=progress, dry_run=dry_run,
- force=force, keep_going=keep_going)
+ submodule.update(
+ recursive,
+ init,
+ to_latest_revision,
+ progress=progress,
+ dry_run=dry_run,
+ force=force,
+ keep_going=keep_going,
+ )
# END handle recursive update
# END handle dry run
# END for each submodule
@@ -712,7 +855,9 @@ class Submodule(IndexObject, TraversableIterableObj):
return self
@unbare_repo
- def move(self, module_path: PathLike, configuration: bool = True, module: bool = True) -> 'Submodule':
+ def move(
+ self, module_path: PathLike, configuration: bool = True, module: bool = True
+ ) -> "Submodule":
"""Move the submodule to a another module path. This involves physically moving
the repository at our current path, changing the configuration, as well as
adjusting our index entry accordingly.
@@ -732,7 +877,9 @@ class Submodule(IndexObject, TraversableIterableObj):
in an inconsistent state if a sub - step fails for some reason
"""
if module + configuration < 1:
- raise ValueError("You must specify to move at least the module or the configuration of the submodule")
+ raise ValueError(
+ "You must specify to move at least the module or the configuration of the submodule"
+ )
# END handle input
module_checkout_path = self._to_relative_path(self.repo, module_path)
@@ -742,9 +889,13 @@ class Submodule(IndexObject, TraversableIterableObj):
return self
# END handle no change
- module_checkout_abspath = join_path_native(str(self.repo.working_tree_dir), module_checkout_path)
+ module_checkout_abspath = join_path_native(
+ str(self.repo.working_tree_dir), module_checkout_path
+ )
if osp.isfile(module_checkout_abspath):
- raise ValueError("Cannot move repository onto a file: %s" % module_checkout_abspath)
+ raise ValueError(
+ "Cannot move repository onto a file: %s" % module_checkout_abspath
+ )
# END handle target files
index = self.repo.index
@@ -780,9 +931,11 @@ class Submodule(IndexObject, TraversableIterableObj):
os.renames(cur_path, module_checkout_abspath)
renamed_module = True
- if osp.isfile(osp.join(module_checkout_abspath, '.git')):
+ if osp.isfile(osp.join(module_checkout_abspath, ".git")):
module_abspath = self._module_abspath(self.repo, self.path, self.name)
- self._write_git_file_and_module_config(module_checkout_abspath, module_abspath)
+ self._write_git_file_and_module_config(
+ module_checkout_abspath, module_abspath
+ )
# end handle git file rewrite
# END move physical module
@@ -794,16 +947,20 @@ class Submodule(IndexObject, TraversableIterableObj):
try:
ekey = index.entry_key(self.path, 0)
entry = index.entries[ekey]
- del(index.entries[ekey])
- nentry = git.IndexEntry(entry[:3] + (module_checkout_path,) + entry[4:])
+ del index.entries[ekey]
+ nentry = git.IndexEntry(
+ entry[:3] + (module_checkout_path,) + entry[4:]
+ )
index.entries[tekey] = nentry
except KeyError as e:
- raise InvalidGitRepositoryError("Submodule's entry at %r did not exist" % (self.path)) from e
+ raise InvalidGitRepositoryError(
+ "Submodule's entry at %r did not exist" % (self.path)
+ ) from e
# END handle submodule doesn't exist
# update configuration
- with self.config_writer(index=index) as writer: # auto-write
- writer.set_value('path', module_checkout_path)
+ with self.config_writer(index=index) as writer: # auto-write
+ writer.set_value("path", module_checkout_path)
self.path = module_checkout_path
# END handle configuration flag
except Exception:
@@ -821,8 +978,13 @@ class Submodule(IndexObject, TraversableIterableObj):
return self
@unbare_repo
- def remove(self, module: bool = True, force: bool = False,
- configuration: bool = True, dry_run: bool = False) -> 'Submodule':
+ def remove(
+ self,
+ module: bool = True,
+ force: bool = False,
+ configuration: bool = True,
+ dry_run: bool = False,
+ ) -> "Submodule":
"""Remove this submodule from the repository. This will remove our entry
from the .gitmodules file and the entry in the .git / config file.
@@ -850,7 +1012,9 @@ class Submodule(IndexObject, TraversableIterableObj):
:raise InvalidGitRepositoryError: thrown if the repository cannot be deleted
:raise OSError: if directories or files could not be removed"""
if not (module or configuration):
- raise ValueError("Need to specify to delete at least the module, or the configuration")
+ raise ValueError(
+ "Need to specify to delete at least the module, or the configuration"
+ )
# END handle parameters
# Recursively remove children of this submodule
@@ -858,12 +1022,14 @@ class Submodule(IndexObject, TraversableIterableObj):
for csm in self.children():
nc += 1
csm.remove(module, force, configuration, dry_run)
- del(csm)
+ del csm
# end
if configuration and not dry_run and nc > 0:
# Assure we don't leave the parent repository in a dirty state, and commit our changes
# It's important for recursive, unforced, deletions to work as expected
- self.module().index.commit("Removed at least one of child-modules of '%s'" % self.name)
+ self.module().index.commit(
+ "Removed at least one of child-modules of '%s'" % self.name
+ )
# end handle recursion
# DELETE REPOSITORY WORKING TREE
@@ -882,7 +1048,9 @@ class Submodule(IndexObject, TraversableIterableObj):
elif osp.isdir(mp):
method = rmtree
elif osp.exists(mp):
- raise AssertionError("Cannot forcibly delete repository as it was neither a link, nor a directory")
+ raise AssertionError(
+ "Cannot forcibly delete repository as it was neither a link, nor a directory"
+ )
# END handle brutal deletion
if not dry_run:
assert method
@@ -893,7 +1061,8 @@ class Submodule(IndexObject, TraversableIterableObj):
if mod.is_dirty(index=True, working_tree=True, untracked_files=True):
raise InvalidGitRepositoryError(
"Cannot delete module at %s with any modifications, unless force is specified"
- % mod.working_tree_dir)
+ % mod.working_tree_dir
+ )
# END check for dirt
# figure out whether we have new commits compared to the remotes
@@ -910,30 +1079,36 @@ class Submodule(IndexObject, TraversableIterableObj):
# not a single remote branch contained all our commits
if len(rrefs) and num_branches_with_new_commits == len(rrefs):
raise InvalidGitRepositoryError(
- "Cannot delete module at %s as there are new commits" % mod.working_tree_dir)
+ "Cannot delete module at %s as there are new commits"
+ % mod.working_tree_dir
+ )
# END handle new commits
# have to manually delete references as python's scoping is
# not existing, they could keep handles open ( on windows this is a problem )
if len(rrefs):
- del(rref) # skipcq: PYL-W0631
+ del rref # skipcq: PYL-W0631
# END handle remotes
- del(rrefs)
- del(remote)
+ del rrefs
+ del remote
# END for each remote
# finally delete our own submodule
if not dry_run:
self._clear_cache()
wtd = mod.working_tree_dir
- del(mod) # release file-handles (windows)
+ del mod # release file-handles (windows)
import gc
+
gc.collect()
try:
rmtree(str(wtd))
except Exception as ex:
if HIDE_WINDOWS_KNOWN_ERRORS:
from unittest import SkipTest
- raise SkipTest("FIXME: fails with: PermissionError\n {}".format(ex)) from ex
+
+ raise SkipTest(
+ "FIXME: fails with: PermissionError\n {}".format(ex)
+ ) from ex
raise
# END delete tree if possible
# END handle force
@@ -945,7 +1120,10 @@ class Submodule(IndexObject, TraversableIterableObj):
except Exception as ex:
if HIDE_WINDOWS_KNOWN_ERRORS:
from unittest import SkipTest
- raise SkipTest(f"FIXME: fails with: PermissionError\n {ex}") from ex
+
+ raise SkipTest(
+ f"FIXME: fails with: PermissionError\n {ex}"
+ ) from ex
else:
raise
# end handle separate bare repository
@@ -961,7 +1139,7 @@ class Submodule(IndexObject, TraversableIterableObj):
# first the index-entry
parent_index = self.repo.index
try:
- del(parent_index.entries[parent_index.entry_key(self.path, 0)])
+ del parent_index.entries[parent_index.entry_key(self.path, 0)]
except KeyError:
pass
# END delete entry
@@ -979,7 +1157,9 @@ class Submodule(IndexObject, TraversableIterableObj):
return self
- def set_parent_commit(self, commit: Union[Commit_ish, None], check: bool = True) -> 'Submodule':
+ def set_parent_commit(
+ self, commit: Union[Commit_ish, None], check: bool = True
+ ) -> "Submodule":
"""Set this instance to use the given commit whose tree is supposed to
contain the .gitmodules blob.
@@ -1000,7 +1180,10 @@ class Submodule(IndexObject, TraversableIterableObj):
pcommit = self.repo.commit(commit)
pctree = pcommit.tree
if self.k_modules_file not in pctree:
- raise ValueError("Tree of commit %s did not contain the %s file" % (commit, self.k_modules_file))
+ raise ValueError(
+ "Tree of commit %s did not contain the %s file"
+ % (commit, self.k_modules_file)
+ )
# END handle exceptions
prev_pc = self._parent_commit
@@ -1010,7 +1193,10 @@ class Submodule(IndexObject, TraversableIterableObj):
parser = self._config_parser(self.repo, self._parent_commit, read_only=True)
if not parser.has_section(sm_section(self.name)):
self._parent_commit = prev_pc
- raise ValueError("Submodule at path %r did not exist in parent commit %s" % (self.path, commit))
+ raise ValueError(
+ "Submodule at path %r did not exist in parent commit %s"
+ % (self.path, commit)
+ )
# END handle submodule did not exist
# END handle checking mode
@@ -1027,8 +1213,9 @@ class Submodule(IndexObject, TraversableIterableObj):
return self
@unbare_repo
- def config_writer(self, index: Union['IndexFile', None] = None, write: bool = True
- ) -> SectionConstraint['SubmoduleConfigParser']:
+ def config_writer(
+ self, index: Union["IndexFile", None] = None, write: bool = True
+ ) -> SectionConstraint["SubmoduleConfigParser"]:
""":return: a config writer instance allowing you to read and write the data
belonging to this submodule into the .gitmodules file.
@@ -1049,7 +1236,7 @@ class Submodule(IndexObject, TraversableIterableObj):
return writer
@unbare_repo
- def rename(self, new_name: str) -> 'Submodule':
+ def rename(self, new_name: str) -> "Submodule":
"""Rename this submodule
:note: This method takes care of renaming the submodule in various places, such as
@@ -1081,7 +1268,9 @@ class Submodule(IndexObject, TraversableIterableObj):
# .git/modules
mod = self.module()
if mod.has_separate_working_tree():
- destination_module_abspath = self._module_abspath(self.repo, self.path, new_name)
+ destination_module_abspath = self._module_abspath(
+ self.repo, self.path, new_name
+ )
source_dir = mod.git_dir
# Let's be sure the submodule name is not so obviously tied to a directory
if str(destination_module_abspath).startswith(str(mod.git_dir)):
@@ -1091,17 +1280,19 @@ class Submodule(IndexObject, TraversableIterableObj):
# end handle self-containment
os.renames(source_dir, destination_module_abspath)
if mod.working_tree_dir:
- self._write_git_file_and_module_config(mod.working_tree_dir, destination_module_abspath)
+ self._write_git_file_and_module_config(
+ mod.working_tree_dir, destination_module_abspath
+ )
# end move separate git repository
return self
- #} END edit interface
+ # } END edit interface
- #{ Query Interface
+ # { Query Interface
@unbare_repo
- def module(self) -> 'Repo':
+ def module(self) -> "Repo":
""":return: Repo instance initialized from the repository at our submodule path
:raise InvalidGitRepositoryError: if a repository was not available. This could
also mean that it was not yet initialized"""
@@ -1113,9 +1304,13 @@ class Submodule(IndexObject, TraversableIterableObj):
return repo
# END handle repo uninitialized
except (InvalidGitRepositoryError, NoSuchPathError) as e:
- raise InvalidGitRepositoryError("No valid repository at %s" % module_checkout_abspath) from e
+ raise InvalidGitRepositoryError(
+ "No valid repository at %s" % module_checkout_abspath
+ ) from e
else:
- raise InvalidGitRepositoryError("Repository at %r was not yet checked out" % module_checkout_abspath)
+ raise InvalidGitRepositoryError(
+ "Repository at %r was not yet checked out" % module_checkout_abspath
+ )
# END handle exceptions
def module_exists(self) -> bool:
@@ -1162,7 +1357,7 @@ class Submodule(IndexObject, TraversableIterableObj):
# END handle object state consistency
@property
- def branch(self) -> 'Head':
+ def branch(self) -> "Head":
""":return: The branch instance that we are to checkout
:raise InvalidGitRepositoryError: if our module is not yet checked out"""
return mkhead(self.module(), self._branch_path)
@@ -1187,7 +1382,7 @@ class Submodule(IndexObject, TraversableIterableObj):
return self._url
@property
- def parent_commit(self) -> 'Commit_ish':
+ def parent_commit(self) -> "Commit_ish":
""":return: Commit instance with the tree containing the .gitmodules file
:note: will always point to the current head's commit if it was not set explicitly"""
if self._parent_commit is None:
@@ -1215,22 +1410,27 @@ class Submodule(IndexObject, TraversableIterableObj):
:raise IOError: If the .gitmodules file/blob could not be read"""
return self._config_parser_constrained(read_only=True)
- def children(self) -> IterableList['Submodule']:
+ def children(self) -> IterableList["Submodule"]:
"""
:return: IterableList(Submodule, ...) an iterable list of submodules instances
which are children of this submodule or 0 if the submodule is not checked out"""
return self._get_intermediate_items(self)
- #} END query interface
+ # } END query interface
- #{ Iterable Interface
+ # { Iterable Interface
@classmethod
- def iter_items(cls, repo: 'Repo', parent_commit: Union[Commit_ish, str] = 'HEAD', *Args: Any, **kwargs: Any
- ) -> Iterator['Submodule']:
+ def iter_items(
+ cls,
+ repo: "Repo",
+ parent_commit: Union[Commit_ish, str] = "HEAD",
+ *Args: Any,
+ **kwargs: Any,
+ ) -> Iterator["Submodule"]:
""":return: iterator yielding Submodule instances available in the given repository"""
try:
- pc = repo.commit(parent_commit) # parent commit instance
+ pc = repo.commit(parent_commit) # parent commit instance
parser = cls._config_parser(repo, pc, read_only=True)
except (IOError, BadName):
return iter([])
@@ -1238,8 +1438,8 @@ class Submodule(IndexObject, TraversableIterableObj):
for sms in parser.sections():
n = sm_name(sms)
- p = parser.get(sms, 'path')
- u = parser.get(sms, 'url')
+ p = parser.get(sms, "path")
+ u = parser.get(sms, "url")
b = cls.k_head_default
if parser.has_option(sms, cls.k_head_option):
b = str(parser.get(sms, cls.k_head_option))
@@ -1248,7 +1448,7 @@ class Submodule(IndexObject, TraversableIterableObj):
# get the binsha
index = repo.index
try:
- rt = pc.tree # root tree
+ rt = pc.tree # root tree
sm = rt[p]
except KeyError:
# try the index, maybe it was just added
@@ -1273,4 +1473,4 @@ class Submodule(IndexObject, TraversableIterableObj):
yield sm
# END for each section
- #} END iterable interface
+ # } END iterable interface