mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-02 07:18:25 +01:00
checkout: friendlier UI when tryint to remove uncached files
Related #9618
This commit is contained in:
+41
-5
@@ -1,12 +1,21 @@
|
||||
import logging
|
||||
import os
|
||||
from typing import Dict, List
|
||||
from typing import TYPE_CHECKING, Dict, List
|
||||
|
||||
from dvc.exceptions import CheckoutError, CheckoutErrorSuggestGit, NoOutputOrStageError
|
||||
from dvc.exceptions import (
|
||||
CheckoutError,
|
||||
CheckoutErrorSuggestGit,
|
||||
DvcException,
|
||||
NoOutputOrStageError,
|
||||
)
|
||||
from dvc.utils import relpath
|
||||
|
||||
from . import locked
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from dvc_data.index import BaseDataIndex, DataIndexEntry
|
||||
from dvc_objects.fs.base import FileSystem
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -59,6 +68,33 @@ def _build_out_changes(index, changes):
|
||||
return out_changes
|
||||
|
||||
|
||||
def _check_can_delete(
|
||||
entries: List["DataIndexEntry"],
|
||||
index: "BaseDataIndex",
|
||||
path: str,
|
||||
fs: "FileSystem",
|
||||
):
|
||||
entry_paths = []
|
||||
for entry in entries:
|
||||
try:
|
||||
cache_fs, cache_path = index.storage_map.get_cache(entry)
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
if cache_fs.exists(cache_path):
|
||||
continue
|
||||
|
||||
entry_paths.append(fs.path.join(path, *entry.key))
|
||||
|
||||
if not entry_paths:
|
||||
return
|
||||
|
||||
raise DvcException(
|
||||
"Can't remove the following unsaved files without confirmation. "
|
||||
"Use `--force` to force.\n" + "\n".join(entry_paths)
|
||||
)
|
||||
|
||||
|
||||
@locked
|
||||
def checkout( # noqa: C901
|
||||
self,
|
||||
@@ -70,7 +106,6 @@ def checkout( # noqa: C901
|
||||
allow_missing=False,
|
||||
**kwargs,
|
||||
):
|
||||
from dvc import prompt
|
||||
from dvc.fs.callbacks import Callback
|
||||
from dvc.repo.index import build_data_index
|
||||
from dvc.stage.exceptions import StageFileBadNameError, StageFileDoesNotExistError
|
||||
@@ -123,6 +158,9 @@ def checkout( # noqa: C901
|
||||
) as cb:
|
||||
diff = compare(old, new, relink=relink, delete=True, callback=cb)
|
||||
|
||||
if not force:
|
||||
_check_can_delete(diff.files_delete, new, self.root_dir, self.fs)
|
||||
|
||||
failed = []
|
||||
|
||||
def checkout_onerror(src_path, dest_path, _exc):
|
||||
@@ -140,9 +178,7 @@ def checkout( # noqa: C901
|
||||
self.root_dir,
|
||||
self.fs,
|
||||
callback=cb,
|
||||
prompt=prompt.confirm,
|
||||
update_meta=False,
|
||||
force=force,
|
||||
onerror=checkout_onerror,
|
||||
state=self.state,
|
||||
**kwargs,
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ dependencies = [
|
||||
"configobj>=5.0.6",
|
||||
"distro>=1.3",
|
||||
"dpath<3,>=2.1.0",
|
||||
"dvc-data>=2.1.1,<2.2.0",
|
||||
"dvc-data>=2.2.0,<2.3.0",
|
||||
"dvc-http>=2.29.0",
|
||||
"dvc-render>=0.3.1,<1",
|
||||
"dvc-studio-client>=0.9.2,<1",
|
||||
|
||||
@@ -84,23 +84,19 @@ def test_remove_files_when_checkout(tmp_dir, dvc, scm):
|
||||
|
||||
class TestCheckoutCleanWorkingDir:
|
||||
def test(self, mocker, tmp_dir, dvc):
|
||||
mock_prompt = mocker.patch("dvc.prompt.confirm", return_value=True)
|
||||
(stage,) = tmp_dir.dvc_gen("data", {"foo": "foo"})
|
||||
|
||||
# change working directory
|
||||
(tmp_dir / "data").gen("not_cached.txt", "not_cached")
|
||||
assert main(["checkout", stage.relpath]) == 0
|
||||
mock_prompt.assert_called()
|
||||
assert main(["checkout", stage.relpath, "--force"]) == 0
|
||||
assert not (tmp_dir / "data" / "not_cached.txt").exists()
|
||||
|
||||
def test_force(self, mocker, tmp_dir, dvc):
|
||||
mock_prompt = mocker.patch("dvc.prompt.confirm", return_value=False)
|
||||
(stage,) = tmp_dir.dvc_gen("data", {"foo": "foo"})
|
||||
|
||||
# change working directory
|
||||
(tmp_dir / "data").gen("not_cached.txt", "not_cached")
|
||||
assert main(["checkout", stage.relpath]) != 0
|
||||
mock_prompt.assert_called()
|
||||
assert (tmp_dir / "data" / "not_cached.txt").exists()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user