dvc: add basic 'dvc status'

(dvc) ➜  myrepo git:(master) ✗ dvc status
foo.dvc
        outs
                changed:  foo
foo2.dvc
        outs
                changed:  foo2
        deps
                changed:  foo1
foo1.dvc
        outs
                changed:  foo1
        deps
                changed:  foo

(dvc) ➜  myrepo git:(master) ✗ dvc status --cloud

        new:      c1/57a79031e1c40f85931829bc5fc552

Signed-off-by: Ruslan Kuprieiev <[email protected]>
This commit is contained in:
Ruslan Kuprieiev
2018-03-16 10:58:09 +02:00
parent 06ff91af62
commit 71fef4d857
5 changed files with 88 additions and 18 deletions
+6 -1
View File
@@ -163,7 +163,12 @@ def parse_args(argv=None):
status_parser = subparsers.add_parser(
'status',
parents=[parent_cache_parser],
help='Show mismatches between local cache and cloud cache')
help='Show the project status')
status_parser.add_argument('-c',
'--cloud',
action='store_true',
default=False,
help='Show status of a local cache compared to a cloud')
status_parser.set_defaults(func=CmdDataStatus)
# Repro
+18 -15
View File
@@ -6,27 +6,30 @@ from dvc.command.data_sync import CmdDataBase
class CmdDataStatus(CmdDataBase):
def _show(self, status):
for s in status:
target, ret = s
STATUS_LEN = 10
STATUS_INDENT = '\t'
if ret == cloud.STATUS_UNKNOWN or ret == cloud.STATUS_OK:
continue
def _normalize(self, s):
s+=':'
if len(s) >= self.STATUS_LEN:
return s
return s + (self.STATUS_LEN - len(s))*' '
prefix_map = {
cloud.STATUS_DELETED : 'deleted: ',
cloud.STATUS_MODIFIED : 'modified:',
cloud.STATUS_NEW : 'new file:',
}
def _show(self, status, indent=0):
ind = indent * self.STATUS_INDENT
path = os.path.relpath(target, self.project.cache.cache_dir)
self.project.logger.info('\t{}\t{}'.format(prefix_map[ret], path))
for key, value in status.items():
if isinstance(value, dict):
self.project.logger.info('{}{}'.format(ind, key))
self._show(value, indent+1)
else:
self.project.logger.info('{}{}{}'.format(ind, self._normalize(value), key))
def do_run(self, target=None):
indent = 1 if self.args.cloud else 0
try:
status = self.project.status(target=target, jobs=self.args.jobs)
self._show(status)
status = self.project.status(target=target, jobs=self.args.jobs, cloud=self.args.cloud)
self._show(status, indent)
except Exception as exc:
self.project.logger.error('Failed to obtain data status', exc)
return 1
+6
View File
@@ -75,6 +75,12 @@ class Dependency(object):
def changed(self):
return self._changed_md5()
def status(self):
if self.changed():
#FIXME better msgs
return {self.rel_path: 'changed'}
return {}
@staticmethod
def is_dir_cache(cache):
return cache.endswith(Output.MD5_DIR_SUFFIX)
+37 -2
View File
@@ -2,6 +2,8 @@ import os
import stat
import networkx as nx
import dvc.cloud.base as cloud
from dvc.logger import Logger
from dvc.exceptions import DvcException
from dvc.stage import Stage, Output
@@ -209,8 +211,41 @@ class Project(object):
self.checkout()
return ret
def status(self, target=None, jobs=1):
return self.cloud.status(self._used_cache(target), jobs)
def _local_status(self, target=None):
status = {}
if target:
stages = [Stage.load(self, target)]
else:
stages = self.stages()
for stage in self.stages():
status.update(stage.status())
return status
def _cloud_status(self, target=None, jobs=1):
status = {}
for target, ret in self.cloud.status(self._used_cache(target), jobs):
if ret == cloud.STATUS_UNKNOWN or ret == cloud.STATUS_OK:
continue
prefix_map = {
cloud.STATUS_DELETED: 'deleted',
cloud.STATUS_MODIFIED: 'modified',
cloud.STATUS_NEW: 'new',
}
path = os.path.relpath(target, self.cache.cache_dir)
status[path] = prefix_map[ret]
return status
def status(self, target=None, jobs=1, cloud=False):
if cloud:
return self._cloud_status(target, jobs)
return self._local_status(target)
def graph(self):
G = nx.DiGraph()
+21
View File
@@ -183,3 +183,24 @@ class Stage(object):
def checkout(self):
for out in self.outs:
out.checkout()
def _status(self, entries, name):
ret = {}
for entry in entries:
ret.update(entry.status())
if ret:
return {name: ret}
return {}
def status(self):
ret = {}
ret.update(self._status(self.deps, 'deps'))
ret.update(self._status(self.outs, 'outs'))
if ret:
return {self.relpath: ret}
return {}