Skip to content

Commit 1622322

Browse files
committed
add support for injecting checksums for cargo crates
Even though the `crates` are recognized as sources for `Cargo` easyconfigs the checksums are not written, at least when neither 'source_urls', 'sources' nor 'patches' are present. Handle `crates` like `sources` and add test-
1 parent 8ff6ba0 commit 1622322

File tree

4 files changed

+123
-8
lines changed

4 files changed

+123
-8
lines changed

easybuild/framework/easyblock.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4751,8 +4751,8 @@ def make_checksum_lines(checksums, indent_level):
47514751
if app.src:
47524752
placeholder = '# PLACEHOLDER FOR SOURCES/PATCHES WITH CHECKSUMS'
47534753

4754-
# grab raw lines for source_urls, sources, patches
4755-
keys = ['patches', 'source_urls', 'sources']
4754+
# grab raw lines for the following params
4755+
keys = ['source_urls', 'sources', 'crates', 'patches']
47564756
raw = {}
47574757
for key in keys:
47584758
regex = re.compile(r'^(%s(?:.|\n)*?\])\s*$' % key, re.M)
@@ -4763,13 +4763,11 @@ def make_checksum_lines(checksums, indent_level):
47634763

47644764
_log.debug("Raw lines for %s easyconfig parameters: %s", '/'.join(keys), raw)
47654765

4766-
# inject combination of source_urls/sources/patches/checksums into easyconfig
4767-
# by replacing first occurence of placeholder that was put in place
4768-
sources_raw = raw.get('sources', '')
4769-
source_urls_raw = raw.get('source_urls', '')
4770-
patches_raw = raw.get('patches', '')
4766+
# inject combination of the grabbed lines and the checksums into the easyconfig
4767+
# by replacing first the occurence of the placeholder that was put in place
4768+
raw_text = ''.join(raw.get(key, '') for key in keys)
47714769
regex = re.compile(placeholder + '\n', re.M)
4772-
ectxt = regex.sub(source_urls_raw + sources_raw + patches_raw + checksums_txt + '\n', ectxt, count=1)
4770+
ectxt = regex.sub(raw_text + checksums_txt + '\n', ectxt, count=1)
47734771

47744772
# get rid of potential remaining placeholders
47754773
ectxt = regex.sub('', ectxt)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
name = 'toy'
2+
version = '0.0'
3+
versionsuffix = '-cargo'
4+
5+
easyblock = 'Cargo'
6+
7+
homepage = 'https://easybuilders.github.io/easybuild'
8+
description = "Toy C program, 100% toy."
9+
10+
toolchain = SYSTEM
11+
12+
crates = [
13+
('toy', 'extra.txt'),
14+
('toy', '0.0_gzip.patch.gz'),
15+
]
16+
17+
moduleclass = 'tools'

test/framework/options.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6285,6 +6285,55 @@ def test_inject_checksums(self):
62856285
]
62866286
self.assertEqual(ext_opts['checksums'], expected_checksums)
62876287

6288+
# Also works for cargo crates
6289+
cargo_ec = os.path.join(topdir, 'easyconfigs', 'test_ecs', 't', 'toy', 'toy-0.0-cargo.eb')
6290+
copy_file(cargo_ec, test_ec)
6291+
stdout, stderr = self._run_mock_eb([test_ec, '--inject-checksums'], raise_error=True, strip=True)
6292+
self.assertIn("injecting sha256 checksums in", stdout)
6293+
self.assertEqual(stderr, '')
6294+
expected_checksums = [
6295+
{'toy-extra.txt': '4196b56771140d8e2468fb77f0240bc48ddbf5dabafe0713d612df7fafb1e458'},
6296+
{'toy-0.0_gzip.patch.gz': 'c5c51dd4b00fd490f8f8226f5fa609c30b66bda7ef6d3391ab2631508f3d5e41'},
6297+
]
6298+
patterns = [r"^== injecting sha256 checksums for sources & patches in test\.eb\.\.\.$"]
6299+
patterns.extend(r"^== \* %s: %s$" % next(iter(entry.items())) for entry in expected_checksums)
6300+
for pattern in patterns:
6301+
regex = re.compile(pattern, re.M)
6302+
self.assertTrue(regex.search(stdout), "Pattern '%s' found in: %s" % (regex.pattern, stdout))
6303+
6304+
ec = EasyConfigParser(test_ec).get_config_dict()
6305+
self.assertEqual(ec['checksums'], expected_checksums)
6306+
6307+
# crates also work with sources and patches (unusual use case)
6308+
copy_file(cargo_ec, test_ec)
6309+
write_file(test_ec, textwrap.dedent("""
6310+
sources = [SOURCE_TAR_GZ]
6311+
patches = [
6312+
'toy-0.0_fix-silly-typo-in-printf-statement.patch',
6313+
]
6314+
"""), append=True)
6315+
stdout, stderr = self._run_mock_eb([test_ec, '--inject-checksums'], raise_error=True, strip=True)
6316+
self.assertIn("injecting sha256 checksums in", stdout)
6317+
self.assertEqual(stderr, '')
6318+
expected_checksums = [
6319+
# Main source
6320+
{'toy-0.0.tar.gz': '44332000aa33b99ad1e00cbd1a7da769220d74647060a10e807b916d73ea27bc'},
6321+
# Specified as "crates"
6322+
{'toy-extra.txt': '4196b56771140d8e2468fb77f0240bc48ddbf5dabafe0713d612df7fafb1e458'},
6323+
{'toy-0.0_gzip.patch.gz': 'c5c51dd4b00fd490f8f8226f5fa609c30b66bda7ef6d3391ab2631508f3d5e41'},
6324+
# Patch
6325+
{'toy-0.0_fix-silly-typo-in-printf-statement.patch':
6326+
'81a3accc894592152f81814fbf133d39afad52885ab52c25018722c7bda92487'},
6327+
]
6328+
patterns = [r"^== injecting sha256 checksums for sources & patches in test\.eb\.\.\.$"]
6329+
patterns.extend(r"^== \* %s: %s$" % next(iter(entry.items())) for entry in expected_checksums)
6330+
for pattern in patterns:
6331+
regex = re.compile(pattern, re.M)
6332+
self.assertTrue(regex.search(stdout), "Pattern '%s' found in: %s" % (regex.pattern, stdout))
6333+
6334+
ec = EasyConfigParser(test_ec).get_config_dict()
6335+
self.assertEqual(ec['checksums'], expected_checksums)
6336+
62886337
# passing easyconfig filename as argument to --inject-checksums results in error being reported,
62896338
# because it's not a valid type of checksum
62906339
args = ['--inject-checksums', test_ec]
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
##
2+
# Copyright 2009-2024 Ghent University
3+
#
4+
# This file is part of EasyBuild,
5+
# originally created by the HPC team of Ghent University (http://ugent.be/hpc/en),
6+
# with support of Ghent University (http://ugent.be/hpc),
7+
# the Flemish Supercomputer Centre (VSC) (https://www.vscentrum.be),
8+
# Flemish Research Foundation (FWO) (http://www.fwo.be/en)
9+
# and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en).
10+
#
11+
# https://github.com/easybuilders/easybuild
12+
#
13+
# EasyBuild is free software: you can redistribute it and/or modify
14+
# it under the terms of the GNU General Public License as published by
15+
# the Free Software Foundation v2.
16+
#
17+
# EasyBuild is distributed in the hope that it will be useful,
18+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
# GNU General Public License for more details.
21+
#
22+
# You should have received a copy of the GNU General Public License
23+
# along with EasyBuild. If not, see <http://www.gnu.org/licenses/>.
24+
##
25+
from easybuild.framework.easyblock import EasyBlock
26+
from easybuild.framework.easyconfig import CUSTOM
27+
28+
29+
class Cargo(EasyBlock):
30+
"""Generic support for building/installing cargo crates."""
31+
32+
@staticmethod
33+
def extra_options():
34+
"""Custom easyconfig parameters for bar."""
35+
extra_vars = {
36+
'crates': [[], "List of (crate, version, [repo, rev]) tuples to use", CUSTOM],
37+
}
38+
return EasyBlock.extra_options(extra_vars)
39+
40+
def __init__(self, *args, **kwargs):
41+
"""Constructor for Cargo easyblock."""
42+
super(Cargo, self).__init__(*args, **kwargs)
43+
44+
# Populate sources from "crates" list of tuples
45+
# For simplicity just assume (name,version.ext) tuples
46+
sources = ['%s-%s' % crate_info for crate_info in self.cfg['crates']]
47+
48+
# copy EasyConfig instance before we make changes to it
49+
self.cfg = self.cfg.copy()
50+
51+
self.cfg.update('sources', sources)

0 commit comments

Comments
 (0)