diff --git a/dvc/dependency/base.py b/dvc/dependency/base.py index ba993b21d..9290389d1 100644 --- a/dvc/dependency/base.py +++ b/dvc/dependency/base.py @@ -39,6 +39,10 @@ class DependencyBase(object): def supported(cls, url): return cls.match(url) != None + @property + def sep(self): + return '/' + def changed(self): raise NotImplementedError diff --git a/dvc/dependency/local.py b/dvc/dependency/local.py index 081ae81e6..7336f9298 100644 --- a/dvc/dependency/local.py +++ b/dvc/dependency/local.py @@ -39,6 +39,10 @@ class DependencyLOCAL(DependencyBase): self.path_info = {'scheme': 'local', 'path': self.path} + @property + def sep(self): + return os.sep + @property def rel_path(self): return os.path.relpath(self.path) diff --git a/dvc/project.py b/dvc/project.py index 1cea1725b..98c17d286 100644 --- a/dvc/project.py +++ b/dvc/project.py @@ -399,22 +399,20 @@ class Project(object): def graph(self): G = nx.DiGraph() stages = self.stages() - - outs_map = {} - for stage in stages: - for o in stage.outs: - outs_map[o.path] = stage + outs = self.outs() for stage in stages: node = os.path.relpath(stage.path, self.root_dir) G.add_node(node, stage=stage) for dep in stage.deps: - dep_stage = outs_map.get(dep.path, None) - if not dep_stage: - continue - dep_node = os.path.relpath(dep_stage.path, self.root_dir) - G.add_node(dep_node, stage=dep_stage) - G.add_edge(node, dep_node) + for out in outs: + if out.path != dep.path and not dep.path.startswith(out.path + out.sep): + continue + + dep_stage = out.stage + dep_node = os.path.relpath(dep_stage.path, self.root_dir) + G.add_node(dep_node, stage=dep_stage) + G.add_edge(node, dep_node) return G diff --git a/tests/test_repro.py b/tests/test_repro.py index 64129fe22..7bc5b4b14 100644 --- a/tests/test_repro.py +++ b/tests/test_repro.py @@ -36,6 +36,27 @@ class TestRepro(TestDvc): cmd='python {} {} {}'.format(self.CODE, self.FOO, self.file1)) +class TestReproDepUnderDir(TestDvc): + def test(self): + self.dir_stage = self.dvc.add(self.DATA_DIR) + + self.file1 = 'file1' + self.file1_stage = self.file1 + '.dvc' + self.dvc.run(fname=self.file1_stage, + outs=[self.file1], + deps=[self.DATA, self.CODE], + cmd='python {} {} {}'.format(self.CODE, self.DATA, self.file1)) + + self.assertTrue(filecmp.cmp(self.file1, self.DATA)) + + os.unlink(self.DATA) + shutil.copyfile(self.FOO, self.DATA) + + stages = self.dvc.reproduce(self.file1_stage) + self.assertEqual(len(stages), 2) + self.assertTrue(filecmp.cmp(self.file1, self.FOO)) + + class TestReproNoDeps(TestRepro): def test(self): out = 'out'