run: preserve order when -f/--force overwrite stage (#4035)

This commit preserves comments, meta and order inside a dvc.yaml
when `-f/--force` is used. But, it does not maintain comments/meta
for .dvc files.

Related: #4014
This commit is contained in:
Saugat Pachhai
2020-06-13 00:55:15 +03:00
committed by GitHub
parent a1d3440f85
commit 24a14563cc
3 changed files with 82 additions and 5 deletions
+6 -5
View File
@@ -1,4 +1,5 @@
import os
from contextlib import suppress
from funcy import concat, first, lfilter
@@ -109,12 +110,12 @@ def run(self, fname=None, no_exec=False, single_stage=False, **kwargs):
return None
dvcfile = Dvcfile(self, stage.path)
if kwargs.get("force", True):
dvcfile.remove_stage(stage)
else:
_check_stage_exists(dvcfile, stage)
try:
if kwargs.get("force", True):
with suppress(ValueError):
self.stages.remove(stage)
else:
_check_stage_exists(dvcfile, stage)
self.check_modified_graph([stage])
except OutputDuplicationError as exc:
raise OutputDuplicationError(exc.output, set(exc.stages) - {stage})
+46
View File
@@ -1,4 +1,5 @@
import os
import textwrap
import pytest
import yaml
@@ -6,6 +7,7 @@ import yaml
from dvc.exceptions import InvalidArgumentError
from dvc.repo import Repo
from dvc.stage.exceptions import DuplicateStageName, InvalidStageName
from dvc.utils.yaml import parse_yaml_for_update
def test_run_with_name(tmp_dir, dvc, run_copy):
@@ -315,3 +317,47 @@ def test_run_without_cmd(kwargs):
with pytest.raises(InvalidArgumentError) as exc:
Repo().run(**kwargs)
assert "command is not specified" == str(exc.value)
def test_run_overwrite_order(tmp_dir, dvc, run_copy):
from dvc.dvcfile import PIPELINE_FILE
tmp_dir.gen({"foo": "foo", "foo1": "foo1"})
run_copy("foo", "bar", name="copy-foo-bar")
run_copy("bar", "foobar", name="copy-bar-foobar")
run_copy("foo1", "bar1", name="copy-foo-bar", force=True)
data = parse_yaml_for_update(
(tmp_dir / PIPELINE_FILE).read_text(), PIPELINE_FILE
)
assert list(data["stages"].keys()) == ["copy-foo-bar", "copy-bar-foobar"]
def test_run_overwrite_preserves_meta_and_comment(tmp_dir, dvc, run_copy):
from dvc.dvcfile import PIPELINE_FILE
tmp_dir.gen({"foo": "foo", "foo1": "foo1"})
text = textwrap.dedent(
"""\
stages:
copy-foo-bar:
cmd: python copy.py {src} {dest}
deps:
- copy.py
- {src}
outs:
# comments are preserved
- {dest}
meta:
name: meta is preserved too
"""
)
(tmp_dir / PIPELINE_FILE).write_text(text.format(src="foo", dest="bar"))
assert dvc.reproduce(PIPELINE_FILE)
assert run_copy("foo1", "bar1", name="copy-foo-bar", force=True)
assert (tmp_dir / PIPELINE_FILE).read_text() == text.format(
src="foo1", dest="bar1"
)
+30
View File
@@ -1,6 +1,7 @@
import filecmp
import logging
import os
import textwrap
import uuid
from pathlib import Path
@@ -1017,3 +1018,32 @@ class TestRunDirMetrics:
metrics_no_cache=["dir"],
single_stage=True,
)
def test_run_force_doesnot_preserve_comments_and_meta(tmp_dir, dvc, run_copy):
"""Depends on loading of stage on `run` where we don't check the file
for stage already exists, so we don't copy `stage_text` over due to which
`meta` and `comments` don't get preserved."""
tmp_dir.gen({"foo": "foo", "foo1": "foo1"})
text = textwrap.dedent(
"""\
cmd: python copy.py foo bar
deps:
- path: copy.py
- path: foo
outs:
# comment not preserved
- path: bar
meta:
name: copy-foo-bar
"""
)
(tmp_dir / "bar.dvc").write_text(text)
dvc.reproduce("bar.dvc")
assert "comment" in (tmp_dir / "bar.dvc").read_text()
assert "meta" in (tmp_dir / "bar.dvc").read_text()
run_copy("foo1", "bar1", single_stage=True, force=True, fname="bar.dvc")
assert "comment" not in (tmp_dir / "bar.dvc").read_text()
assert "meta" not in (tmp_dir / "bar.dvc").read_text()