Skip to content

Commit

Permalink
Merge pull request #2683 from mroutis/fix-2678
Browse files Browse the repository at this point in the history
s3: ignore empty directories while walking files
  • Loading branch information
efiop authored Nov 29, 2019
2 parents 6ad278f + 1f9a0f0 commit 94f803e
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 1 deletion.
12 changes: 12 additions & 0 deletions dvc/remote/s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,15 @@ def exists(self, path_info):
fname = next(self._list_paths(path_info, max_items=1), "")
return path_info.path == fname or fname.startswith(dir_path.path)

def makedirs(self, path_info):
# We need to support creating empty directories, which means
# creating an object with an empty body and a trailing slash `/`.
#
# We are not creating directory objects for every parent prefix,
# as it is not required.
dir_path = path_info / ""
self.s3.put_object(Bucket=path_info.bucket, Key=dir_path.path, Body="")

def isdir(self, path_info):
# S3 doesn't have a concept for directories.
#
Expand Down Expand Up @@ -271,4 +280,7 @@ def _generate_download_url(self, path_info, expires=3600):

def walk_files(self, path_info, max_items=None):
for fname in self._list_paths(path_info, max_items):
if fname.endswith("/"):
continue

yield path_info.replace(path=fname)
12 changes: 11 additions & 1 deletion tests/unit/remote/test_s3.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,11 @@ def test_walk_files(remote):
remote.path_info / "data/subdir/1",
remote.path_info / "data/subdir/2",
remote.path_info / "data/subdir/3",
remote.path_info / "empty_file",
remote.path_info / "foo",
]

assert list(remote.walk_files(remote.path_info / "data")) == files
assert list(remote.walk_files(remote.path_info)) == files


def test_copy_preserve_etag_across_buckets(remote):
Expand All @@ -99,3 +101,11 @@ def test_copy_preserve_etag_across_buckets(remote):
to_etag = RemoteS3.get_etag(s3, "another", "foo")

assert from_etag == to_etag


def test_makedirs(remote):
empty_dir = remote.path_info / "empty_dir" / ""
remote.remove(empty_dir)
assert not remote.exists(empty_dir)
remote.makedirs(empty_dir)
assert remote.exists(empty_dir)

0 comments on commit 94f803e

Please sign in to comment.