diff --git a/.gitignore b/.gitignore index 3f25a701e..92077daad 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ innosetup/config.ini .coverage dvc/version.py + +*.swp diff --git a/dvc/cli.py b/dvc/cli.py index 075aff008..2ba52bb3f 100644 --- a/dvc/cli.py +++ b/dvc/cli.py @@ -215,6 +215,10 @@ def parse_args(argv=None): action='store_true', default=False, help='Reproduce only single data item without recursive dependencies check.') + repro_parser.add_argument('-c', + '--cwd', + default=os.path.curdir, + help='Directory to reproduce from.') repro_parser.set_defaults(func=CmdRepro) # Remove diff --git a/dvc/command/repro.py b/dvc/command/repro.py index 4125ddb33..681df032e 100644 --- a/dvc/command/repro.py +++ b/dvc/command/repro.py @@ -8,6 +8,11 @@ from dvc.stage import Stage class CmdRepro(CmdBase): def run(self): recursive = not self.args.single_item + saved_dir = os.path.realpath(os.curdir) + if self.args.cwd: + os.chdir(self.args.cwd) + + ret = 0 for target in self.args.targets: try: self.project.reproduce(target, @@ -16,7 +21,8 @@ class CmdRepro(CmdBase): except ReproductionError as ex: msg = 'Failed to reproduce \'{}\''.format(target) self.project.logger.error(msg, ex) - return 1 + ret = 1 + break except StageNotFoundError as ex: if os.path.exists(target): msg = '\'{}\' is not a dvc file.'.format(target) @@ -26,9 +32,13 @@ class CmdRepro(CmdBase): else: msg = '\'{}\' does not exist.'.format(target) self.project.logger.error(msg) - return 1 + ret = 1 + break except Exception as ex: msg = 'Failed to reproduce \'{}\' - unexpected error'.format(target) self.project.logger.error(msg, ex) - return 1 - return 0 + ret = 1 + break + + os.chdir(saved_dir) + return ret diff --git a/tests/test_repro.py b/tests/test_repro.py index 119b58e9a..9ee5d052e 100644 --- a/tests/test_repro.py +++ b/tests/test_repro.py @@ -186,6 +186,37 @@ class TestCmdRepro(TestRepro): self.assertNotEqual(ret, 0) +class TestCmdReproChdir(TestDvc): + def test(self): + dname = 'dir' + os.mkdir(dname) + foo = os.path.join(dname, self.FOO) + bar = os.path.join(dname, self.BAR) + code = os.path.join(dname, self.CODE) + shutil.copyfile(self.FOO, foo) + shutil.copyfile(self.CODE, code) + + ret = main(['run', + '-f', 'Dvcfile', + '-c', dname, + '-d', self.FOO, + '-o', self.BAR, + 'python {} {} {}'.format(self.CODE, self.FOO, self.BAR)]) + self.assertEqual(ret, 0) + self.assertTrue(os.path.isfile(foo)) + self.assertTrue(os.path.isfile(bar)) + self.assertTrue(filecmp.cmp(foo, bar)) + + os.unlink(bar) + + ret = main(['repro', + '-c', dname]) + self.assertEqual(ret, 0) + self.assertTrue(os.path.isfile(foo)) + self.assertTrue(os.path.isfile(bar)) + self.assertTrue(filecmp.cmp(foo, bar)) + + class TestReproExternalBase(TestDvc): def should_test(self): return False