From fef8ea4602f2112cbc3cd1a08c650cda143379e2 Mon Sep 17 00:00:00 2001 From: Ruslan Kuprieiev Date: Sun, 15 Jul 2018 18:09:36 +0300 Subject: [PATCH] dvc: add confirmation for `dvc destroy` Signed-off-by: Ruslan Kuprieiev --- dvc/cli.py | 5 +++++ dvc/command/destroy.py | 13 ++++++++++++- dvc/prompt.py | 18 ++++++++++++++++++ tests/test_destroy.py | 21 +++++++++++++++++++++ 4 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 dvc/prompt.py create mode 100644 tests/test_destroy.py diff --git a/dvc/cli.py b/dvc/cli.py index 3be482007..7836f4c84 100644 --- a/dvc/cli.py +++ b/dvc/cli.py @@ -94,6 +94,11 @@ def parse_args(argv=None): 'destroy', parents=[parent_parser], help='Destroy dvc') + destroy_parser.add_argument('-f', + '--force', + action='store_true', + default=False, + help='Force destruction') destroy_parser.set_defaults(func=CmdDestroy) diff --git a/dvc/command/destroy.py b/dvc/command/destroy.py index 8d2a719db..5308239bc 100644 --- a/dvc/command/destroy.py +++ b/dvc/command/destroy.py @@ -1,9 +1,20 @@ from dvc.command.common.base import CmdBase +from dvc.prompt import prompt class CmdDestroy(CmdBase): - def run(self): + def run_cmd(self): try: + msg = u'This will destroy all information about your pipelines as ' \ + u'well as cache in .dvc/cache.\n' \ + u'Are you sure you want to continue?' + + if not self.args.force and not prompt(msg, False): + err = u'Cannot destroy without a confirmation from the user. ' \ + u'Use \'-f\' to force.' + self.project.logger.error(err) + return 1 + self.project.destroy() except Exception as exc: self.project.logger.error('Failed to destroy DVC', exc) diff --git a/dvc/prompt.py b/dvc/prompt.py new file mode 100644 index 000000000..f8befe411 --- /dev/null +++ b/dvc/prompt.py @@ -0,0 +1,18 @@ +import sys + +try: + # NOTE: in Python3 raw_input() was renamed to input() + input = raw_input +except NameError: + pass + + +def prompt(msg, default=False): + if not sys.stdout.isatty(): + return default + + answer = input(msg + u'\n').lower() + while answer not in ['yes', 'no', 'y', 'n']: + answer = input('Enter \'yes\' or \'no\'.\n').lower() + + return answer[0] == "y" diff --git a/tests/test_destroy.py b/tests/test_destroy.py new file mode 100644 index 000000000..cd45e43f2 --- /dev/null +++ b/tests/test_destroy.py @@ -0,0 +1,21 @@ +import os + +from dvc.main import main + +from tests.test_repro import TestRepro + + +class TestDestroyNoConfirmation(TestRepro): + def test(self): + ret = main(['destroy']) + self.assertNotEqual(ret, 0) + + +class TestDestroyForce(TestRepro): + def test(self): + ret = main(['destroy', '-f']) + self.assertEqual(ret, 0) + + self.assertFalse(os.path.exists(self.dvc.dvc_dir)) + self.assertFalse(os.path.exists(self.file1_stage)) + self.assertFalse(os.path.exists(self.file1))