diff --git a/scmrepo/git/__init__.py b/scmrepo/git/__init__.py index d3b7ebbb..69153a96 100644 --- a/scmrepo/git/__init__.py +++ b/scmrepo/git/__init__.py @@ -363,6 +363,8 @@ def add_commit( validate_git_remote = partialmethod(_backend_func, "validate_git_remote") check_ref_format = partialmethod(_backend_func, "check_ref_format") + get_tree_obj = partialmethod(_backend_func, "get_tree_obj") + def branch_revs( self, branch: str, end_rev: Optional[str] = None ) -> Iterable[str]: diff --git a/tests/conftest.py b/tests/conftest.py index 794b1f77..3b354945 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -74,6 +74,35 @@ def scm(tmp_dir: TmpDir) -> Iterator[Git]: git_.close() +backends = ["gitpython", "dulwich", "pygit2"] + + +@pytest.fixture(params=backends) +def git_backend(request) -> str: + marker = request.node.get_closest_marker("skip_git_backend") + to_skip = marker.args if marker else [] + + backend = request.param + if backend in to_skip: + pytest.skip() + return backend + + +@pytest.fixture +def git(tmp_dir: TmpDir, git_backend: str) -> Iterator[Git]: + git_ = Git(tmp_dir, backends=[git_backend]) + yield git_ + git_.close() + + +@pytest.fixture +def remote_git_dir(tmp_dir_factory: TempDirFactory): + git_dir = tmp_dir_factory.mktemp("git-remote") + remote_git = Git.init(git_dir) + remote_git.close() + return git_dir + + @pytest.fixture(scope="session") def docker(request: pytest.FixtureRequest): for cmd in [("docker", "ps"), ("docker-compose", "version")]: diff --git a/tests/test_fs.py b/tests/test_fs.py index bd509663..59d6ee5c 100644 --- a/tests/test_fs.py +++ b/tests/test_fs.py @@ -1,16 +1,34 @@ +import os + import pytest from pytest_test_utils import TmpDir from scmrepo.git import Git -def test_open(tmp_dir: TmpDir, scm: Git): +@pytest.fixture(name="make_fs") +def fixture_make_fs(scm: Git, git: Git): + def _make_fs(rev=None): + from scmrepo.fs import GitFileSystem + from scmrepo.git.objects import GitTrie + + # NOTE: not all git backends have `resolve_rev` implemented, + # so we are using whichever works. + resolved = scm.resolve_rev(rev or "HEAD") + tree = git.get_tree_obj(rev=resolved) + trie = GitTrie(tree, resolved) + return GitFileSystem(trie=trie) + + return _make_fs + + +def test_open(tmp_dir: TmpDir, scm: Git, make_fs): files = tmp_dir.gen( {"foo": "foo", "тест": "проверка", "data": {"lorem": "ipsum"}} ) scm.add_commit(files, message="add") - fs = scm.get_fs("master") + fs = make_fs() with fs.open("foo", mode="r", encoding="utf-8") as fobj: assert fobj.read() == "foo" with fs.open("тест", mode="r", encoding="utf-8") as fobj: @@ -21,13 +39,13 @@ def test_open(tmp_dir: TmpDir, scm: Git): fs.open("data") -def test_exists(tmp_dir: TmpDir, scm: Git): +def test_exists(tmp_dir: TmpDir, scm: Git, make_fs): scm.commit("init") files = tmp_dir.gen( {"foo": "foo", "тест": "проверка", "data": {"lorem": "ipsum"}} ) - fs = scm.get_fs("master") + fs = make_fs() assert fs.exists("/") assert fs.exists(".") @@ -38,7 +56,7 @@ def test_exists(tmp_dir: TmpDir, scm: Git): scm.add_commit(files, message="add") - fs = scm.get_fs("master") + fs = make_fs() assert fs.exists("/") assert fs.exists(".") assert fs.exists("foo") @@ -48,11 +66,11 @@ def test_exists(tmp_dir: TmpDir, scm: Git): assert not fs.exists("non-existing-file") -def test_isdir(tmp_dir: TmpDir, scm: Git): +def test_isdir(tmp_dir: TmpDir, scm: Git, make_fs): tmp_dir.gen({"foo": "foo", "тест": "проверка", "data": {"lorem": "ipsum"}}) scm.add_commit(["foo", "data"], message="add") - fs = scm.get_fs("master") + fs = make_fs() assert fs.isdir("/") assert fs.isdir(".") @@ -61,11 +79,11 @@ def test_isdir(tmp_dir: TmpDir, scm: Git): assert not fs.isdir("non-existing-file") -def test_isfile(tmp_dir: TmpDir, scm: Git): +def test_isfile(tmp_dir: TmpDir, scm: Git, make_fs): tmp_dir.gen({"foo": "foo", "тест": "проверка", "data": {"lorem": "ipsum"}}) scm.add_commit(["foo", "data"], message="add") - fs = scm.get_fs("master") + fs = make_fs() assert not fs.isfile("/") assert not fs.isfile(".") assert fs.isfile("foo") @@ -73,7 +91,7 @@ def test_isfile(tmp_dir: TmpDir, scm: Git): assert not fs.isfile("not-existing-file") -def test_walk(tmp_dir: TmpDir, scm: Git): +def test_walk(tmp_dir: TmpDir, scm: Git, make_fs): tmp_dir.gen( { "foo": "foo", @@ -82,7 +100,7 @@ def test_walk(tmp_dir: TmpDir, scm: Git): } ) scm.add_commit("data/subdir", message="add") - fs = scm.get_fs("master") + fs = make_fs() def convert_to_sets(walk_results): return [ @@ -113,7 +131,32 @@ def convert_to_sets(walk_results): ) -def test_ls(tmp_dir: TmpDir, scm: Git): +def test_walk_with_submodules( + scm: Git, + remote_git_dir: TmpDir, + make_fs, +): + remote_git = Git(remote_git_dir) + remote_git_dir.gen({"foo": "foo", "bar": "bar", "dir": {"data": "data"}}) + remote_git.add_commit(["foo", "bar", "dir"], message="add dir and files") + scm.gitpython.repo.create_submodule( + "submodule", "submodule", url=os.fspath(remote_git_dir) + ) + scm.commit("added submodule") + + files = [] + dirs = [] + fs = make_fs() + for _, dnames, fnames in fs.walk(""): + dirs.extend(dnames) + files.extend(fnames) + + # currently we don't walk through submodules + assert not dirs + assert set(files) == {".gitmodules", "submodule"} + + +def test_ls(tmp_dir: TmpDir, scm: Git, make_fs): files = tmp_dir.gen( { "foo": "foo", @@ -122,7 +165,7 @@ def test_ls(tmp_dir: TmpDir, scm: Git): } ) scm.add_commit(files, message="add") - fs = scm.get_fs("master") + fs = make_fs() assert fs.ls("/", detail=False) == ["/data", "/foo", "/тест"] assert fs.ls("/") == [ diff --git a/tests/test_git.py b/tests/test_git.py index d40bbfb5..453315d9 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -1,6 +1,6 @@ import os import shutil -from typing import Any, Dict, Iterator, Optional, Type +from typing import Any, Dict, Optional, Type import pytest from asyncssh import SFTPClient @@ -17,35 +17,9 @@ ) from scmrepo.git import Git -# pylint: disable=redefined-outer-name,unused-argument,protected-access - -backends = ["gitpython", "dulwich", "pygit2"] - - -@pytest.fixture(params=backends) -def git_backend(request) -> str: - marker = request.node.get_closest_marker("skip_git_backend") - to_skip = marker.args if marker else [] - - backend = request.param - if backend in to_skip: - pytest.skip() - return backend - - -@pytest.fixture -def git(tmp_dir: TmpDir, git_backend: str) -> Iterator[Git]: - git_ = Git(tmp_dir, backends=[git_backend]) - yield git_ - git_.close() - +from .conftest import backends -@pytest.fixture -def remote_git_dir(tmp_dir_factory: TempDirFactory): - git_dir = tmp_dir_factory.mktemp("git-remote") - remote_git = Git.init(git_dir) - remote_git.close() - return git_dir +# pylint: disable=redefined-outer-name,unused-argument,protected-access @pytest.fixture @@ -115,31 +89,6 @@ def test_belongs_to_scm(scm: Git, git: Git, path: str, expected: str): assert git.belongs_to_scm(path) == expected -def test_walk_with_submodules( - tmp_dir: Git, - scm: Git, - remote_git_dir: TmpDir, -): - remote_git = Git(remote_git_dir) - remote_git_dir.gen({"foo": "foo", "bar": "bar", "dir": {"data": "data"}}) - remote_git.add_commit(["foo", "bar", "dir"], message="add dir and files") - scm.gitpython.repo.create_submodule( - "submodule", "submodule", url=os.fspath(remote_git_dir) - ) - scm.commit("added submodule") - - files = [] - dirs = [] - fs = scm.get_fs("HEAD") - for _, dnames, fnames in fs.walk(""): - dirs.extend(dnames) - files.extend(fnames) - - # currently we don't walk through submodules - assert not dirs - assert set(files) == {".gitmodules", "submodule"} - - @pytest.mark.skip_git_backend("pygit2") def test_is_tracked(tmp_dir: TmpDir, scm: Git, git: Git): tmp_dir.gen(