Skip to content

Commit bc75ff2

Browse files
committed
Make matching component sources in Bundle easyblock more reliable
Store where sources have been added to get the corresponding filled structure without relying on partially resolved templates.
1 parent bacc8b3 commit bc75ff2

File tree

1 file changed

+38
-47
lines changed

1 file changed

+38
-47
lines changed

easybuild/easyblocks/generic/bundle.py

Lines changed: 38 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ def __init__(self, *args, **kwargs):
9292
# (like adding component sources to top-level sources easyconfig parameter)
9393
self.cfg = self.cfg.copy()
9494

95+
self.comp_to_src_idxs = []
96+
9597
# disable templating to avoid premature resolving of template values
9698
# Note that self.cfg.update also resolves templates!
9799
with self.cfg.disable_templating():
@@ -166,6 +168,11 @@ def __init__(self, *args, **kwargs):
166168
for key in comp_specs:
167169
comp_cfg[key] = comp_specs[key]
168170

171+
# Combine all component sources into the top-level sources parameter
172+
# This allows reusing top-level source_urls and unpacking them all in the extract_step
173+
174+
# Keep track of sources for each component to restore them: (Component instance, start idx [in self.src], end idx)
175+
old_num_srcs = len(self.cfg.get('sources', resolve=False))
169176
# Don't require that all template values can be resolved at this point but still resolve them.
170177
# This is important to ensure that template values like %(name)s and %(version)s
171178
# are correctly resolved with the component name/version before values are copied over to self.cfg
@@ -195,19 +202,15 @@ def __init__(self, *args, **kwargs):
195202
comp_checksums = comp_cfg['checksums']
196203
if comp_checksums:
197204
src_cnt = len(comp_sources)
198-
199205
# add per-component checksums for sources to list of checksums
200206
self.cfg.update('checksums', comp_checksums[:src_cnt])
201207

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-
210208
self.comp_instances.append((comp_cfg, comp_cfg.easyblock(comp_cfg, logfile=self.logfile)))
209+
new_num_srcs = len(self.cfg.get('sources', resolve=False))
210+
self.comp_to_src_idxs.append((self.comp_instances[-1], old_num_srcs, new_num_srcs))
211+
# check if sanity checks are enabled for the component
212+
if self.cfg['sanity_check_all_components'] or comp_cfg['name'] in self.cfg['sanity_check_components']:
213+
self.comp_cfgs_sanity_check.append(self.comp_instances[-1])
211214

212215
self.cfg.update('checksums', checksums_patches)
213216

@@ -229,6 +232,26 @@ def check_checksums(self):
229232

230233
return checksum_issues
231234

235+
def fetch_step(self):
236+
"""Fetch sources of all extensions"""
237+
super().fetch_step()
238+
# Init src attribute as usually done by fetch_step
239+
for (_, comp), start_idx, end_idx in self.comp_to_src_idxs:
240+
comp.src = self.src[start_idx:end_idx]
241+
# need to run fetch_patches to ensure per-component patches are gathered
242+
comp.fetch_patches()
243+
244+
def prepare_step(self, *args, **kwargs):
245+
"""Init required properties for components"""
246+
super().prepare_step(*args, **kwargs)
247+
for _, comp in self.comp_instances:
248+
# correct build/install dirs
249+
comp.builddir = self.builddir
250+
comp.install_subdir, comp.installdir = self.install_subdir, self.installdir
251+
252+
# make sure we can build in parallel
253+
comp.set_parallel()
254+
232255
def patch_step(self):
233256
"""Patch step must be a no-op for bundle, since there are no top-level sources/patches."""
234257
pass
@@ -260,47 +283,15 @@ def install_step(self):
260283
(cfg['name'], cfg['version'], idx + 1, comp_cnt))
261284
self.log.info("Installing component %s v%s using easyblock %s", cfg['name'], cfg['version'], cfg.easyblock)
262285

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-
270286
# 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-
287+
# Compatibility with ECs expecting the previous behavior where src wasn't populated at this point
288+
tmp_src = comp.src
276289
comp.src = []
290+
comp.guess_start_dir()
291+
comp.src = tmp_src
277292

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']
293+
# location of first unpacked source is used to determine where to apply patch(es)
294+
comp.src[0]['finalpath'] = comp.cfg['start_dir']
304295

305296
# check if sanity checks are enabled for the component
306297
if self.cfg['sanity_check_all_components'] or comp.cfg['name'] in self.cfg['sanity_check_components']:

0 commit comments

Comments
 (0)