From d2790f930611e5a9da7ff795287ab4ab1b5df1c1 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 6 Jan 2018 04:15:23 -0800 Subject: [PATCH 01/11] Refactoring: move find_cache() to Cache class --- dvc/cache.py | 11 +++++++++++ dvc/command/checkout.py | 15 ++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dvc/cache.py b/dvc/cache.py index dbb8417e9..2a5cdea12 100644 --- a/dvc/cache.py +++ b/dvc/cache.py @@ -1,5 +1,7 @@ import os +from dvc.system import System + class Cache(object): CACHE_DIR = 'cache' @@ -23,3 +25,12 @@ class Cache(object): def get(self, md5): return os.path.join(self.cache_dir, md5) + + def find_cache(self, files): + file_set = set(files) + cached = {} + for cache_file in self.all(): + cached_files = list(filter(lambda f: System.samefile(cache_file, f, True), file_set)) + cached.update(dict((f, os.path.basename(cache_file)) for f in cached_files)) + file_set = file_set - set(cached_files) + return cached diff --git a/dvc/command/checkout.py b/dvc/command/checkout.py index c6e5877fc..c8c171d38 100644 --- a/dvc/command/checkout.py +++ b/dvc/command/checkout.py @@ -2,7 +2,6 @@ import os from dvc.command.common.base import CmdBase from dvc.logger import Logger -from dvc.system import System class CmdCheckout(CmdBase): @@ -12,9 +11,9 @@ class CmdCheckout(CmdBase): return 0 def remove_untracked_hardlinks(self): - untracked_cache_files = self.untracked_hardlinks_files() + untracked = self.project.scm.untracked_files() - for file in untracked_cache_files: + for file in self.project.cache.find_cache(untracked).keys(): Logger.info(u'Remove \'{}\''.format(file)) os.remove(file) @@ -23,13 +22,3 @@ class CmdCheckout(CmdBase): Logger.info(u'Remove empty directory \'{}\''.format(dir)) os.removedirs(dir) pass - - def untracked_hardlinks_files(self): - untracked_files = set(self.project.scm.untracked_files()) - cached_files = [] - for cache_file in self.project.cache.all(): - hardlinks = list(filter(lambda f: System.samefile(cache_file, f), untracked_files)) - cached_files.extend(hardlinks) - untracked_files = untracked_files - set(hardlinks) - - return cached_files From c79a7cd2df198f9c7fcdf301dd9c826cc84fed5f Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 6 Jan 2018 04:16:22 -0800 Subject: [PATCH 02/11] Convert mtime to int --- dvc/state.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dvc/state.py b/dvc/state.py index ddd579e92..4be003877 100644 --- a/dvc/state.py +++ b/dvc/state.py @@ -54,6 +54,7 @@ class State(object): return State(root_dir, dvc_dir) def update(self, path, md5, mtime): + mtime = int(mtime) existing = self.get(path) if not existing: return self.add(path, md5, mtime) @@ -64,6 +65,7 @@ class State(object): return state def add(self, path, md5, mtime): + mtime = int(mtime) entry = StateEntry(self.root_dir, path, md5, mtime) self._db.insert(entry.dumpd()) return entry From ab3abbe87a785983da2fbb840076a0c68b28cbe5 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 6 Jan 2018 04:17:55 -0800 Subject: [PATCH 03/11] New command: dvc fsck. Close #381. --- dvc/cli.py | 23 ++++++++++++++++ dvc/command/fsck.py | 67 +++++++++++++++++++++++++++++++++++++++++++++ dvc/project.py | 7 +++++ dvc/stage.py | 26 ++++++++++++++++-- dvc/system.py | 6 +++- 5 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 dvc/command/fsck.py diff --git a/dvc/cli.py b/dvc/cli.py index f277e7df0..a64b8fd53 100644 --- a/dvc/cli.py +++ b/dvc/cli.py @@ -6,6 +6,7 @@ import argparse from multiprocessing import cpu_count from dvc.command.find import CmdFind +from dvc.command.fsck import CmdFsck from dvc.command.init import CmdInit from dvc.command.remove import CmdRemove from dvc.command.run import CmdRun @@ -414,6 +415,28 @@ def parse_args(argv=None): default=False, help='Show metrics value.') + fsck_parser = subparsers.add_parser( + 'fsck', + parents=[parent_parser], + help='Data file consistency check') + fsck_parser.add_argument( + 'targets', + nargs='*', + help='Data files to check') + fsck_parser.add_argument( + '-a', + '--all', + action='store_true', + default=False, + help='Check all data files') + fsck_parser.add_argument( + '-p', + '--physical', + action='store_true', + default=False, + help='Compute actual md5') + fsck_parser.set_defaults(func=CmdFsck) + if isinstance(argv, str): argv = argv.split() diff --git a/dvc/command/fsck.py b/dvc/command/fsck.py new file mode 100644 index 000000000..ec4d98af9 --- /dev/null +++ b/dvc/command/fsck.py @@ -0,0 +1,67 @@ +import os + +from dvc.command.common.base import CmdBase +from dvc.data_cloud import file_md5 + + +class CmdFsck(CmdBase): + def run(self): + if not self.args.targets and not self.args.all: + self.project.logger.error(u'Data files are not specified') + return 1 + + directions = self.project.all_directions() + files_and_stages = self.directions_by_datafile(directions) + + if self.args.all: + dvc_files = files_and_stages.keys() + else: + dvc_files = [os.path.relpath(os.path.abspath(f), self.project.root_dir) + for f in self.args.targets] + + caches = self.project.cache.find_cache(dvc_files) + + self.print_fsck(caches, dvc_files, files_and_stages) + return 0 + + def print_fsck(self, caches, dvc_files, files_and_stages): + for file in dvc_files: + print('File {}:'.format(file)) + + full_path = os.path.join(self.project.root_dir, file) + if self.args.physical: + md5 = file_md5(full_path)[0] + print(u' Actual checksum: {}'.format(md5)) + else: + md5 = None + + hardlink_md5 = caches.get(file) + hardlink_msg = hardlink_md5 if caches else 'Error - cache file not found!' + hardlink_error = '!!!' if hardlink_md5 and md5 and md5 <> hardlink_md5 else '' + print(u' Hardlink to cache file: {} {}'.format(hardlink_msg, hardlink_error)) + + state = self.project.state.get(file) + local_state_error = '!!!' if state.md5 and hardlink_md5 and state.md5 <> hardlink_md5 else '' + print(u' Local state checksum: {} {}'.format(state.md5 if state else '', local_state_error)) + print(u' Local state mtime: {}'.format(state.mtime if state else '')) + mtime = int(os.path.getmtime(full_path)) if os.path.exists(full_path) else 'None' + print(u' Actual mtime: {}'.format(mtime)) + + for stage, dep in files_and_stages.get(file, []): + stage_error = '!!!' if dep.md5 and hardlink_md5 and dep.md5 <> hardlink_md5 else '' + print(u' Stage file: {}'.format(stage.dvc_path)) + print(u' Type: {}'.format(dep.direction)) + print(u' Checksum: {} {}'.format(dep.md5, stage_error)) + print(u' Use cache: {}'.format(str(dep.use_cache).lower())) + pass + + @staticmethod + def directions_by_datafile(directions): + result = {} + + for stage, dep in directions: + if dep.dvc_path not in result: + result[dep.dvc_path] = [] + result[dep.dvc_path].append((stage, dep)) + + return result diff --git a/dvc/project.py b/dvc/project.py index 62f620f25..a5c8274c3 100644 --- a/dvc/project.py +++ b/dvc/project.py @@ -232,6 +232,13 @@ class Project(object): return G + def all_directions(self): + result = [] + for stage in self.stages(): + for dep in stage.deps + stage.outs: + result.append((stage, dep)) + return result + def stages(self): stages = [] for root, dirs, files in os.walk(self.root_dir): diff --git a/dvc/stage.py b/dvc/stage.py index e0fdfa883..ed9ae6508 100644 --- a/dvc/stage.py +++ b/dvc/stage.py @@ -38,7 +38,12 @@ class OutputAlreadyTrackedError(OutputError): super(OutputAlreadyTrackedError, self).__init__(path, 'already tracked by scm(e.g. git)') -class Output(object): +class Direction(object): + DIRECTION_TYPE_OUT = 'Output' + DIRECTION_TYPE_DEP = 'Dependency' + + +class Output(Direction): PARAM_PATH = 'path' PARAM_MD5 = 'md5' PARAM_CACHE = 'cache' @@ -52,8 +57,16 @@ class Output(object): self.md5 = md5 self.use_cache = use_cache + self.direction = self.DIRECTION_TYPE_OUT + + @property + def dvc_path(self): + return os.path.relpath(self.path, self.project.root_dir) def _changed_md5(self): + if not os.path.exists(self.path): + return True + state = self.project.state.get(self.path) if state and state.mtime == self.mtime(): md5 = state.md5 @@ -179,7 +192,9 @@ class Output(object): class Dependency(Output): - pass + def __init__(self, project, path, md5=None, use_cache=False): + super(Dependency, self).__init__(project, path, md5, use_cache) + self.direction = self.DIRECTION_TYPE_DEP class Stage(object): @@ -200,6 +215,10 @@ class Stage(object): self.deps = deps self.locked = locked + @property + def dvc_path(self): + return os.path.relpath(self.path, self.project.root_dir) + @staticmethod def is_stage_file(path): if not os.path.isfile(path): @@ -223,7 +242,8 @@ class Stage(object): self.project.logger.debug("Removing '{}'".format(out.path)) os.chmod(out.path, stat.S_IWUSR) os.unlink(out.path) - os.chmod(out.cache, stat.S_IREAD) + if os.path.exists(out.cache): + os.chmod(out.cache, stat.S_IREAD) def remove(self): self.remove_outs() diff --git a/dvc/system.py b/dvc/system.py index 99c662e9a..b8b0c8098 100644 --- a/dvc/system.py +++ b/dvc/system.py @@ -26,7 +26,11 @@ class System(object): return winlink.create(source, link_name) @staticmethod - def samefile(path1, path2): + def samefile(path1, path2, check_exist=False): + if check_exist: + if not os.path.exists(path1) or not os.path.exists(path2): + return False + if System.is_unix(): return os.path.samefile(path1, path2) From d232a15e8ef467eaa6baf5cb4cb37d20297859d8 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 6 Jan 2018 04:15:23 -0800 Subject: [PATCH 04/11] Refactoring: move find_cache() to Cache class --- dvc/cache.py | 11 +++++++++++ dvc/command/checkout.py | 15 ++------------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/dvc/cache.py b/dvc/cache.py index dbb8417e9..2a5cdea12 100644 --- a/dvc/cache.py +++ b/dvc/cache.py @@ -1,5 +1,7 @@ import os +from dvc.system import System + class Cache(object): CACHE_DIR = 'cache' @@ -23,3 +25,12 @@ class Cache(object): def get(self, md5): return os.path.join(self.cache_dir, md5) + + def find_cache(self, files): + file_set = set(files) + cached = {} + for cache_file in self.all(): + cached_files = list(filter(lambda f: System.samefile(cache_file, f, True), file_set)) + cached.update(dict((f, os.path.basename(cache_file)) for f in cached_files)) + file_set = file_set - set(cached_files) + return cached diff --git a/dvc/command/checkout.py b/dvc/command/checkout.py index c6e5877fc..c8c171d38 100644 --- a/dvc/command/checkout.py +++ b/dvc/command/checkout.py @@ -2,7 +2,6 @@ import os from dvc.command.common.base import CmdBase from dvc.logger import Logger -from dvc.system import System class CmdCheckout(CmdBase): @@ -12,9 +11,9 @@ class CmdCheckout(CmdBase): return 0 def remove_untracked_hardlinks(self): - untracked_cache_files = self.untracked_hardlinks_files() + untracked = self.project.scm.untracked_files() - for file in untracked_cache_files: + for file in self.project.cache.find_cache(untracked).keys(): Logger.info(u'Remove \'{}\''.format(file)) os.remove(file) @@ -23,13 +22,3 @@ class CmdCheckout(CmdBase): Logger.info(u'Remove empty directory \'{}\''.format(dir)) os.removedirs(dir) pass - - def untracked_hardlinks_files(self): - untracked_files = set(self.project.scm.untracked_files()) - cached_files = [] - for cache_file in self.project.cache.all(): - hardlinks = list(filter(lambda f: System.samefile(cache_file, f), untracked_files)) - cached_files.extend(hardlinks) - untracked_files = untracked_files - set(hardlinks) - - return cached_files From 64a1666d787c96190d847469432a217a1903435b Mon Sep 17 00:00:00 2001 From: Ruslan Kuprieiev Date: Sat, 6 Jan 2018 18:36:54 +0200 Subject: [PATCH 05/11] test: add test for Cache.find_cache() Signed-off-by: Ruslan Kuprieiev --- tests/test_cache.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_cache.py b/tests/test_cache.py index efa2dff29..a501161dd 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -1,6 +1,7 @@ import os from dvc.cache import Cache +from dvc.system import System from tests.basic_env import TestDvc @@ -22,3 +23,20 @@ class TestCache(TestDvc): def test_get(self): cache = Cache(self.dvc.dvc_dir).get(os.path.basename(self.cache1)) self.assertEquals(cache, self.cache1) + + def test_find_cache(self): + fname1 = os.path.basename(self.cache1) + fname1_md5 = fname1 + fname2 = os.path.basename(self.cache2) + fname2_md5 = fname2 + fname3 = 'non_existing' + + System.hardlink(self.cache1, fname1) + System.hardlink(self.cache2, fname2) + + cache = Cache(self.dvc.dvc_dir).find_cache([fname1, fname2, fname3]) + + expected = {fname1: fname1_md5, fname2: fname2_md5} + + self.assertEqual(len(cache), 2) + self.assertEqual(cache, expected) From 018302e2086d5f5065220f7f446937dbcfaf99f3 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 6 Jan 2018 04:17:55 -0800 Subject: [PATCH 06/11] New command: dvc fsck. Close #381. --- dvc/cache.py | 2 +- dvc/cli.py | 23 ++++++++++++++ dvc/command/fsck.py | 75 +++++++++++++++++++++++++++++++++++++++++++++ dvc/stage.py | 13 +++++++- dvc/system.py | 3 ++ 5 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 dvc/command/fsck.py diff --git a/dvc/cache.py b/dvc/cache.py index 2a5cdea12..e4e59fce7 100644 --- a/dvc/cache.py +++ b/dvc/cache.py @@ -30,7 +30,7 @@ class Cache(object): file_set = set(files) cached = {} for cache_file in self.all(): - cached_files = list(filter(lambda f: System.samefile(cache_file, f, True), file_set)) + cached_files = list(filter(lambda f: System.samefile(cache_file, f), file_set)) cached.update(dict((f, os.path.basename(cache_file)) for f in cached_files)) file_set = file_set - set(cached_files) return cached diff --git a/dvc/cli.py b/dvc/cli.py index f277e7df0..a64b8fd53 100644 --- a/dvc/cli.py +++ b/dvc/cli.py @@ -6,6 +6,7 @@ import argparse from multiprocessing import cpu_count from dvc.command.find import CmdFind +from dvc.command.fsck import CmdFsck from dvc.command.init import CmdInit from dvc.command.remove import CmdRemove from dvc.command.run import CmdRun @@ -414,6 +415,28 @@ def parse_args(argv=None): default=False, help='Show metrics value.') + fsck_parser = subparsers.add_parser( + 'fsck', + parents=[parent_parser], + help='Data file consistency check') + fsck_parser.add_argument( + 'targets', + nargs='*', + help='Data files to check') + fsck_parser.add_argument( + '-a', + '--all', + action='store_true', + default=False, + help='Check all data files') + fsck_parser.add_argument( + '-p', + '--physical', + action='store_true', + default=False, + help='Compute actual md5') + fsck_parser.set_defaults(func=CmdFsck) + if isinstance(argv, str): argv = argv.split() diff --git a/dvc/command/fsck.py b/dvc/command/fsck.py new file mode 100644 index 000000000..d6bc6a790 --- /dev/null +++ b/dvc/command/fsck.py @@ -0,0 +1,75 @@ +import os + +from dvc.command.common.base import CmdBase +from dvc.data_cloud import file_md5 + + +class CmdFsck(CmdBase): + def run(self): + if not self.args.targets and not self.args.all: + self.project.logger.error(u'Data files are not specified') + return 1 + + directions = self.all_directions() + files_and_stages = self.directions_by_datafile(directions) + + if self.args.all: + dvc_files = files_and_stages.keys() + else: + dvc_files = [os.path.relpath(os.path.abspath(f), self.project.root_dir) + for f in self.args.targets] + + caches = self.project.cache.find_cache(dvc_files) + + self.print_fsck(caches, dvc_files, files_and_stages) + return 0 + + def all_directions(self): + result = [] + for stage in self.project.stages(): + for dep in stage.deps + stage.outs: + result.append((stage, dep)) + return result + + def print_fsck(self, caches, dvc_files, files_and_stages): + for file in dvc_files: + print('File {}:'.format(file)) + + full_path = os.path.join(self.project.root_dir, file) + if self.args.physical: + md5 = file_md5(full_path)[0] + print(u' Actual checksum: {}'.format(md5)) + else: + md5 = None + + hardlink_md5 = caches.get(file) + hardlink_msg = hardlink_md5 if caches else 'Error - cache file not found!' + hardlink_error = '!!!' if hardlink_md5 and md5 and md5 != hardlink_md5 else '' + print(u' Hardlink to cache file: {} {}'.format(hardlink_msg, hardlink_error)) + + state = self.project.state.get(file) + local_state_error = '!!!' if state.md5 and hardlink_md5 and state.md5 != hardlink_md5 else '' + print(u' Local state checksum: {} {}'.format(state.md5 if state else '', local_state_error)) + print(u' Local state mtime: {}'.format(state.mtime if state else '')) + mtime = os.path.getmtime(full_path) if os.path.exists(full_path) else 'None' + print(u' Actual mtime: {}'.format(mtime)) + + for stage, dep in files_and_stages.get(file, []): + direction = type(dep).__name__ + stage_error = '!!!' if dep.md5 and hardlink_md5 and dep.md5 != hardlink_md5 else '' + print(u' Stage file: {}'.format(stage.dvc_path)) + print(u' Type: {}'.format(direction)) + print(u' Checksum: {} {}'.format(dep.md5, stage_error)) + print(u' Use cache: {}'.format(str(dep.use_cache).lower())) + pass + + @staticmethod + def directions_by_datafile(directions): + result = {} + + for stage, dep in directions: + if dep.dvc_path not in result: + result[dep.dvc_path] = [] + result[dep.dvc_path].append((stage, dep)) + + return result diff --git a/dvc/stage.py b/dvc/stage.py index 749555df3..e11fcc0ce 100644 --- a/dvc/stage.py +++ b/dvc/stage.py @@ -54,7 +54,14 @@ class Output(object): self.md5 = md5 self.use_cache = use_cache + @property + def dvc_path(self): + return os.path.relpath(self.path, self.project.root_dir) + def _changed_md5(self): + if not os.path.exists(self.path): + return True + state = self.project.state.get(self.path) if state and state.mtime == self.mtime(): md5 = state.md5 @@ -213,7 +220,11 @@ class Stage(object): @property def relpath(self): - return os.path.relpath(self.path, '.') + return os.path.relpath(self.path) + + @property + def dvc_path(self): + return os.path.relpath(self.path, self.project.root_dir) @staticmethod def is_stage_file(path): diff --git a/dvc/system.py b/dvc/system.py index 99c662e9a..28cfb3a03 100644 --- a/dvc/system.py +++ b/dvc/system.py @@ -27,6 +27,9 @@ class System(object): @staticmethod def samefile(path1, path2): + if not os.path.exists(path1) or not os.path.exists(path2): + return False + if System.is_unix(): return os.path.samefile(path1, path2) From de533f0437d76f8a9ece22b27ad951599fd23bc0 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 6 Jan 2018 15:47:57 -0800 Subject: [PATCH 07/11] Remove --all option - empty param list instead --- dvc/cli.py | 6 ------ dvc/command/fsck.py | 10 +++------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/dvc/cli.py b/dvc/cli.py index a64b8fd53..cea296125 100644 --- a/dvc/cli.py +++ b/dvc/cli.py @@ -423,12 +423,6 @@ def parse_args(argv=None): 'targets', nargs='*', help='Data files to check') - fsck_parser.add_argument( - '-a', - '--all', - action='store_true', - default=False, - help='Check all data files') fsck_parser.add_argument( '-p', '--physical', diff --git a/dvc/command/fsck.py b/dvc/command/fsck.py index ec4d98af9..88374217f 100644 --- a/dvc/command/fsck.py +++ b/dvc/command/fsck.py @@ -6,18 +6,14 @@ from dvc.data_cloud import file_md5 class CmdFsck(CmdBase): def run(self): - if not self.args.targets and not self.args.all: - self.project.logger.error(u'Data files are not specified') - return 1 - directions = self.project.all_directions() files_and_stages = self.directions_by_datafile(directions) - if self.args.all: - dvc_files = files_and_stages.keys() - else: + if self.args.targets: dvc_files = [os.path.relpath(os.path.abspath(f), self.project.root_dir) for f in self.args.targets] + else: + dvc_files = files_and_stages.keys() caches = self.project.cache.find_cache(dvc_files) From 24b9d5a3376e4c17ce2142c1e65b2caa2d9481c0 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 6 Jan 2018 18:54:37 -0800 Subject: [PATCH 08/11] Remove --all again --- dvc/command/fsck.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/dvc/command/fsck.py b/dvc/command/fsck.py index ff3199831..029d463c8 100644 --- a/dvc/command/fsck.py +++ b/dvc/command/fsck.py @@ -6,18 +6,14 @@ from dvc.data_cloud import file_md5 class CmdFsck(CmdBase): def run(self): - if not self.args.targets and not self.args.all: - self.project.logger.error(u'Data files are not specified') - return 1 - directions = self.all_directions() files_and_stages = self.directions_by_datafile(directions) - if self.args.all: - dvc_files = files_and_stages.keys() - else: + if self.args.targets: dvc_files = [os.path.relpath(os.path.abspath(f), self.project.root_dir) for f in self.args.targets] + else: + dvc_files = files_and_stages.keys() caches = self.project.cache.find_cache(dvc_files) From 828970a0c448a22e26a44447c8a5f40d416ce6ea Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 6 Jan 2018 19:06:08 -0800 Subject: [PATCH 09/11] Bugfix: "no cache file" message --- dvc/command/fsck.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dvc/command/fsck.py b/dvc/command/fsck.py index 029d463c8..68f90b7ed 100644 --- a/dvc/command/fsck.py +++ b/dvc/command/fsck.py @@ -39,7 +39,7 @@ class CmdFsck(CmdBase): md5 = None hardlink_md5 = caches.get(file) - hardlink_msg = hardlink_md5 if caches else 'Error - cache file not found!' + hardlink_msg = hardlink_md5 if hardlink_md5 else 'No cache file found' hardlink_error = '!!!' if hardlink_md5 and md5 and md5 != hardlink_md5 else '' print(u' Hardlink to cache file: {} {}'.format(hardlink_msg, hardlink_error)) @@ -69,4 +69,3 @@ class CmdFsck(CmdBase): result[dep.dvc_path].append((stage, dep)) return result - From fce38bce7b67c65331ce407f8a09650617638610 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 6 Jan 2018 20:15:32 -0800 Subject: [PATCH 10/11] Refactoring: reduce method length and use unicode string --- dvc/command/fsck.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dvc/command/fsck.py b/dvc/command/fsck.py index 68f90b7ed..6db5688d1 100644 --- a/dvc/command/fsck.py +++ b/dvc/command/fsck.py @@ -29,7 +29,7 @@ class CmdFsck(CmdBase): def print_fsck(self, caches, dvc_files, files_and_stages): for file in dvc_files: - print('File {}:'.format(file)) + print(u'File {}:'.format(file)) full_path = os.path.join(self.project.root_dir, file) if self.args.physical: @@ -51,10 +51,9 @@ class CmdFsck(CmdBase): print(u' Actual mtime: {}'.format(mtime)) for stage, dep in files_and_stages.get(file, []): - direction = type(dep).__name__ stage_error = '!!!' if dep.md5 and hardlink_md5 and dep.md5 != hardlink_md5 else '' print(u' Stage file: {}'.format(stage.dvc_path)) - print(u' Type: {}'.format(direction)) + print(u' Type: {}'.format(type(dep).__name__)) print(u' Checksum: {} {}'.format(dep.md5, stage_error)) print(u' Use cache: {}'.format(str(dep.use_cache).lower())) pass From e0dac325753aa141ef4982f2cc50710c264deda0 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 6 Jan 2018 20:17:17 -0800 Subject: [PATCH 11/11] Refactoring: reduce LOC in a file by getting rid of Direction class --- dvc/stage.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/dvc/stage.py b/dvc/stage.py index 7144222e2..dcad68e9b 100644 --- a/dvc/stage.py +++ b/dvc/stage.py @@ -39,12 +39,7 @@ class OutputAlreadyTrackedError(OutputError): super(OutputAlreadyTrackedError, self).__init__(path, 'already tracked by scm(e.g. git)') -class Direction(object): - DIRECTION_TYPE_OUT = 'Output' - DIRECTION_TYPE_DEP = 'Dependency' - - -class Output(Direction): +class Output(object): PARAM_PATH = 'path' PARAM_MD5 = 'md5' PARAM_CACHE = 'cache' @@ -58,7 +53,6 @@ class Output(Direction): self.md5 = md5 self.use_cache = use_cache - self.direction = self.DIRECTION_TYPE_OUT @property def dvc_path(self): @@ -207,9 +201,7 @@ class Output(Direction): class Dependency(Output): - def __init__(self, project, path, md5=None, use_cache=False): - super(Dependency, self).__init__(project, path, md5, use_cache) - self.direction = self.DIRECTION_TYPE_DEP + pass class Stage(object):