diff --git a/dvc/repo/experiments/apply.py b/dvc/repo/experiments/apply.py index c0a676641..88f657f97 100644 --- a/dvc/repo/experiments/apply.py +++ b/dvc/repo/experiments/apply.py @@ -21,7 +21,8 @@ logger = logging.getLogger(__name__) @scm_context def apply(repo, rev, force=True, **kwargs): from dvc.repo.checkout import checkout as dvc_checkout - from dvc.scm.base import MergeConflictError, SCMError + from dvc.scm.base import SCMError + from dvc.scm.exceptions import MergeConflictError exps = repo.experiments diff --git a/dvc/repo/scm_context.py b/dvc/repo/scm_context.py index 5043710c0..8711c97e1 100644 --- a/dvc/repo/scm_context.py +++ b/dvc/repo/scm_context.py @@ -37,15 +37,29 @@ class SCMContext: return self.scm.add(self.files_to_track) def ignore(self, path: str) -> None: + from dvc.scm.base import SCMError + from dvc.scm.exceptions import FileNotInRepoError + logger.debug("Adding '%s' to gitignore file.", path) - gitignore_file = self.scm.ignore(path) + try: + gitignore_file = self.scm.ignore(path) + except FileNotInRepoError as exc: + raise SCMError(str(exc)) + if gitignore_file: self.track_file(gitignore_file) return self.ignored_paths.append(path) def ignore_remove(self, path: str) -> None: + from dvc.scm.base import SCMError + from dvc.scm.exceptions import FileNotInRepoError + logger.debug("Removing '%s' from gitignore file.", path) - gitignore_file = self.scm.ignore_remove(path) + try: + gitignore_file = self.scm.ignore_remove(path) + except FileNotInRepoError as exc: + raise SCMError(str(exc)) + if gitignore_file: return self.track_file(gitignore_file) diff --git a/dvc/scm/base.py b/dvc/scm/base.py index 9fda3afa9..e29a05fb0 100644 --- a/dvc/scm/base.py +++ b/dvc/scm/base.py @@ -9,12 +9,6 @@ class SCMError(DvcException): """Base class for source control management errors.""" -class FileNotInRepoError(SCMError): - """Thrown when trying to find .gitignore for a file that is not in a scm - repository. - """ - - class CloneError(SCMError): def __init__(self, url, path): super().__init__(f"Failed to clone repo '{url}' to '{path}'") @@ -34,10 +28,6 @@ class NoSCMError(SCMError): super().__init__(msg) -class MergeConflictError(SCMError): - pass - - class InvalidRemoteSCMRepo(SCMError): def __init__(self, url: str): msg = f"'{url}' is not a valid Git remote or URL" diff --git a/dvc/scm/exceptions.py b/dvc/scm/exceptions.py index 1c8202044..cca9307a0 100644 --- a/dvc/scm/exceptions.py +++ b/dvc/scm/exceptions.py @@ -6,3 +6,13 @@ class GitHookAlreadyExists(SCMError): def __init__(self, name: str) -> None: self.name = name super().__init__(f"Hook '{name}' already exists") + + +class FileNotInRepoError(SCMError): + """Thrown when trying to find .gitignore for a file that is not in a scm + repository. + """ + + +class MergeConflictError(SCMError): + pass diff --git a/dvc/scm/git/__init__.py b/dvc/scm/git/__init__.py index 74db062a9..756416529 100644 --- a/dvc/scm/git/__init__.py +++ b/dvc/scm/git/__init__.py @@ -11,7 +11,8 @@ from typing import Dict, Iterable, Optional, Tuple, Type from funcy import cached_property, first from pathspec.patterns import GitWildMatchPattern -from dvc.scm.base import Base, FileNotInRepoError, RevError +from dvc.scm.base import Base, RevError +from dvc.scm.exceptions import FileNotInRepoError from dvc.utils import relpath from dvc.utils.fs import path_isin diff --git a/dvc/scm/git/backend/gitpython.py b/dvc/scm/git/backend/gitpython.py index e9b245aea..61715a3a8 100644 --- a/dvc/scm/git/backend/gitpython.py +++ b/dvc/scm/git/backend/gitpython.py @@ -17,7 +17,8 @@ from typing import ( from funcy import ignore from dvc.progress import Tqdm -from dvc.scm.base import CloneError, MergeConflictError, RevError, SCMError +from dvc.scm.base import CloneError, RevError, SCMError +from dvc.scm.exceptions import MergeConflictError from dvc.utils import fix_env, is_binary, relpath from ..objects import GitCommit, GitObject diff --git a/dvc/scm/git/backend/pygit2.py b/dvc/scm/git/backend/pygit2.py index 891f21d32..bf0be8efd 100644 --- a/dvc/scm/git/backend/pygit2.py +++ b/dvc/scm/git/backend/pygit2.py @@ -17,7 +17,8 @@ from typing import ( from funcy import cached_property -from dvc.scm.base import MergeConflictError, RevError, SCMError +from dvc.scm.base import RevError, SCMError +from dvc.scm.exceptions import MergeConflictError from dvc.utils import relpath from ..objects import GitCommit, GitObject diff --git a/tests/unit/scm/test_git.py b/tests/unit/scm/test_git.py index e578cb283..e98c1849c 100644 --- a/tests/unit/scm/test_git.py +++ b/tests/unit/scm/test_git.py @@ -344,7 +344,7 @@ def test_commit_no_verify(tmp_dir, scm, git, hook): @pytest.mark.parametrize("squash", [True, False]) def test_merge(tmp_dir, scm, git, squash): - from dvc.scm.base import MergeConflictError + from dvc.scm.exceptions import MergeConflictError if git.test_backend == "dulwich": pytest.skip() @@ -399,7 +399,7 @@ def test_checkout_index(tmp_dir, scm, git): "strategy, expected", [("ours", "baz"), ("theirs", "bar")] ) def test_checkout_index_conflicts(tmp_dir, scm, git, strategy, expected): - from dvc.scm.base import MergeConflictError + from dvc.scm.exceptions import MergeConflictError if git.test_backend == "dulwich": pytest.skip()