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
21*edff4923SAndrew GeisslerRECIPE_UPDATE_EXTRA_TASKS += "do_update_crates"
22*edff4923SAndrew Geissler
232390b1b6SPatrick Williams# The directory where to search for Cargo.lock files
242390b1b6SPatrick WilliamsCARGO_LOCK_SRC_DIR ??= "${S}"
252390b1b6SPatrick Williams
262390b1b6SPatrick Williamsdo_update_crates() {
27fc113eadSAndrew Geissler    TARGET_FILE="${THISDIR}/${BPN}-crates.inc"
28fc113eadSAndrew Geissler
292390b1b6SPatrick Williams    nativepython3 - <<EOF
302390b1b6SPatrick Williams
312390b1b6SPatrick Williamsdef get_crates(f):
322390b1b6SPatrick Williams    import tomllib
332390b1b6SPatrick Williams    c_list = '# from %s' % os.path.relpath(f, '${CARGO_LOCK_SRC_DIR}')
342390b1b6SPatrick Williams    c_list += '\nSRC_URI += " \\\'
352390b1b6SPatrick Williams    crates = tomllib.load(open(f, 'rb'))
36fc113eadSAndrew Geissler
37fc113eadSAndrew Geissler    # Build a list with crates info that have crates.io in the source
38fc113eadSAndrew Geissler    crates_candidates = list(filter(lambda c: 'crates.io' in c.get('source', ''), crates['package']))
39fc113eadSAndrew Geissler
40fc113eadSAndrew Geissler    if not crates_candidates:
41fc113eadSAndrew Geissler        raise ValueError("Unable to find any candidate crates that use crates.io")
42fc113eadSAndrew Geissler
43fc113eadSAndrew Geissler    # Update crates uri and their checksum, to avoid name clashing on the checksum
448e7b46e2SPatrick Williams    # we need to rename crates with name and version to have a unique key
45fc113eadSAndrew Geissler    cksum_list = ''
46fc113eadSAndrew Geissler    for c in crates_candidates:
47fc113eadSAndrew Geissler        rename = "%s-%s" % (c['name'], c['version'])
482390b1b6SPatrick Williams        c_list += '\n    crate://crates.io/%s/%s \\\' % (c['name'], c['version'])
49fc113eadSAndrew Geissler        if 'checksum' in c:
50fc113eadSAndrew Geissler            cksum_list += '\nSRC_URI[%s.sha256sum] = "%s"' % (rename, c['checksum'])
51fc113eadSAndrew Geissler
522390b1b6SPatrick Williams    c_list += '\n"\n'
53fc113eadSAndrew Geissler    c_list += cksum_list
54fc113eadSAndrew Geissler    c_list += '\n'
552390b1b6SPatrick Williams    return c_list
562390b1b6SPatrick Williams
572390b1b6SPatrick Williamsimport os
582390b1b6SPatrick Williamscrates = "# Autogenerated with 'bitbake -c update_crates ${PN}'\n\n"
59fc113eadSAndrew Geisslerfound = False
602390b1b6SPatrick Williamsfor root, dirs, files in os.walk('${CARGO_LOCK_SRC_DIR}'):
618e7b46e2SPatrick Williams    # ignore git and patches directories
628e7b46e2SPatrick Williams    if root.startswith(os.path.join('${CARGO_LOCK_SRC_DIR}', '.pc')):
638e7b46e2SPatrick Williams        continue
648e7b46e2SPatrick Williams    if root.startswith(os.path.join('${CARGO_LOCK_SRC_DIR}', '.git')):
658e7b46e2SPatrick Williams        continue
662390b1b6SPatrick Williams    for file in files:
672390b1b6SPatrick Williams        if file == 'Cargo.lock':
688e7b46e2SPatrick Williams            try:
698e7b46e2SPatrick Williams                cargo_lock_path = os.path.join(root, file)
702390b1b6SPatrick Williams                crates += get_crates(os.path.join(root, file))
718e7b46e2SPatrick Williams            except Exception as e:
728e7b46e2SPatrick Williams                raise ValueError("Cannot parse '%s'" % cargo_lock_path) from e
738e7b46e2SPatrick Williams            else:
74fc113eadSAndrew Geissler                found = True
75fc113eadSAndrew Geisslerif not found:
768e7b46e2SPatrick Williams    raise ValueError("Unable to find any Cargo.lock in ${CARGO_LOCK_SRC_DIR}")
77fc113eadSAndrew Geissleropen("${TARGET_FILE}", 'w').write(crates)
782390b1b6SPatrick WilliamsEOF
79fc113eadSAndrew Geissler
80fc113eadSAndrew Geissler    bbnote "Successfully update crates inside '${TARGET_FILE}'"
812390b1b6SPatrick Williams}
82