diff options
author | Sebastian Thiel <sebastian.thiel@icloud.com> | 2022-05-18 07:43:53 +0800 |
---|---|---|
committer | Sebastian Thiel <sebastian.thiel@icloud.com> | 2022-05-18 07:43:53 +0800 |
commit | 21ec529987d10e0010badd37f8da3274167d436f (patch) | |
tree | a3394cfe902ce7edd07c89420c21c13274a2d295 /git/objects/submodule/base.py | |
parent | b30720ee4d9762a03eae4fa7cfa4b0190d81784d (diff) | |
download | gitpython-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.py | 536 |
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 |