|
5 | 5 | import os |
6 | 6 | import threading |
7 | 7 |
|
| 8 | +from botocore.exceptions import ClientError |
8 | 9 | from funcy import cached_property, wrap_prop |
9 | 10 |
|
10 | 11 | from dvc.config import Config |
@@ -207,10 +208,26 @@ def _list_paths(self, path_info, max_items=None): |
207 | 208 | def list_cache_paths(self): |
208 | 209 | return self._list_paths(self.path_info) |
209 | 210 |
|
| 211 | + def isfile(self, path_info): |
| 212 | + if path_info.path.endswith("/"): |
| 213 | + return False |
| 214 | + |
| 215 | + try: |
| 216 | + self.s3.head_object(Bucket=path_info.bucket, Key=path_info.path) |
| 217 | + except ClientError as exc: |
| 218 | + if exc.response["Error"]["Code"] != "404": |
| 219 | + raise |
| 220 | + return False |
| 221 | + |
| 222 | + return True |
| 223 | + |
210 | 224 | def exists(self, path_info): |
211 | | - dir_path = path_info / "" |
212 | | - fname = next(self._list_paths(path_info, max_items=1), "") |
213 | | - return path_info.path == fname or fname.startswith(dir_path.path) |
| 225 | + """Check if the blob exists. If it does not exist, |
| 226 | + it could be a part of a directory path. |
| 227 | +
|
| 228 | + eg: if `data/file.txt` exists, check for `data` should return True |
| 229 | + """ |
| 230 | + return self.isfile(path_info) or self.isdir(path_info) |
214 | 231 |
|
215 | 232 | def makedirs(self, path_info): |
216 | 233 | # We need to support creating empty directories, which means |
@@ -279,7 +296,7 @@ def _generate_download_url(self, path_info, expires=3600): |
279 | 296 | ) |
280 | 297 |
|
281 | 298 | def walk_files(self, path_info, max_items=None): |
282 | | - for fname in self._list_paths(path_info, max_items): |
| 299 | + for fname in self._list_paths(path_info / "", max_items): |
283 | 300 | if fname.endswith("/"): |
284 | 301 | continue |
285 | 302 |
|
|
0 commit comments