dvc: check if cache file inside dir was changed

Fixes #1125

Signed-off-by: Ruslan Kuprieiev <[email protected]>
This commit is contained in:
Ruslan Kuprieiev
2018-10-14 03:03:41 +03:00
parent 31fed211f6
commit 4503a7f503
2 changed files with 53 additions and 5 deletions
+26 -5
View File
@@ -81,14 +81,35 @@ class RemoteLOCAL(RemoteBase):
relpath = os.path.relpath(path, self.cache_dir)
return os.path.dirname(relpath) + os.path.basename(relpath)
def changed_cache(self, md5):
def changed_cache_file(self, md5):
cache = self.get(md5)
if self.state.changed(cache, md5=md5):
if os.path.exists(cache):
msg = 'Corrupted cache file {}'
msg = 'Corrupted cache file {}.'
Logger.warn(msg.format(os.path.relpath(cache)))
remove(cache)
return True
return False
def changed_cache(self, md5):
cache = self.get(md5)
clist = [(cache, md5)]
while True:
if len(clist) == 0:
break
cache, md5 = clist.pop()
if self.changed_cache_file(md5):
return True
if not self.is_dir_cache(cache):
continue
for entry in self.load_dir_cache(md5):
md5 = entry[self.PARAM_MD5]
cache = self.get(md5)
clist.append((cache, md5))
return False
@@ -512,7 +533,7 @@ class RemoteLOCAL(RemoteBase):
progress.update_target(title, 90, 100)
local_exists = [not self.changed_cache(md5) for md5 in md5s]
local_exists = [not self.changed_cache_file(md5) for md5 in md5s]
progress.finish_target(title)
@@ -539,7 +560,7 @@ class RemoteLOCAL(RemoteBase):
names = []
# NOTE: filter files that are not corrupted
for md5, name in grouped:
if self.changed_cache(md5):
if self.changed_cache_file(md5):
md5s.append(md5)
names.append(name)
@@ -617,7 +638,7 @@ class RemoteLOCAL(RemoteBase):
# NOTE: verifying that our cache is not corrupted
def func(info):
return not self.changed_cache(info[self.PARAM_MD5])
return not self.changed_cache_file(info[self.PARAM_MD5])
checksum_infos = list(filter(func, checksum_infos))
progress.update_target(title, 20, 100)
+27
View File
@@ -6,6 +6,7 @@ import shutil
import filecmp
from dvc.main import main
from dvc.project import Project
from tests.basic_env import TestDvc
from tests.test_repro import TestRepro
from dvc.stage import Stage
@@ -65,6 +66,32 @@ class TestCheckoutCorruptedCacheFile(TestRepro):
self.assertFalse(os.path.isfile(cache))
class TestCheckoutCorruptedCacheDir(TestDvc):
def test(self):
# NOTE: using 'copy' so that cache and link don't have same inode
ret = main(['config', 'cache.type', 'copy'])
self.assertEqual(ret, 0)
self.dvc = Project('.')
stages = self.dvc.add(self.DATA_DIR)
self.assertEqual(len(stages), 1)
self.assertEqual(len(stages[0].outs), 1)
out = stages[0].outs[0]
# NOTE: modifying cache file for one of the files inside the directory
# to check if dvc will detect that the cache is corrupted.
entry = self.dvc.cache.local.load_dir_cache(out.md5)[0]
md5 = entry[self.dvc.cache.local.PARAM_MD5]
cache = self.dvc.cache.local.get(md5)
with open(cache, 'w+') as fobj:
fobj.write('1')
self.dvc.checkout()
self.assertFalse(os.path.exists(cache))
class TestCmdCheckout(TestCheckout):
def test(self):
ret = main(['checkout'])