10
10
from typing import Callable , Dict , List , MutableMapping , Optional , Tuple , cast
11
11
12
12
from schema_salad .sourceline import SourceLine
13
+ from spython .main import Client
14
+ from spython .main .parse .parsers .docker import DockerParser
15
+ from spython .main .parse .writers .singularity import SingularityWriter
13
16
14
17
from .builder import Builder
15
18
from .context import RuntimeContext
@@ -140,6 +143,7 @@ def __init__(
140
143
def get_image (
141
144
dockerRequirement : Dict [str , str ],
142
145
pull_image : bool ,
146
+ tmp_outdir_prefix : str ,
143
147
force_pull : bool = False ,
144
148
) -> bool :
145
149
"""
@@ -162,7 +166,35 @@ def get_image(
162
166
elif is_version_2_6 () and "SINGULARITY_PULLFOLDER" in os .environ :
163
167
cache_folder = os .environ ["SINGULARITY_PULLFOLDER" ]
164
168
165
- if "dockerImageId" not in dockerRequirement and "dockerPull" in dockerRequirement :
169
+ if "dockerFile" in dockerRequirement :
170
+ if cache_folder is None : # if environment variables were not set
171
+ cache_folder = create_tmp_dir (tmp_outdir_prefix )
172
+
173
+ absolute_path = os .path .abspath (cache_folder )
174
+ dockerfile_path = os .path .join (absolute_path , "Dockerfile" )
175
+ singularityfile_path = dockerfile_path + ".def"
176
+ # if you do not set APPTAINER_TMPDIR will crash
177
+ # WARNING: 'nodev' mount option set on /tmp, it could be a
178
+ # source of failure during build process
179
+ # FATAL: Unable to create build: 'noexec' mount option set on
180
+ # /tmp, temporary root filesystem won't be usable at this location
181
+ with open (dockerfile_path , "w" ) as dfile :
182
+ dfile .write (dockerRequirement ["dockerFile" ])
183
+
184
+ singularityfile = SingularityWriter (DockerParser (dockerfile_path ).parse ()).convert ()
185
+ with open (singularityfile_path , "w" ) as file :
186
+ file .write (singularityfile )
187
+
188
+ os .environ ["APPTAINER_TMPDIR" ] = absolute_path
189
+ singularity_options = ["--fakeroot" ] if not shutil .which ("proot" ) else []
190
+ Client .build (
191
+ recipe = singularityfile_path ,
192
+ build_folder = absolute_path ,
193
+ sudo = False ,
194
+ options = singularity_options ,
195
+ )
196
+ found = True
197
+ elif "dockerImageId" not in dockerRequirement and "dockerPull" in dockerRequirement :
166
198
match = re .search (pattern = r"([a-z]*://)" , string = dockerRequirement ["dockerPull" ])
167
199
img_name = _normalize_image_id (dockerRequirement ["dockerPull" ])
168
200
candidates .append (img_name )
@@ -243,13 +275,6 @@ def get_image(
243
275
check_call (cmd , stdout = sys .stderr ) # nosec
244
276
found = True
245
277
246
- elif "dockerFile" in dockerRequirement :
247
- raise SourceLine (
248
- dockerRequirement , "dockerFile" , WorkflowException , debug
249
- ).makeError (
250
- "dockerFile is not currently supported when using the "
251
- "Singularity runtime for Docker containers."
252
- )
253
278
elif "dockerLoad" in dockerRequirement :
254
279
if is_version_3_1_or_newer ():
255
280
if "dockerImageId" in dockerRequirement :
@@ -298,7 +323,7 @@ def get_from_requirements(
298
323
if not bool (shutil .which ("singularity" )):
299
324
raise WorkflowException ("singularity executable is not available" )
300
325
301
- if not self .get_image (cast (Dict [str , str ], r ), pull_image , force_pull ):
326
+ if not self .get_image (cast (Dict [str , str ], r ), pull_image , tmp_outdir_prefix , force_pull ):
302
327
raise WorkflowException ("Container image {} not found" .format (r ["dockerImageId" ]))
303
328
304
329
return os .path .abspath (cast (str , r ["dockerImageId" ]))
0 commit comments