Skip to content

Commit

Permalink
pygit2: implement status
Browse files Browse the repository at this point in the history
  • Loading branch information
dtrifiro committed Jul 26, 2022
1 parent 83b340a commit 34fb1f1
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 10 deletions.
72 changes: 69 additions & 3 deletions scmrepo/git/backend/pygit2.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,12 +602,78 @@ def checkout_index(
index.add(entry.path)
index.write()

def iter_remote_refs(self, url: str, base: Optional[str] = None, **kwargs):
raise NotImplementedError

def status(
self, ignored: bool = False, untracked_files: str = "all"
) -> Tuple[Mapping[str, Iterable[str]], Iterable[str], Iterable[str]]:
from pygit2 import (
GIT_STATUS_IGNORED,
GIT_STATUS_INDEX_DELETED,
GIT_STATUS_INDEX_MODIFIED,
GIT_STATUS_INDEX_NEW,
GIT_STATUS_WT_DELETED,
GIT_STATUS_WT_MODIFIED,
GIT_STATUS_WT_NEW,
GIT_STATUS_WT_RENAMED,
GIT_STATUS_WT_TYPECHANGE,
GIT_STATUS_WT_UNREADABLE,
)

staged: Mapping[str, List[str]] = {
"add": [],
"delete": [],
"modify": [],
}
unstaged: List[str] = []
untracked: List[str] = []
unreadable: List[str] = []

states = {
GIT_STATUS_WT_NEW: untracked,
GIT_STATUS_WT_MODIFIED: unstaged,
GIT_STATUS_WT_TYPECHANGE: staged["modify"],
GIT_STATUS_WT_DELETED: staged["modify"],
GIT_STATUS_WT_RENAMED: staged["modify"],
GIT_STATUS_INDEX_NEW: staged["add"],
GIT_STATUS_INDEX_MODIFIED: staged["modify"],
GIT_STATUS_INDEX_DELETED: staged["delete"],
GIT_STATUS_WT_UNREADABLE: unreadable,
}
if untracked_files != "no" and ignored:
states[GIT_STATUS_IGNORED] = untracked

for file, state in self.repo.status(
untracked_files=untracked_files, ignored=ignored
).items():
for git_state in states:
flag = state & git_state
if flag:
states[flag].append(file)

if unreadable:
import warnings

warnings.warn("Unreadable files: {', '.join(unreadable)}")

if os.name == "nt":
# pygit2 always returns posix paths, convert them to nt paths

def posix_to_nt(path: str) -> str:
return path.replace("/", "\\")

staged = {
status: [posix_to_nt(path) for path in paths]
for status, paths in staged.items()
}
unstaged = [posix_to_nt(path) for path in unstaged]
untracked = [posix_to_nt(path) for path in untracked]

return (
{status: paths for status, paths in staged.items() if paths},
unstaged,
untracked,
)

def iter_remote_refs(self, url: str, base: Optional[str] = None, **kwargs):
raise NotImplementedError

def merge(
Expand Down
23 changes: 16 additions & 7 deletions tests/test_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -939,17 +939,26 @@ def test_fetch(
assert target.get_ref("refs/remotes/origin/master") == rev


@pytest.mark.skip_git_backend("pygit2", "gitpython")
@pytest.mark.parametrize("untracked_files", ["all", "no"])
@pytest.mark.skip_git_backend("gitpython")
@pytest.mark.parametrize("untracked_files", ["all", "no", "normal"])
@pytest.mark.parametrize("ignored", [False, True])
def test_status(
request,
tmp_dir: TmpDir,
scm: Git,
git: Git,
tmp_dir_factory: TempDirFactory,
untracked_files: str,
ignored: bool,
):
if (
untracked_files == "normal"
and request.getfixturevalue("git_backend") == "dulwich"
):
pytest.skip(
"untracked_files=normal is not implemented for dulwich",
)

tmp_dir.gen(
{
"foo": "foo",
Expand Down Expand Up @@ -979,12 +988,12 @@ def test_status(
expected_untracked = []
if ignored and untracked_files != "no":
expected_untracked.append("ignored")
if untracked_files != "no":
expected_untracked.append(
os.path.join("untracked_dir", "subfolder", "subfile")
)
if untracked_files == "all":
expected_untracked.append("untracked_dir/subfolder/subfile")
elif untracked_files == "normal":
expected_untracked.append("untracked_dir/")

git.add("foo")
scm.add("foo")
staged, unstaged, untracked = git.status(ignored, untracked_files)

assert staged["modify"] == ["foo"]
Expand Down

0 comments on commit 34fb1f1

Please sign in to comment.