@@ -257,15 +257,38 @@ def to_local(self) -> 'FileSet':
257
257
if fs .isdir (root ):
258
258
temp_dir = new_temp_dir (prefix = TEMP_FILE_PREFIX ,
259
259
suffix = temp_file_suffix )
260
- # Note, AbstractFileSystem.get() behaves
261
- # unpredictably. Sometimes it will create a new directory
262
- # named after root in temp_dir (e.g. this is the case
263
- # if temp_dir exists). To avoid this, we add a non-existing
264
- # directory here:
265
- temp_dir += "/data"
266
- # TODO: replace by loop so we can apply includes/excludes
267
- # before downloading actual files. See impl of fs.get().
268
- fs .get (root + "/*" , temp_dir , recursive = True )
260
+
261
+ # Note, actually want to use
262
+ # fs.get(root + "/*", temp_dir, recursive=True)
263
+ # here, but fs.get() behaves unpredictably with
264
+ # fsspec=2023.3.0 and s3fs=2023.3.0.
265
+ # Sometimes it will create a new subdirectory in temp_dir
266
+ # named after last path element of root, sometimes not.
267
+ # Behaviour randomly changes if
268
+ # - temp_dir exists or not
269
+ # - root or temp_dir paths end with a slash
270
+ # - whether root or temp_dir are absolute path or not.
271
+ #
272
+ # See https://github.com/dcs4cop/xcube/issues/828
273
+ #
274
+ # Workaround used here is to manually download the directory.
275
+
276
+ def get_files (source : str , target : str ):
277
+ source_items = fs .listdir (source , detail = True )
278
+ for source_item in source_items :
279
+ source_path = source_item ["name" ]
280
+ source_type = source_item ["type" ]
281
+ source_name = source_path .replace ("\\ " , "/" ) \
282
+ .split ("/" )[- 1 ]
283
+ target_path = os .path .join (target , source_name )
284
+ if source_type == "file" :
285
+ fs .get_file (source_path , target_path )
286
+ elif source_type == "directory" :
287
+ os .mkdir (target_path )
288
+ get_files (source_path , target_path )
289
+
290
+ get_files (root , temp_dir )
291
+
269
292
return FileSet (temp_dir ,
270
293
sub_path = self .sub_path ,
271
294
includes = self .includes ,
0 commit comments