diff --git a/dvc/repo/fetch.py b/dvc/repo/fetch.py index 913c3b9b0d..130c276440 100644 --- a/dvc/repo/fetch.py +++ b/dvc/repo/fetch.py @@ -48,7 +48,14 @@ def _collect_indexes( # noqa: PLR0913 max_size=max_size, types=types, ) - indexes[idx.data_tree.hash_info.value] = idx.data["repo"] + + def onerror(_entry, _exc): + pass + + data = idx.data["repo"] + data.onerror = onerror + + indexes[idx.data_tree.hash_info.value] = data except Exception as exc: # pylint: disable=broad-except collection_exc = exc logger.exception("failed to collect '%s'", rev or "workspace") diff --git a/pyproject.toml b/pyproject.toml index c09495e368..3327f3f893 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ dependencies = [ "configobj>=5.0.6", "distro>=1.3", "dpath<3,>=2.1.0", - "dvc-data>=2.10.0,<2.11.0", + "dvc-data>=2.11.0,<2.12.0", "dvc-http>=2.29.0", "dvc-render>=0.3.1,<1", "dvc-studio-client>=0.9.2,<1", diff --git a/tests/func/test_get.py b/tests/func/test_get.py index 1c5d0b536b..a4b29e1d45 100644 --- a/tests/func/test_get.py +++ b/tests/func/test_get.py @@ -64,6 +64,22 @@ def test_get_repo_dir(tmp_dir, erepo_dir): assert (tmp_dir / "dir_imported").read_text() == {"file": "contents"} +def test_get_repo_broken_dir(tmp_dir, erepo_dir): + import shutil + + from dvc_data.index import DataIndexDirError + + with erepo_dir.chdir(): + erepo_dir.dvc_gen({"broken": {"file": "contents"}}) + erepo_dir.dvc.cache.local.clear() + shutil.rmtree(erepo_dir / "broken") + + with pytest.raises(DataIndexDirError): + Repo.get(os.fspath(erepo_dir), "broken", "out") + + assert not (tmp_dir / "out").exists() + + @pytest.mark.parametrize( "erepo", [pytest.lazy_fixture("git_dir"), pytest.lazy_fixture("erepo_dir")] ) diff --git a/tests/func/test_import.py b/tests/func/test_import.py index 6a81dff9f5..ba311dbbcf 100644 --- a/tests/func/test_import.py +++ b/tests/func/test_import.py @@ -12,6 +12,7 @@ from dvc.stage.exceptions import StagePathNotFoundError from dvc.testing.tmp_dir import make_subrepo from dvc.utils.fs import remove +from dvc_data.index.index import DataIndexDirError def test_import(tmp_dir, scm, dvc, erepo_dir): @@ -96,6 +97,19 @@ def test_import_dir(tmp_dir, scm, dvc, erepo_dir): } +def test_import_broken_dir(tmp_dir, scm, dvc, erepo_dir): + with erepo_dir.chdir(): + erepo_dir.dvc_gen({"dir": {"foo": "foo content"}}, commit="create dir") + erepo_dir.dvc.cache.local.clear() + remove(erepo_dir / "dir") + + with pytest.raises(DataIndexDirError): + dvc.imp(os.fspath(erepo_dir), "dir", "dir_imported") + + assert not (tmp_dir / "dir_imported").exists() + assert not (tmp_dir / "dir_imported.dvc").exists() + + def test_import_file_from_dir(tmp_dir, scm, dvc, erepo_dir): with erepo_dir.chdir(): erepo_dir.dvc_gen( @@ -346,7 +360,8 @@ def test_push_wildcard_from_bare_git_repo( with dvc_repo.chdir(): dvc_repo.dvc.imp(os.fspath(tmp_dir), "dirextra") - dvc_repo.dvc.imp(os.fspath(tmp_dir), "dir123") + with pytest.raises(DataIndexDirError): + dvc_repo.dvc.imp(os.fspath(tmp_dir), "dir123") @pytest.mark.parametrize("dname", [".", "dir", "dir/subdir"]) diff --git a/tests/func/test_ls.py b/tests/func/test_ls.py index aa42f241de..c74e435842 100644 --- a/tests/func/test_ls.py +++ b/tests/func/test_ls.py @@ -583,3 +583,40 @@ def test_broken_symlink(tmp_dir, dvc): "path": "link", }, ] + + +def test_ls_broken_dir(tmp_dir, dvc): + from dvc_data.index import DataIndexDirError + + tmp_dir.dvc_gen( + { + "broken": {"baz": "baz"}, + } + ) + + shutil.rmtree(tmp_dir / "broken") + dvc.cache.local.clear() + + tmp_dir.dvc_gen( + { + "foo": "foo", + "dir": {"bar": "bar"}, + } + ) + + entries = Repo.ls(os.fspath(tmp_dir)) + assert entries == [ + {"isdir": False, "isexec": False, "isout": False, "path": ".dvcignore"}, + {"isdir": True, "isexec": False, "isout": True, "path": "broken"}, + {"isdir": False, "isexec": False, "isout": False, "path": "broken.dvc"}, + {"isdir": True, "isexec": False, "isout": True, "path": "dir"}, + {"isdir": False, "isexec": False, "isout": False, "path": "dir.dvc"}, + {"isdir": False, "isexec": False, "isout": True, "path": "foo"}, + {"isdir": False, "isexec": False, "isout": False, "path": "foo.dvc"}, + ] + + with pytest.raises(DataIndexDirError): + Repo.ls(os.fspath(tmp_dir), "broken") + + with pytest.raises(DataIndexDirError): + Repo.ls(os.fspath(tmp_dir), recursive=True)