[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/Dev69/GitPython/master/git/objects/submodule/base.py [Back]  [Original]

# need a dict to set bloody .name field
from io import BytesIO
import logging
import os
import stat
from unittest import SkipTest
import uuid

import git
from git.cmd import Git
from git.compat import (
    string_types,
    defenc,
    is_win,
)
from git.config import (
    SectionConstraint,
    GitConfigParser,
    cp
)
from git.exc import (
    InvalidGitRepositoryError,
    NoSuchPathError,
    RepositoryDirtyError
)
from git.objects.base import IndexObject, Object
from git.objects.util import Traversable
from git.util import (
    Iterable,
    join_path_native,
    to_native_path_linux,
    RemoteProgress,
    rmtree,
    unbare_repo
)
from git.util import HIDE_WINDOWS_KNOWN_ERRORS

import os.path as osp

from .util import (
    mkhead,
    sm_name,
    sm_section,
    SubmoduleConfigParser,
    find_first_remote_branch
)


__all__ = ["Submodule", "UpdateProgress"]


log = logging.getLogger('git.objects.submodule.base')
log.addHandler(logging.NullHandler())


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 =v1.8.0: move submodule repository to new name)

        As .gitmodules will be changed, you would need to make a commit afterwards. The changed .gitmodules file
        will already be added to the index

        :return: this submodule instance
        """
        if self.name == new_name:
            return self

        # .git/config
        with self.repo.config_writer() as pw:
            # As we ourselves didn't write anything about submodules into the parent .git/config,
            # we will not require it to exist, and just ignore missing entries.
            if pw.has_section(sm_section(self.name)):
                pw.rename_section(sm_section(self.name), sm_section(new_name))

        # .gitmodules
        with self.config_writer(write=True).config as cw:
            cw.rename_section(sm_section(self.name), sm_section(new_name))

        self._name = new_name

        # .git/modules
        mod = self.module()
        if mod.has_separate_working_tree():
            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 destination_module_abspath.startswith(mod.git_dir):
                tmp_dir = self._module_abspath(self.repo, self.path, str(uuid.uuid4()))
                os.renames(source_dir, tmp_dir)
                source_dir = tmp_dir
            # end handle self-containment
            os.renames(source_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

    #{ Query Interface

    @unbare_repo
    def module(self):
        """: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"""
        # late import to workaround circular dependencies
        module_checkout_abspath = self.abspath
        try:
            repo = git.Repo(module_checkout_abspath)
            if repo != self.repo:
                return repo
            # END handle repo uninitialized
        except (InvalidGitRepositoryError, NoSuchPathError):
            raise InvalidGitRepositoryError("No valid repository at %s" % module_checkout_abspath)
        else:
            raise InvalidGitRepositoryError("Repository at %r was not yet checked out" % module_checkout_abspath)
        # END handle exceptions

    def module_exists(self):
        """:return: True if our module exists and is a valid git repository. See module() method"""
        try:
            self.module()
            return True
        except Exception:
            return False
        # END handle exception

    def exists(self):
        """
        :return: True if the submodule exists, False otherwise. Please note that
            a submodule may exist (in the .gitmodules file) even though its module
            doesn't exist on disk"""
        # keep attributes for later, and restore them if we have no valid data
        # this way we do not actually alter the state of the object
        loc = locals()
        for attr in self._cache_attrs:
            try:
                if hasattr(self, attr):
                    loc[attr] = getattr(self, attr)
                # END if we have the attribute cache
            except (cp.NoSectionError, ValueError):
                # on PY3, this can happen apparently ... don't know why this doesn't happen on PY2
                pass
        # END for each attr
        self._clear_cache()

        try:
            try:
                self.path
                return True
            except Exception:
                return False
            # END handle exceptions
        finally:
            for attr in self._cache_attrs:
                if attr in loc:
                    setattr(self, attr, loc[attr])
                # END if we have a cache
            # END reapply each attribute
        # END handle object state consistency

    @property
    def branch(self):
        """: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)

    @property
    def branch_path(self):
        """
        :return: full (relative) path as string to the branch we would checkout
            from the remote and track"""
        return self._branch_path

    @property
    def branch_name(self):
        """:return: the name of the branch, which is the shortest possible branch name"""
        # use an instance method, for this we create a temporary Head instance
        # which uses a repository that is available at least ( it makes no difference )
        return git.Head(self.repo, self._branch_path).name

    @property
    def url(self):
        """:return: The url to the repository which our module-repository refers to"""
        return self._url

    @property
    def parent_commit(self):
        """: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:
            return self.repo.commit()
        return self._parent_commit

    @property
    def name(self):
        """:return: The name of this submodule. It is used to identify it within the
            .gitmodules file.
        :note: by default, the name is the path at which to find the submodule, but
            in git-python it should be a unique identifier similar to the identifiers
            used for remotes, which allows to change the path of the submodule
            easily
        """
        return self._name

    def config_reader(self):
        """
        :return: ConfigReader instance which allows you to qurey the configuration values
            of this submodule, as provided by the .gitmodules file
        :note: The config reader will actually read the data directly from the repository
            and thus does not need nor care about your working tree.
        :note: Should be cached by the caller and only kept as long as needed
        :raise IOError: If the .gitmodules file/blob could not be read"""
        return self._config_parser_constrained(read_only=True)

    def children(self):
        """
        :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

    #{ Iterable Interface

    @classmethod
    def iter_items(cls, repo, parent_commit='HEAD'):
        """:return: iterator yielding Submodule instances available in the given repository"""
        pc = repo.commit(parent_commit)         # parent commit instance
        try:
            parser = cls._config_parser(repo, pc, read_only=True)
        except IOError:
            return
        # END handle empty iterator

        rt = pc.tree                                # root tree

        for sms in parser.sections():
            n = sm_name(sms)
            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))
            # END handle optional information

            # get the binsha
            index = repo.index
            try:
                sm = rt[p]
            except KeyError:
                # try the index, maybe it was just added
                try:
                    entry = index.entries[index.entry_key(p, 0)]
                    sm = Submodule(repo, entry.binsha, entry.mode, entry.path)
                except KeyError:
                    # The submodule doesn't exist, probably it wasn't
                    # removed from the .gitmodules file.
                    continue
                # END handle keyerror
            # END handle critical error

            # fill in remaining info - saves time as it doesn't have to be parsed again
            sm._name = n
            if pc != repo.commit():
                sm._parent_commit = pc
            # end set only if not most recent !
            sm._branch_path = git.Head.to_full_path(b)
            sm._url = u

            yield sm
        # END for each section

    #} END iterable interface

Web Proxy Viewer  |  New URL  |  Original Page