@@ -1087,11 +1087,12 @@ def get_singularity_images(self, current_revision: str = "") -> None:
1087
1087
# Organise containers based on what we need to do with them
1088
1088
containers_exist : List [str ] = []
1089
1089
containers_cache : List [Tuple [str , str , str ]] = []
1090
+ containers_library : List [Tuple [str , str , str , Optional [str ]]] = []
1090
1091
containers_download : List [Tuple [str , str , Optional [str ]]] = []
1091
1092
containers_pull : List [Tuple [str , str , Optional [str ]]] = []
1092
1093
for container in self .containers :
1093
1094
# Fetch the output and cached filenames for this container
1094
- out_path , cache_path = self .singularity_image_filenames (container )
1095
+ out_path , cache_path , library_path = self .singularity_image_filenames (container )
1095
1096
1096
1097
# Check that the directories exist
1097
1098
out_path_dir = os .path .dirname (out_path )
@@ -1109,11 +1110,16 @@ def get_singularity_images(self, current_revision: str = "") -> None:
1109
1110
containers_exist .append (container )
1110
1111
continue
1111
1112
1112
- # We have a copy of this in the NXF_SINGULARITY_CACHE dir
1113
+ # We have a copy of this in NXF_SINGULARITY_CACHEDIR
1113
1114
if cache_path and os .path .exists (cache_path ):
1114
1115
containers_cache .append ((container , out_path , cache_path ))
1115
1116
continue
1116
1117
1118
+ # We have a copy of this in NXF_SINGULARITY_LIBRARYDIR
1119
+ if library_path and os .path .exists (library_path ):
1120
+ containers_library .append ((container , library_path , out_path , cache_path ))
1121
+ continue
1122
+
1117
1123
# Direct download within Python
1118
1124
if container .startswith ("http" ):
1119
1125
containers_download .append ((container , out_path , cache_path ))
@@ -1145,6 +1151,12 @@ def get_singularity_images(self, current_revision: str = "") -> None:
1145
1151
self .singularity_copy_cache_image (* container )
1146
1152
progress .update (task , advance = 1 )
1147
1153
1154
+ if containers_library :
1155
+ for container in containers_library :
1156
+ progress .update (task , description = "Copying singularity images from library" )
1157
+ self .singularity_copy_library_image (* container )
1158
+ progress .update (task , advance = 1 )
1159
+
1148
1160
if containers_download or containers_pull :
1149
1161
# if clause gives slightly better UX, because Download is no longer displayed if nothing is left to be downloaded.
1150
1162
with concurrent .futures .ThreadPoolExecutor (max_workers = self .parallel_downloads ) as pool :
@@ -1226,19 +1238,20 @@ def get_singularity_images(self, current_revision: str = "") -> None:
1226
1238
# Task should advance in any case. Failure to pull will not kill the download process.
1227
1239
progress .update (task , advance = 1 )
1228
1240
1229
- def singularity_image_filenames (self , container : str ) -> Tuple [str , Optional [str ]]:
1241
+ def singularity_image_filenames (self , container : str ) -> Tuple [str , Optional [str ], Optional [ str ] ]:
1230
1242
"""Check Singularity cache for image, copy to destination folder if found.
1231
1243
1232
1244
Args:
1233
1245
container (str): A pipeline's container name. Can be direct download URL
1234
1246
or a Docker Hub repository ID.
1235
1247
1236
1248
Returns:
1237
- tuple (str, str): Returns a tuple of (out_path, cache_path).
1249
+ (str, str, str ): Returns a tuple of (out_path, cache_path, library_path ).
1238
1250
out_path is the final target output path. it may point to the NXF_SINGULARITY_CACHEDIR, if cache utilisation was set to 'amend'.
1239
1251
If cache utilisation was set to 'copy', it will point to the target folder, a subdirectory of the output directory. In the latter case,
1240
1252
cache_path may either be None (image is not yet cached locally) or point to the image in the NXF_SINGULARITY_CACHEDIR, so it will not be
1241
1253
downloaded from the web again, but directly copied from there. See get_singularity_images() for implementation.
1254
+ library_path is the points to the container in NXF_SINGULARITY_LIBRARYDIR, if the latter is defined.
1242
1255
"""
1243
1256
1244
1257
# Generate file paths
@@ -1281,14 +1294,26 @@ def singularity_image_filenames(self, container: str) -> Tuple[str, Optional[str
1281
1294
elif self .container_cache_utilisation in ["amend" , "copy" ]:
1282
1295
raise FileNotFoundError ("Singularity cache is required but no '$NXF_SINGULARITY_CACHEDIR' set!" )
1283
1296
1284
- return (out_path , cache_path )
1297
+ library_path = None
1298
+ if os .environ .get ("NXF_SINGULARITY_LIBRARYDIR" ):
1299
+ library_path = os .path .join (os .environ ["NXF_SINGULARITY_LIBRARYDIR" ], out_name )
1300
+
1301
+ return (out_path , cache_path , library_path )
1285
1302
1286
1303
def singularity_copy_cache_image (self , container : str , out_path : str , cache_path : str ) -> None :
1287
1304
"""Copy Singularity image from NXF_SINGULARITY_CACHEDIR to target folder."""
1288
1305
self .singularity_copy_image (container , cache_path , out_path )
1289
1306
# Create symlinks to ensure that the images are found even with different registries being used.
1290
1307
self .symlink_singularity_images (cache_path )
1291
1308
1309
+ def singularity_copy_library_image (
1310
+ self , container : str , library_path : str , out_path : str , cache_path : Optional [str ]
1311
+ ) -> None :
1312
+ """Copy Singularity image from NXF_SINGULARITY_LIBRARYDIR to target folder, and possibly NXF_SINGULARITY_CACHEDIR."""
1313
+ self .singularity_copy_image (container , library_path , out_path )
1314
+ if cache_path :
1315
+ self .singularity_copy_image (container , library_path , cache_path )
1316
+
1292
1317
def singularity_copy_image (self , container : str , from_path : str , to_path : str ) -> None :
1293
1318
"""Copy Singularity image between folders. This function is used seamlessly
1294
1319
across the target directory, NXF_SINGULARITY_CACHEDIR, and NXF_SINGULARITY_LIBRARYDIR."""
0 commit comments