Ejemplo n.º 1
0
    def add(self, paths: Union[str, Iterable[str]], update=False):
        assert paths or update

        if isinstance(paths, str):
            paths = [paths]

        if update and not paths:
            self.repo.stage(list(self.repo.open_index()))
            return

        files: List[bytes] = []
        for path in paths:
            if not os.path.isabs(path) and self._submodules:
                # NOTE: If path is inside a submodule, Dulwich expects the
                # staged paths to be relative to the submodule root (not the
                # parent git repo root). We append path to root_dir here so
                # that the result of relpath(path, root_dir) is actually the
                # path relative to the submodule root.
                fs_path = relpath(path, self.root_dir)
                for sm_path in self._submodules.values():
                    if fs_path.startswith(sm_path):
                        path = os.path.join(
                            self.root_dir,
                            relpath(fs_path, sm_path),
                        )
                        break
            if os.path.isdir(path):
                files.extend(
                    os.fsencode(
                        relpath(os.path.join(root, fpath), self.root_dir))
                    for root, _, fs in os.walk(path) for fpath in fs)
            else:
                files.append(os.fsencode(relpath(path, self.root_dir)))

        # NOTE: this doesn't check gitignore, same as GitPythonBackend.add
        if update:
            index = self.repo.open_index()
            if os.name == "nt":
                # NOTE: we need git/unix separator to compare against index
                # paths but repo.stage() expects to be called with OS paths
                self.repo.stage([
                    fname for fname in files
                    if fname.replace(b"\\", b"/") in index
                ])
            else:
                self.repo.stage([fname for fname in files if fname in index])
        else:
            self.repo.stage(files)
Ejemplo n.º 2
0
 def checkout_index(
     self,
     paths: Optional[Iterable[str]] = None,
     force: bool = False,
     ours: bool = False,
     theirs: bool = False,
 ):
     """Checkout the specified paths from HEAD index."""
     assert not (ours and theirs)
     if ours or theirs:
         args = ["--ours"] if ours else ["--theirs"]
         if force:
             args.append("--force")
         args.append("--")
         if paths:
             args.extend(list(paths))
         else:
             args.append(".")
         self.repo.git.checkout(*args)
     else:
         if paths:
             paths_list: Optional[List[str]] = [
                 relpath(path, self.root_dir) for path in paths
             ]
             if os.name == "nt":
                 paths_list = [
                     path.replace("\\", "/")
                     for path in paths_list  # type: ignore[union-attr]
                 ]
         else:
             paths_list = None
         self.repo.index.checkout(paths=paths_list, force=force)
Ejemplo n.º 3
0
 def is_tracked(self, path: str) -> bool:
     rel = relpath(path, self.root_dir).replace(os.path.sep, "/").encode()
     rel_dir = rel + b"/"
     for p in self.repo.open_index():
         if p == rel or p.startswith(rel_dir):
             return True
     return False
Ejemplo n.º 4
0
 def is_ignored(self, path: "Union[str, os.PathLike[str]]") -> bool:
     # `is_ignored` returns `false` if excluded in `.gitignore` and
     # `None` if it's not mentioned at all. `True` if it is ignored.
     relative_path = relpath(path, self.root_dir)
     # if checking a directory, a trailing slash must be included
     if str(path)[-1] == os.sep:
         relative_path += os.sep
     return bool(self.ignore_manager.is_ignored(relative_path))
Ejemplo n.º 5
0
    def checkout_index(
        self,
        paths: Optional[Iterable[str]] = None,
        force: bool = False,
        ours: bool = False,
        theirs: bool = False,
    ):
        from pygit2 import (
            GIT_CHECKOUT_ALLOW_CONFLICTS,
            GIT_CHECKOUT_FORCE,
            GIT_CHECKOUT_RECREATE_MISSING,
            GIT_CHECKOUT_SAFE,
        )

        assert not (ours and theirs)
        strategy = GIT_CHECKOUT_RECREATE_MISSING
        if force or ours or theirs:
            strategy |= GIT_CHECKOUT_FORCE
        else:
            strategy |= GIT_CHECKOUT_SAFE

        if ours or theirs:
            strategy |= GIT_CHECKOUT_ALLOW_CONFLICTS
        strategy = self._get_checkout_strategy(strategy)

        index = self.repo.index
        if paths:
            path_list: Optional[List[str]] = [
                relpath(path, self.root_dir) for path in paths
            ]
            if os.name == "nt":
                path_list = [
                    path.replace("\\", "/")
                    for path in path_list  # type: ignore[union-attr]
                ]
        else:
            path_list = None

        with self.release_odb_handles():
            self.repo.checkout_index(index=index,
                                     paths=path_list,
                                     strategy=strategy)

            if index.conflicts and (ours or theirs):
                for ancestor, ours_entry, theirs_entry in index.conflicts:
                    if not ancestor:
                        continue
                    if ours:
                        entry = ours_entry
                        index.add(ours_entry)
                    else:
                        entry = theirs_entry
                    path = os.path.join(self.root_dir, entry.path)
                    with open(path, "wb") as fobj:
                        fobj.write(self.repo.get(entry.id).read_raw())
                    index.add(entry.path)
                index.write()
Ejemplo n.º 6
0
    def _get_key(self, path: str) -> Tuple[str, ...]:
        from dvc.scm.utils import relpath

        if os.path.isabs(path):
            path = relpath(path, self.root_dir)
        relparts = path.split(os.sep)
        if relparts == ["."]:
            return ()
        return tuple(relparts)
Ejemplo n.º 7
0
 def reset(self, hard: bool = False, paths: Iterable[str] = None):
     if paths:
         paths_list: Optional[List[str]] = [
             relpath(path, self.root_dir) for path in paths
         ]
         if os.name == "nt":
             paths_list = [
                 path.replace("\\", "/")
                 for path in paths_list  # type: ignore[union-attr]
             ]
     else:
         paths_list = None
     self.repo.head.reset(index=True, working_tree=hard, paths=paths_list)
Ejemplo n.º 8
0
    def reset(self, hard: bool = False, paths: Iterable[str] = None):
        from pygit2 import GIT_RESET_HARD, GIT_RESET_MIXED, IndexEntry

        self.repo.index.read(False)
        if paths is not None:
            tree = self.repo.revparse_single("HEAD").tree
            for path in paths:
                rel = relpath(path, self.root_dir)
                if os.name == "nt":
                    rel = rel.replace("\\", "/")
                obj = tree[rel]
                self.repo.index.add(IndexEntry(rel, obj.oid, obj.filemode))
            self.repo.index.write()
        elif hard:
            self.repo.reset(self.repo.head.target, GIT_RESET_HARD)
        else:
            self.repo.reset(self.repo.head.target, GIT_RESET_MIXED)
Ejemplo n.º 9
0
    def _get_gitignore(self, path):
        ignore_file_dir = os.path.dirname(path)

        assert os.path.isabs(path)
        assert os.path.isabs(ignore_file_dir)

        entry = relpath(path, ignore_file_dir).replace(os.sep, "/")
        # NOTE: using '/' prefix to make path unambiguous
        if len(entry) > 0 and entry[0] != "/":
            entry = "/" + entry

        gitignore = os.path.join(ignore_file_dir, self.GITIGNORE)

        if not os.path.realpath(gitignore).startswith(self.root_dir + os.sep):
            raise FileNotInRepoError(
                f"'{path}' is outside of git repository '{self.root_dir}'")

        return entry, gitignore
Ejemplo n.º 10
0
 def is_ignored(self, path: "Union[str, os.PathLike[str]]") -> bool:
     rel = relpath(path, self.root_dir)
     if os.name == "nt":
         rel.replace("\\", "/")
     return self.repo.path_is_ignored(rel)