From 4897a6a44ff0df7a1e2a7a321035ee672179b3b1 Mon Sep 17 00:00:00 2001 From: pared Date: Fri, 8 Mar 2019 11:09:25 +0100 Subject: [PATCH] add: prevent adding git files --- dvc/repo/__init__.py | 4 ++++ dvc/repo/add.py | 24 ++++++++++++++---------- dvc/scm/base.py | 3 +++ dvc/scm/git.py | 5 +++++ tests/test_add.py | 13 +++++++++++++ tests/unit/repo.py | 13 +++++++++++++ tests/unit/scm/git.py | 17 +++++++++++++++++ 7 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 tests/unit/repo.py create mode 100644 tests/unit/scm/git.py diff --git a/dvc/repo/__init__.py b/dvc/repo/__init__.py index 3831d695c..c667f9f0f 100644 --- a/dvc/repo/__init__.py +++ b/dvc/repo/__init__.py @@ -415,3 +415,7 @@ class Repo(object): raise OutputNotFoundError(path) return matched + + def is_dvc_internal(self, path): + path_parts = os.path.normpath(path).split(os.path.sep) + return self.DVC_DIR in path_parts diff --git a/dvc/repo/add.py b/dvc/repo/add.py index 27caffc27..2a7182b75 100644 --- a/dvc/repo/add.py +++ b/dvc/repo/add.py @@ -11,16 +11,7 @@ def add(repo, target, recursive=False, no_commit=False, fname=None): if recursive and fname: raise RecursiveAddingWhileUsingFilename() - targets = [target] - - if os.path.isdir(target) and recursive: - targets = [ - file - for file in walk_files(target) - if not Stage.is_stage_file(file) - if os.path.basename(file) != repo.scm.ignore_file - if not repo.scm.is_tracked(file) - ] + targets = _find_all_targets(repo, target, recursive) stages = _create_stages(repo, targets, fname, no_commit) @@ -31,6 +22,19 @@ def add(repo, target, recursive=False, no_commit=False, fname=None): return stages +def _find_all_targets(repo, target, recursive): + if os.path.isdir(target) and recursive: + return [ + file + for file in walk_files(target) + if not repo.is_dvc_internal(file) + if not Stage.is_stage_file(file) + if not repo.scm.belongs_to_scm(file) + if not repo.scm.is_tracked(file) + ] + return [target] + + def _create_stages(repo, targets, fname, no_commit): stages = [] diff --git a/dvc/scm/base.py b/dvc/scm/base.py index 07611853a..48031ec3e 100644 --- a/dvc/scm/base.py +++ b/dvc/scm/base.py @@ -162,3 +162,6 @@ class Base(object): Method to add file to mechanism that will remind user to track new files """ + + def belongs_to_scm(self, path): + """Return boolean whether file belongs to scm""" diff --git a/dvc/scm/git.py b/dvc/scm/git.py index b2bb76cca..f60c2cfb9 100644 --- a/dvc/scm/git.py +++ b/dvc/scm/git.py @@ -198,3 +198,8 @@ class Git(Base): def track_file(self, path): self.files_to_track.append(path) + + def belongs_to_scm(self, path): + basename = os.path.basename(path) + path_parts = os.path.normpath(path).split(os.path.sep) + return basename == self.ignore_file or Git.GIT_DIR in path_parts diff --git a/tests/test_add.py b/tests/test_add.py index 35ddddd07..b8e8866db 100644 --- a/tests/test_add.py +++ b/tests/test_add.py @@ -477,3 +477,16 @@ class TestShouldCleanUpAfterFailedAdd(TestDvc): gitignore_content = get_gitignore_content() self.assertFalse(any(self.BAR in line for line in gitignore_content)) + + +class TestShouldNotTrackGitInternalFiles(TestDvc): + def test(self): + stage_creator_spy = spy(dvc.repo.add._create_stages) + + with patch.object(dvc.repo.add, "_create_stages", stage_creator_spy): + ret = main(["add", "-R", self.dvc.root_dir]) + self.assertEqual(0, ret) + + created_stages_filenames = stage_creator_spy.mock.call_args[0][0] + for fname in created_stages_filenames: + self.assertNotIn(".git", fname) diff --git a/tests/unit/repo.py b/tests/unit/repo.py new file mode 100644 index 000000000..ad7426154 --- /dev/null +++ b/tests/unit/repo.py @@ -0,0 +1,13 @@ +import os + +from tests.basic_env import TestDvc + + +class TestIsDvcInternal(TestDvc): + def test_return_false_on_non_dvc_file(self): + path = os.path.join("path", "to-non-.dvc", "file") + self.assertFalse(self.dvc.is_dvc_internal(path)) + + def test_return_true_on_dvc_internal_file(self): + path = os.path.join("path", "to", ".dvc", "file") + self.assertTrue(path) diff --git a/tests/unit/scm/git.py b/tests/unit/scm/git.py new file mode 100644 index 000000000..b9ad27615 --- /dev/null +++ b/tests/unit/scm/git.py @@ -0,0 +1,17 @@ +import os + +from tests.basic_env import TestDvc + + +class TestGit(TestDvc): + def test_belongs_to_scm_true_on_gitignore(self): + path = os.path.join("path", "to", ".gitignore") + self.assertTrue(self.dvc.scm.belongs_to_scm(path)) + + def test_belongs_to_scm_true_on_git_internal(self): + path = os.path.join("path", "to", ".git", "internal", "file") + self.assertTrue(self.dvc.scm.belongs_to_scm(path)) + + def test_belongs_to_scm_false(self): + path = os.path.join("some", "non-.git", "file") + self.assertFalse(self.dvc.scm.belongs_to_scm(path))