Repository: iterative/dvc
Issue: run: Check whether file specified by the output already exists

DVC version: `0.19.12`
Installation: `Arch Linux AUR package`

This prevents overwritting the file or causing some unexpected behaviour.

```bash
#!/bin/bash

# Clean and create a repository
rm -rf myrepo
mkdir myrepo
cd myrepo

# Init git and dvc
git init
dvc init
git add -A
git commit -m "Init"

# Creating the dependency
echo "hello" > hello.txt

dvc run \\
  --file circular-dependency.dvc \\
  --deps hello.txt \\
  --outs hello.txt \\
  'echo "overwrite" > hello.txt'
```

Changed files:
dvc/project.py, tests/test_run.py, dvc/exceptions.py

diff --git a/dvc/exceptions.py b/dvc/exceptions.py
index 2cadd52bb..6895c67c1 100644
--- a/dvc/exceptions.py
+++ b/dvc/exceptions.py
@@ -31,6 +31,13 @@ class OutputDuplicationError(DvcException):
         super(OutputDuplicationError, self).__init__(msg.format(output, s))
 
 
+class CircularDependencyError(DvcException):
+    def __init__(self, dependency):
+        assert isinstance(dependency, str)
+        msg = "File '{}' is specified as an output and as a dependency."
+        super(CircularDependencyError, self).__init__(msg.format(dependency))
+
+
 class MoveNotDataSourceError(DvcException):
     def __init__(self, path):
         msg = "Move is not permitted for stages that are not data sources. " \\
diff --git a/dvc/project.py b/dvc/project.py
index 0bb795044..bcb40e411 100644
--- a/dvc/project.py
+++ b/dvc/project.py
@@ -143,6 +143,14 @@ class Project(object):
                         stages = [o.stage.relpath, out.stage.relpath]
                         raise OutputDuplicationError(o.path, stages)
 
+    def _check_circular_dependency(self, deps, outs):
+        from dvc.exceptions import CircularDependencyError
+
+        circular_dependencies = set(deps) & set(outs)
+
+        if circular_dependencies:
+            raise CircularDependencyError(circular_dependencies.pop())
+
     def add(self, fname, recursive=False):
         fnames = []
         if recursive and os.path.isdir(fname):
@@ -258,6 +266,7 @@ class Project(object):
                             overwrite=overwrite)
 
         self._check_output_duplication(stage.outs)
+        self._check_circular_dependency(deps, outs)
 
         self._files_to_git_add = []
         with self.state:
diff --git a/tests/test_run.py b/tests/test_run.py
index 32b908ee6..4c14940fd 100644
--- a/tests/test_run.py
+++ b/tests/test_run.py
@@ -5,7 +5,7 @@ from dvc.main import main
 from dvc.utils import file_md5
 from dvc.stage import Stage, StageFileBadNameError, MissingDep
 from dvc.command.run import CmdRun
-from dvc.exceptions import OutputDuplicationError
+from dvc.exceptions import OutputDuplicationError, CircularDependencyError
 
 from tests.basic_env import TestDvc
 
@@ -93,6 +93,15 @@ class TestRunNoExec(TestDvc):
         self.assertFalse(os.path.exists('out'))
 
 
+class TestRunCircularDependency(TestDvc):
+    def test(self):
+        with self.assertRaises(CircularDependencyError):
+            self.dvc.run(cmd='',
+                         deps=[self.FOO],
+                         outs=[self.FOO],
+                         fname='circular-dependency.dvc')
+
+
 class TestCmdRun(TestDvc):
     def test_run(self):
         ret = main(['run',