Skip to content

Commit 8fa2682

Browse files
authored
Merge pull request #2894 from odd-industries/master
import-url: support directories
2 parents 13f6101 + 896b08c commit 8fa2682

File tree

2 files changed

+66
-4
lines changed

2 files changed

+66
-4
lines changed

dvc/remote/base.py

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -577,11 +577,51 @@ def download(
577577
if to_info.scheme != "local":
578578
raise NotImplementedError
579579

580-
logger.debug("Downloading '{}' to '{}'".format(from_info, to_info))
580+
if self.isdir(from_info):
581+
return self._download_dir(
582+
from_info, to_info, name, no_progress_bar, file_mode, dir_mode
583+
)
584+
return self._download_file(
585+
from_info, to_info, name, no_progress_bar, file_mode, dir_mode
586+
)
581587

582-
name = name or to_info.name
588+
def _download_dir(
589+
self, from_info, to_info, name, no_progress_bar, file_mode, dir_mode
590+
):
591+
file_to_infos = (
592+
to_info / file_to_info.relative_to(from_info)
593+
for file_to_info in self.walk_files(from_info)
594+
)
583595

596+
with ThreadPoolExecutor(max_workers=self.JOBS) as executor:
597+
file_from_info = list(self.walk_files(from_info))
598+
download_files = partial(
599+
self._download_file,
600+
name=name,
601+
no_progress_bar=True,
602+
file_mode=file_mode,
603+
dir_mode=dir_mode,
604+
)
605+
futures = executor.map(
606+
download_files, file_from_info, file_to_infos
607+
)
608+
with Tqdm(
609+
futures,
610+
total=len(file_from_info),
611+
desc="Downloading directory",
612+
unit="Files",
613+
disable=no_progress_bar,
614+
) as futures:
615+
return sum(futures)
616+
617+
def _download_file(
618+
self, from_info, to_info, name, no_progress_bar, file_mode, dir_mode
619+
):
584620
makedirs(to_info.parent, exist_ok=True, mode=dir_mode)
621+
622+
logger.debug("Downloading '{}' to '{}'".format(from_info, to_info))
623+
name = name or to_info.name
624+
585625
tmp_file = tmp_fname(to_info)
586626

587627
try:

tests/unit/remote/test_remote_dir.py

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# -*- coding: utf-8 -*-
22
import pytest
3-
3+
import os
44
from dvc.remote.s3 import RemoteS3
5-
5+
from dvc.utils import walk_files
6+
from dvc.path_info import PathInfo
67
from tests.remotes import GCP, S3Mocked
78

89
remotes = [GCP, S3Mocked]
@@ -132,3 +133,24 @@ def test_isfile(remote):
132133

133134
for expected, path in test_cases:
134135
assert remote.isfile(remote.path_info / path) == expected
136+
137+
138+
@pytest.mark.parametrize("remote", remotes, indirect=True)
139+
def test_download_dir(remote, tmpdir):
140+
path = str(tmpdir / "data")
141+
to_info = PathInfo(path)
142+
remote.download(remote.path_info / "data", to_info)
143+
assert os.path.isdir(path)
144+
data_dir = tmpdir / "data"
145+
assert len(list(walk_files(path, None))) == 7
146+
assert (data_dir / "alice").read_text(encoding="utf-8") == "alice"
147+
assert (data_dir / "alpha").read_text(encoding="utf-8") == "alpha"
148+
assert (data_dir / "subdir-file.txt").read_text(
149+
encoding="utf-8"
150+
) == "subdir"
151+
assert (data_dir / "subdir" / "1").read_text(encoding="utf-8") == "1"
152+
assert (data_dir / "subdir" / "2").read_text(encoding="utf-8") == "2"
153+
assert (data_dir / "subdir" / "3").read_text(encoding="utf-8") == "3"
154+
assert (data_dir / "subdir" / "empty_file").read_text(
155+
encoding="utf-8"
156+
) == ""

0 commit comments

Comments
 (0)