From 289797e7eb4cc648ed4eaa9aa15f0c8c524d914c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Santos?= Date: Wed, 15 Jan 2020 11:33:26 +0000 Subject: [PATCH] can now get whether an item changed, but not when an item changes from non-DVC to DVC --- dvc/dependency/repo.py | 44 ++++++++++++++++++++++++++++++++++++--- tests/func/test_status.py | 35 +++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/dvc/dependency/repo.py b/dvc/dependency/repo.py index 875544a00..b273e34e3 100644 --- a/dvc/dependency/repo.py +++ b/dvc/dependency/repo.py @@ -1,6 +1,7 @@ import copy import os from contextlib import contextmanager +import filecmp from funcy import merge @@ -52,7 +53,7 @@ class DependencyREPO(DependencyLOCAL): PathInfo(os.path.join(repo.root_dir, self.def_path)) ) - def status(self): + def _has_changed(self): with self._make_repo() as repo, self._make_repo( rev_lock=None ) as updated_repo: @@ -60,16 +61,53 @@ class DependencyREPO(DependencyLOCAL): current = repo.find_out_by_relpath(self.def_path).info updated = updated_repo.find_out_by_relpath(self.def_path).info - has_changed = current != updated + return current != updated except OutputNotFoundError: # Need to load the state before calculating checksums repo.state.load() updated_repo.state.load() - has_changed = self._get_checksum_in_repo( + return self._get_checksum_in_repo( repo ) != self._get_checksum_in_repo(updated_repo) + def _has_changed_non_dvc(self): + url = self.def_repo[self.PARAM_URL] + rev = self.def_repo.get(self.PARAM_REV) + rev_lock = self.def_repo.get(self.PARAM_REV_LOCK, rev) + + current_repo = cached_clone(url, rev=rev_lock or rev) + updated_repo = cached_clone(url, rev=rev) + + current_path = os.path.join(current_repo, self.def_path) + updated_path = os.path.join(updated_repo, self.def_path) + + if not os.path.exists(current_path): + raise FileNotFoundError(current_path) + + if not os.path.exists(updated_path): + raise FileNotFoundError(updated_path) + + is_dir = os.path.isdir(current_path) + + assert is_dir == os.path.isdir(updated_path) + + if is_dir: + comparison = filecmp.dircmp(current_path, updated_path) + return not ( + comparison.left_only + or comparison.right_only + or comparison.diff_files + ) + + return not filecmp.cmp(current_path, updated_path, shallow=False) + + def status(self): + try: + has_changed = self._has_changed() + except NotDvcRepoError: + has_changed = self._has_changed_non_dvc() + if has_changed: return {str(self): "update available"} diff --git a/tests/func/test_status.py b/tests/func/test_status.py index e4de03852..b122a9e7a 100644 --- a/tests/func/test_status.py +++ b/tests/func/test_status.py @@ -1,9 +1,12 @@ import os +import shutil from mock import patch from dvc.main import main +from dvc.compat import fspath from tests.basic_env import TestDvc +from dvc.external_repo import clean_repos class TestStatus(TestDvc): @@ -23,3 +26,35 @@ class TestStatus(TestDvc): def test_implied_cloud(self, mock_status): main(["status", "--remote", "something"]) mock_status.assert_called() + + +def test_status_non_dvc_repo_import(tmp_dir, dvc, erepo_dir): + with erepo_dir.branch("branch", new=True), erepo_dir.chdir(): + erepo_dir.scm.repo.index.remove([".dvc"], r=True) + shutil.rmtree(".dvc") + erepo_dir.scm_gen("file", "first version") + erepo_dir.scm.add(["file"]) + erepo_dir.scm.commit("first version") + + dvc.imp(fspath(erepo_dir), "file", "file", rev="branch") + + status = dvc.status(["file.dvc"]) + + assert status == {} + + # Caching in external repos doesn't see upstream updates within single + # cli call, so we need to clean the caches to see the changes. + clean_repos() + + with erepo_dir.branch("branch", new=False), erepo_dir.chdir(): + erepo_dir.scm_gen("file", "second_version", commit="update file") + erepo_dir.scm.add(["file"]) + erepo_dir.scm.commit("first version") + + status, = dvc.status(["file.dvc"])["file.dvc"] + + assert status == { + "changed deps": { + "file ({})".format(fspath(erepo_dir)): "update available" + } + }