@@ -92,6 +92,10 @@ def __init__(self, *args, **kwargs):
92
92
# (like adding component sources to top-level sources easyconfig parameter)
93
93
self .cfg = self .cfg .copy ()
94
94
95
+ # Keep track of sources for each component to restore them:
96
+ # (Component instance, start idx [in self.src], end idx)
97
+ self .comp_to_src_idxs = []
98
+
95
99
# disable templating to avoid premature resolving of template values
96
100
# Note that self.cfg.update also resolves templates!
97
101
with self .cfg .disable_templating ():
@@ -166,6 +170,10 @@ def __init__(self, *args, **kwargs):
166
170
for key in comp_specs :
167
171
comp_cfg [key ] = comp_specs [key ]
168
172
173
+ # Combine all component sources into the top-level sources parameter
174
+ # This allows reusing top-level source_urls and unpacking them all in the extract_step
175
+
176
+ old_num_srcs = len (self .cfg .get ('sources' , resolve = False ))
169
177
# Don't require that all template values can be resolved at this point but still resolve them.
170
178
# This is important to ensure that template values like %(name)s and %(version)s
171
179
# are correctly resolved with the component name/version before values are copied over to self.cfg
@@ -195,19 +203,15 @@ def __init__(self, *args, **kwargs):
195
203
comp_checksums = comp_cfg ['checksums' ]
196
204
if comp_checksums :
197
205
src_cnt = len (comp_sources )
198
-
199
206
# add per-component checksums for sources to list of checksums
200
207
self .cfg .update ('checksums' , comp_checksums [:src_cnt ])
201
208
202
- # add per-component checksums for patches to list of checksums for patches
203
- checksums_patches .extend (comp_checksums [src_cnt :])
204
-
205
- with comp_cfg .allow_unresolved_templates ():
206
- comp_patches = comp_cfg ['patches' ]
207
- if comp_patches :
208
- self .cfg .update ('patches' , comp_patches )
209
-
210
209
self .comp_instances .append ((comp_cfg , comp_cfg .easyblock (comp_cfg , logfile = self .logfile )))
210
+ new_num_srcs = len (self .cfg .get ('sources' , resolve = False ))
211
+ self .comp_to_src_idxs .append ((self .comp_instances [- 1 ], old_num_srcs , new_num_srcs ))
212
+ # check if sanity checks are enabled for the component
213
+ if self .cfg ['sanity_check_all_components' ] or comp_cfg ['name' ] in self .cfg ['sanity_check_components' ]:
214
+ self .comp_cfgs_sanity_check .append (self .comp_instances [- 1 ])
211
215
212
216
self .cfg .update ('checksums' , checksums_patches )
213
217
@@ -229,6 +233,26 @@ def check_checksums(self):
229
233
230
234
return checksum_issues
231
235
236
+ def fetch_step (self ):
237
+ """Fetch sources of all extensions"""
238
+ super ().fetch_step ()
239
+ # Init src attribute as usually done by fetch_step
240
+ for (_ , comp ), start_idx , end_idx in self .comp_to_src_idxs :
241
+ comp .src = self .src [start_idx :end_idx ]
242
+ # need to run fetch_patches to ensure per-component patches are gathered
243
+ comp .fetch_patches ()
244
+
245
+ def prepare_step (self , * args , ** kwargs ):
246
+ """Init required properties for components"""
247
+ super ().prepare_step (* args , ** kwargs )
248
+ for _ , comp in self .comp_instances :
249
+ # correct build/install dirs
250
+ comp .builddir = self .builddir
251
+ comp .install_subdir , comp .installdir = self .install_subdir , self .installdir
252
+
253
+ # make sure we can build in parallel
254
+ comp .set_parallel ()
255
+
232
256
def patch_step (self ):
233
257
"""Patch step must be a no-op for bundle, since there are no top-level sources/patches."""
234
258
pass
@@ -260,47 +284,15 @@ def install_step(self):
260
284
(cfg ['name' ], cfg ['version' ], idx + 1 , comp_cnt ))
261
285
self .log .info ("Installing component %s v%s using easyblock %s" , cfg ['name' ], cfg ['version' ], cfg .easyblock )
262
286
263
- # correct build/install dirs
264
- comp .builddir = self .builddir
265
- comp .install_subdir , comp .installdir = self .install_subdir , self .installdir
266
-
267
- # make sure we can build in parallel
268
- comp .set_parallel ()
269
-
270
287
# figure out correct start directory
271
- comp .guess_start_dir ()
272
-
273
- # need to run fetch_patches to ensure per-component patches are applied
274
- comp .fetch_patches ()
275
-
288
+ # Compatibility with ECs expecting the previous behavior where src wasn't populated at this point
289
+ tmp_src = comp .src
276
290
comp .src = []
291
+ comp .guess_start_dir ()
292
+ comp .src = tmp_src
277
293
278
- # find matching entries in self.src for this component
279
- with comp .cfg .allow_unresolved_templates ():
280
- comp_sources = comp .cfg ['sources' ]
281
- for source in comp_sources :
282
- if isinstance (source , str ):
283
- comp_src_fn = source
284
- elif isinstance (source , dict ):
285
- if 'filename' in source :
286
- comp_src_fn = source ['filename' ]
287
- else :
288
- raise EasyBuildError ("Encountered source file specified as dict without 'filename': %s" , source )
289
- else :
290
- raise EasyBuildError ("Specification of unknown type for source file: %s" , source )
291
-
292
- found = False
293
- for src in self .src :
294
- if src ['name' ] == comp_src_fn :
295
- self .log .info ("Found spec for source %s for component %s: %s" , comp_src_fn , comp .name , src )
296
- comp .src .append (src )
297
- found = True
298
- break
299
- if not found :
300
- raise EasyBuildError ("Failed to find spec for source %s for component %s" , comp_src_fn , comp .name )
301
-
302
- # location of first unpacked source is used to determine where to apply patch(es)
303
- comp .src [- 1 ]['finalpath' ] = comp .cfg ['start_dir' ]
294
+ # location of first unpacked source is used to determine where to apply patch(es)
295
+ comp .src [0 ]['finalpath' ] = comp .cfg ['start_dir' ]
304
296
305
297
# check if sanity checks are enabled for the component
306
298
if self .cfg ['sanity_check_all_components' ] or comp .cfg ['name' ] in self .cfg ['sanity_check_components' ]:
0 commit comments