mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-06 23:09:55 +01:00
+14
@@ -8,6 +8,7 @@ from multiprocessing import cpu_count
|
||||
from dvc.logger import Logger
|
||||
from dvc.command.init import CmdInit
|
||||
from dvc.command.remove import CmdRemove
|
||||
from dvc.command.move import CmdMove
|
||||
from dvc.command.run import CmdRun
|
||||
from dvc.command.repro import CmdRepro
|
||||
from dvc.command.data_sync import CmdDataPush, CmdDataPull, CmdDataFetch
|
||||
@@ -289,6 +290,19 @@ def parse_args(argv=None):
|
||||
help='DVC files.')
|
||||
remove_parser.set_defaults(func=CmdRemove)
|
||||
|
||||
# Move
|
||||
move_parser = subparsers.add_parser(
|
||||
'move',
|
||||
parents=[parent_parser],
|
||||
help='Move output of DVC file.')
|
||||
move_parser.add_argument(
|
||||
'src',
|
||||
help='Source')
|
||||
move_parser.add_argument(
|
||||
'dst',
|
||||
help='Destination')
|
||||
move_parser.set_defaults(func=CmdMove)
|
||||
|
||||
# Garbage collector
|
||||
gc_parser = subparsers.add_parser(
|
||||
'gc',
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
from dvc.exceptions import DvcException
|
||||
from dvc.command.common.base import CmdBase
|
||||
|
||||
|
||||
class CmdMove(CmdBase):
|
||||
def run(self):
|
||||
try:
|
||||
self.project.move(self.args.src, self.args.dst)
|
||||
except DvcException as ex:
|
||||
self.project.logger.error('Failed to move \'{}\' -> \'{}\''.format(self.args.src,
|
||||
self.args.dst), ex)
|
||||
return 1
|
||||
return 0
|
||||
@@ -33,7 +33,7 @@ class DependencyLOCAL(DependencyBase):
|
||||
if not os.path.isabs(path):
|
||||
path = self.ospath(path)
|
||||
path = os.path.join(stage.cwd, path)
|
||||
self.path = os.path.normpath(path)
|
||||
self.path = os.path.abspath(os.path.normpath(path))
|
||||
|
||||
self.path_info = {'scheme': 'local',
|
||||
'path': self.path}
|
||||
|
||||
@@ -82,3 +82,15 @@ class OutputLOCAL(DependencyLOCAL):
|
||||
self.remote.remove(self.path_info)
|
||||
if ignore_remove and self.use_cache:
|
||||
self.project.scm.ignore_remove(self.path)
|
||||
|
||||
def move(self, out):
|
||||
if self.use_cache:
|
||||
self.project.scm.ignore_remove(self.path)
|
||||
|
||||
self.remote.move(self.path_info, out.path_info)
|
||||
self.path = out.path
|
||||
self.path_info = out.path_info
|
||||
self.save()
|
||||
|
||||
if self.use_cache:
|
||||
self.project.scm.ignore(self.path)
|
||||
|
||||
@@ -5,6 +5,7 @@ import json
|
||||
import networkx as nx
|
||||
from jsonpath_rw import parse
|
||||
|
||||
import dvc.output as Output
|
||||
from dvc.logger import Logger
|
||||
from dvc.exceptions import DvcException
|
||||
from dvc.stage import Stage
|
||||
@@ -137,6 +138,35 @@ class Project(object):
|
||||
|
||||
return stage
|
||||
|
||||
def move(self, from_path, to_path):
|
||||
from_out = Output.loads_from(Stage(self, cwd=os.curdir), [from_path])[0]
|
||||
|
||||
found = False
|
||||
for stage in self.stages():
|
||||
for out in stage.outs:
|
||||
if out.path != from_out.path:
|
||||
continue
|
||||
|
||||
if not stage.is_data_source:
|
||||
raise DvcException('Dvcfile \'{}\' is not a data source.'.format(stage.rel_path))
|
||||
|
||||
found = True
|
||||
to_out = Output.loads_from(out.stage, [to_path], out.cache, out.metric)[0]
|
||||
out.move(to_out)
|
||||
|
||||
stage_base = os.path.basename(stage.path).rstrip(Stage.STAGE_FILE_SUFFIX)
|
||||
stage_dir = os.path.dirname(stage.path)
|
||||
from_base = os.path.basename(from_path)
|
||||
to_base = os.path.basename(to_path)
|
||||
if stage_base == from_base:
|
||||
os.unlink(stage.path)
|
||||
stage.path = os.path.join(stage_dir, to_base + Stage.STAGE_FILE_SUFFIX)
|
||||
|
||||
stage.dump()
|
||||
|
||||
if not found:
|
||||
raise DvcException('Unable to find dvcfile with output \'{}\''.format(from_path))
|
||||
|
||||
def run(self,
|
||||
cmd=None,
|
||||
deps=[],
|
||||
|
||||
@@ -79,6 +79,12 @@ class RemoteBase(object):
|
||||
def upload(self, path, path_info, name=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def remove(self, path_info):
|
||||
raise NotImplementedError
|
||||
|
||||
def move(self, path_info):
|
||||
raise NotImplementedError
|
||||
|
||||
def cache_file_key(self, fname):
|
||||
""" Key of a file within the bucket """
|
||||
relpath = os.path.relpath(fname, self.project.cache.local.cache_dir)
|
||||
|
||||
@@ -246,6 +246,12 @@ class RemoteLOCAL(RemoteBase):
|
||||
|
||||
remove(path_info['path'])
|
||||
|
||||
def move(self, from_info, to_info):
|
||||
if from_info['scheme'] != 'local' or to_info['scheme'] != 'local':
|
||||
raise NotImplementedError
|
||||
|
||||
move(from_info['path'], to_info['path'])
|
||||
|
||||
def cache_file_key(self, path):
|
||||
relpath = os.path.relpath(os.path.abspath(path), self.project.cache.local.cache_dir)
|
||||
return os.path.join(self.prefix, relpath)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import os
|
||||
|
||||
from dvc.main import main
|
||||
from dvc.exceptions import DvcException
|
||||
|
||||
from tests.basic_env import TestDvc
|
||||
|
||||
|
||||
class TestMove(TestDvc):
|
||||
def test(self):
|
||||
dst = self.FOO + '1'
|
||||
self.dvc.add(self.FOO)
|
||||
self.dvc.move(self.FOO, dst)
|
||||
|
||||
self.assertFalse(os.path.isfile(self.FOO))
|
||||
self.assertTrue(os.path.isfile(dst))
|
||||
|
||||
|
||||
class TestMoveNonExistentFile(TestDvc):
|
||||
def test(self):
|
||||
with self.assertRaises(DvcException) as cx:
|
||||
self.dvc.move('non_existent_file', 'dst')
|
||||
|
||||
|
||||
class TestMoveDirectory(TestDvc):
|
||||
def test(self):
|
||||
dst = 'dst'
|
||||
stage_add = self.dvc.add(self.DATA_DIR)
|
||||
self.dvc.move(self.DATA_DIR, dst)
|
||||
self.assertFalse(os.path.exists(self.DATA_DIR))
|
||||
self.assertTrue(os.path.exists(dst))
|
||||
|
||||
|
||||
class TestCmdMove(TestDvc):
|
||||
def test(self):
|
||||
stage = self.dvc.add(self.FOO)
|
||||
ret = main(['move', self.FOO, self.FOO + '1'])
|
||||
self.assertEqual(ret, 0)
|
||||
|
||||
ret = main(['move', 'non-existing-file', 'dst'])
|
||||
self.assertNotEqual(ret, 0)
|
||||
Reference in New Issue
Block a user