12390b1b6SPatrick Williams#
22390b1b6SPatrick Williams# Copyright OpenEmbedded Contributors
32390b1b6SPatrick Williams#
42390b1b6SPatrick Williams# SPDX-License-Identifier: MIT
52390b1b6SPatrick Williams#
62390b1b6SPatrick Williams
72390b1b6SPatrick Williams##
82390b1b6SPatrick Williams## Purpose:
92390b1b6SPatrick Williams## This class is used to update the list of crates in SRC_URI
102390b1b6SPatrick Williams## by reading Cargo.lock in the source tree.
112390b1b6SPatrick Williams##
122390b1b6SPatrick Williams## See meta/recipes-devtools/python/python3-bcrypt_*.bb for an example
132390b1b6SPatrick Williams##
142390b1b6SPatrick Williams## To perform the update: bitbake -c update_crates recipe-name
152390b1b6SPatrick Williams
162390b1b6SPatrick Williamsaddtask do_update_crates after do_patch
172390b1b6SPatrick Williamsdo_update_crates[depends] = "python3-native:do_populate_sysroot"
18c5535c91SAndrew Geisslerdo_update_crates[nostamp] = "1"
19fc113eadSAndrew Geisslerdo_update_crates[doc] = "Update the recipe by reading Cargo.lock and write in ${THISDIR}/${BPN}-crates.inc"
202390b1b6SPatrick Williams
212390b1b6SPatrick Williams# The directory where to search for Cargo.lock files
222390b1b6SPatrick WilliamsCARGO_LOCK_SRC_DIR ??= "${S}"
232390b1b6SPatrick Williams
242390b1b6SPatrick Williamsdo_update_crates() {
25fc113eadSAndrew Geissler    TARGET_FILE="${THISDIR}/${BPN}-crates.inc"
26fc113eadSAndrew Geissler
272390b1b6SPatrick Williams    nativepython3 - <<EOF
282390b1b6SPatrick Williams
292390b1b6SPatrick Williamsdef get_crates(f):
302390b1b6SPatrick Williams    import tomllib
312390b1b6SPatrick Williams    c_list = '# from %s' % os.path.relpath(f, '${CARGO_LOCK_SRC_DIR}')
322390b1b6SPatrick Williams    c_list += '\nSRC_URI += " \\\'
332390b1b6SPatrick Williams    crates = tomllib.load(open(f, 'rb'))
34fc113eadSAndrew Geissler
35fc113eadSAndrew Geissler    # Build a list with crates info that have crates.io in the source
36fc113eadSAndrew Geissler    crates_candidates = list(filter(lambda c: 'crates.io' in c.get('source', ''), crates['package']))
37fc113eadSAndrew Geissler
38fc113eadSAndrew Geissler    if not crates_candidates:
39fc113eadSAndrew Geissler        raise ValueError("Unable to find any candidate crates that use crates.io")
40fc113eadSAndrew Geissler
41fc113eadSAndrew Geissler    # Update crates uri and their checksum, to avoid name clashing on the checksum
42*8e7b46e2SPatrick Williams    # we need to rename crates with name and version to have a unique key
43fc113eadSAndrew Geissler    cksum_list = ''
44fc113eadSAndrew Geissler    for c in crates_candidates:
45fc113eadSAndrew Geissler        rename = "%s-%s" % (c['name'], c['version'])
462390b1b6SPatrick Williams        c_list += '\n    crate://crates.io/%s/%s \\\' % (c['name'], c['version'])
47fc113eadSAndrew Geissler        if 'checksum' in c:
48fc113eadSAndrew Geissler            cksum_list += '\nSRC_URI[%s.sha256sum] = "%s"' % (rename, c['checksum'])
49fc113eadSAndrew Geissler
502390b1b6SPatrick Williams    c_list += '\n"\n'
51fc113eadSAndrew Geissler    c_list += cksum_list
52fc113eadSAndrew Geissler    c_list += '\n'
532390b1b6SPatrick Williams    return c_list
542390b1b6SPatrick Williams
552390b1b6SPatrick Williamsimport os
562390b1b6SPatrick Williamscrates = "# Autogenerated with 'bitbake -c update_crates ${PN}'\n\n"
57fc113eadSAndrew Geisslerfound = False
582390b1b6SPatrick Williamsfor root, dirs, files in os.walk('${CARGO_LOCK_SRC_DIR}'):
59*8e7b46e2SPatrick Williams    # ignore git and patches directories
60*8e7b46e2SPatrick Williams    if root.startswith(os.path.join('${CARGO_LOCK_SRC_DIR}', '.pc')):
61*8e7b46e2SPatrick Williams        continue
62*8e7b46e2SPatrick Williams    if root.startswith(os.path.join('${CARGO_LOCK_SRC_DIR}', '.git')):
63*8e7b46e2SPatrick Williams        continue
642390b1b6SPatrick Williams    for file in files:
652390b1b6SPatrick Williams        if file == 'Cargo.lock':
66*8e7b46e2SPatrick Williams            try:
67*8e7b46e2SPatrick Williams                cargo_lock_path = os.path.join(root, file)
682390b1b6SPatrick Williams                crates += get_crates(os.path.join(root, file))
69*8e7b46e2SPatrick Williams            except Exception as e:
70*8e7b46e2SPatrick Williams                raise ValueError("Cannot parse '%s'" % cargo_lock_path) from e
71*8e7b46e2SPatrick Williams            else:
72fc113eadSAndrew Geissler                found = True
73fc113eadSAndrew Geisslerif not found:
74*8e7b46e2SPatrick Williams    raise ValueError("Unable to find any Cargo.lock in ${CARGO_LOCK_SRC_DIR}")
75fc113eadSAndrew Geissleropen("${TARGET_FILE}", 'w').write(crates)
762390b1b6SPatrick WilliamsEOF
77fc113eadSAndrew Geissler
78fc113eadSAndrew Geissler    bbnote "Successfully update crates inside '${TARGET_FILE}'"
792390b1b6SPatrick Williams}
80