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'
```

Discussion:
mroutis: > @mroutis I think it would be better to use already provided stage.deps and stage.outs, instead of converting them to abspath yourself.

Indeed, @efiop, let send another commit with that change

Patch:
diff --git a/dvc/project.py b/dvc/project.py
index 542fb32bc..739b874e6 100644
--- a/dvc/project.py
+++ b/dvc/project.py
@@ -146,7 +146,10 @@ class Project(object):
     def _check_circular_dependency(self, deps, outs):
         from dvc.exceptions import CircularDependencyError
 
-        circular_dependencies = set(deps) & set(outs)
+        circular_dependencies = (
+            set(file.path for file in deps) &
+            set(file.path for file in outs)
+        )
 
         if circular_dependencies:
             raise CircularDependencyError(circular_dependencies.pop())
@@ -298,7 +301,7 @@ class Project(object):
                             overwrite=overwrite)
 
         self._check_output_duplication(stage.outs)
-        self._check_circular_dependency(deps, outs)
+        self._check_circular_dependency(stage.deps, stage.outs)
 
         self._files_to_git_add = []
         with self.state:


Test patch:
diff --git a/tests/test_run.py b/tests/test_run.py
index b42c90605..ac1eed326 100644
--- a/tests/test_run.py
+++ b/tests/test_run.py
@@ -102,6 +102,21 @@ class TestRunCircularDependency(TestDvc):
                          outs=[self.FOO],
                          fname='circular-dependency.dvc')
 
+    def test_outs_no_cache(self):
+        with self.assertRaises(CircularDependencyError):
+            self.dvc.run(cmd='',
+                         deps=[self.FOO],
+                         outs_no_cache=[self.FOO],
+                         fname='circular-dependency.dvc')
+
+    def test_non_normalized_paths(self):
+        with self.assertRaises(CircularDependencyError):
+            self.dvc.run(cmd='',
+                         deps=['./foo'],
+                         outs=['foo'],
+                         fname='circular-dependency.dvc')
+
+
 class TestRunBadCwd(TestDvc):
     def test(self):
         with self.assertRaises(StageBadCwdError):