diff --git a/dvc/remote/ssh/connection.py b/dvc/remote/ssh/connection.py index dcbb1727cc..b2da0b67ac 100644 --- a/dvc/remote/ssh/connection.py +++ b/dvc/remote/ssh/connection.py @@ -185,8 +185,27 @@ def download(self, src, dest, no_progress_bar=False, progress_title=None): self.sftp.get(src, dest, callback=pbar.update_to) def move(self, src, dst): + """Rename src to dst, if it is not possible (in case src and dst are + on different filesystems) and actual physical copying of data is + happening. + """ self.makedirs(posixpath.dirname(dst)) - self.sftp.rename(src, dst) + + try: + self.sftp.rename(src, dst) + except OSError: + self._atomic_copy(src, dst) + + self.remove(src) + + def _atomic_copy(self, src, dst): + tmp = tmp_fname(dst) + + try: + self.copy(src, tmp) + self.sftp.rename(tmp, dst) + finally: + self.remove(tmp) def upload(self, src, dest, no_progress_bar=False, progress_title=None): self.makedirs(posixpath.dirname(dest)) diff --git a/tests/unit/remote/ssh/test_connection.py b/tests/unit/remote/ssh/test_connection.py index f0c12ec219..6b1300ce30 100644 --- a/tests/unit/remote/ssh/test_connection.py +++ b/tests/unit/remote/ssh/test_connection.py @@ -111,3 +111,9 @@ def test_hardlink(repo_dir, ssh): def test_copy(repo_dir, ssh): ssh.copy("foo", "link") assert filecmp.cmp("foo", "link") + + +def test_move(repo_dir, ssh): + ssh.move("foo", "copy") + assert os.path.exists("copy") + assert not os.path.exists("foo")