Skip to content

Commit

Permalink
add: meaningful message upon adding overlapping paths (#3296)
Browse files Browse the repository at this point in the history
  • Loading branch information
pared committed Feb 13, 2020
1 parent 7e6e8ee commit ccca126
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 15 deletions.
15 changes: 4 additions & 11 deletions dvc/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,17 +188,10 @@ def __init__(self):


class OverlappingOutputPathsError(DvcException):
def __init__(self, out_1, out_2):
super().__init__(
"Paths for outs:\n'{}'('{}')\n'{}'('{}')\noverlap. To avoid "
"unpredictable behaviour, rerun command with non overlapping outs "
"paths.".format(
str(out_1),
out_1.stage.relpath,
str(out_2),
out_2.stage.relpath,
)
)
def __init__(self, parent, overlapping_out, message):
self.parent = parent
self.overlapping_out = overlapping_out
super().__init__(message)


class CheckoutErrorSuggestGit(DvcException):
Expand Down
12 changes: 11 additions & 1 deletion dvc/repo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,17 @@ def _collect_graph(self, stages=None):
for out in stage.outs:
for p in out.path_info.parents:
if p in outs:
raise OverlappingOutputPathsError(outs[p], out)
msg = (
"Paths for outs:\n'{}'('{}')\n'{}'('{}')\n"
"overlap. To avoid unpredictable behaviour, "
"rerun command with non overlapping outs paths."
).format(
str(outs[p]),
outs[p].stage.relpath,
str(out),
out.stage.relpath,
)
raise OverlappingOutputPathsError(outs[p], out, msg)

for stage in stages:
stage_path_info = PathInfo(stage.path)
Expand Down
22 changes: 20 additions & 2 deletions dvc/repo/add.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
import colorama

from . import locked
from ..exceptions import RecursiveAddingWhileUsingFilename
from ..exceptions import (
RecursiveAddingWhileUsingFilename,
OverlappingOutputPathsError,
)
from ..output.base import OutputDoesNotExistError
from ..progress import Tqdm
from ..repo.scm_context import scm_context
Expand Down Expand Up @@ -49,7 +52,22 @@ def add(repo, targets, recursive=False, no_commit=False, fname=None):

stages = _create_stages(repo, sub_targets, fname, pbar=pbar)

repo.check_modified_graph(stages)
try:
repo.check_modified_graph(stages)
except OverlappingOutputPathsError as exc:
msg = (
"Cannot add '{out}', because it is overlapping with other "
"DVC tracked output: '{parent}'.\n"
"To include '{out}' in '{parent}', run "
"'dvc commit {parent_stage}'"
).format(
out=exc.overlapping_out.path_info,
parent=exc.parent.path_info,
parent_stage=exc.parent.stage.relpath,
)
raise OverlappingOutputPathsError(
exc.parent, exc.overlapping_out, msg
)

with Tqdm(
total=len(stages),
Expand Down
16 changes: 15 additions & 1 deletion tests/func/test_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import dvc as dvc_module
from dvc.cache import Cache
from dvc.exceptions import DvcException
from dvc.exceptions import DvcException, OverlappingOutputPathsError
from dvc.exceptions import RecursiveAddingWhileUsingFilename
from dvc.exceptions import StageFileCorruptedError
from dvc.main import main
Expand Down Expand Up @@ -641,3 +641,17 @@ def test_escape_gitignore_entries(tmp_dir, scm, dvc):

tmp_dir.dvc_gen(fname, "...")
assert ignored_fname in get_gitignore_content()


def test_add_from_data_dir(tmp_dir, scm, dvc):
tmp_dir.dvc_gen({"dir": {"file1": "file1 content"}})

tmp_dir.gen({"dir": {"file2": "file2 content"}})

with pytest.raises(OverlappingOutputPathsError) as e:
dvc.add(os.path.join("dir", "file2"))
assert str(e.value) == (
"Cannot add '{out}', because it is overlapping with other DVC "
"tracked output: 'dir'.\n"
"To include '{out}' in 'dir', run 'dvc commit dir.dvc'"
).format(out=os.path.join("dir", "file2"))

0 comments on commit ccca126

Please sign in to comment.