From: Stefan Herbrechtsmeier <stefan.herbrechtsme...@weidmueller.com>

Add a vendor module for cargo to resolve dependencies and populate
vendor directories from a Cargo.lock file.

Signed-off-by: Stefan Herbrechtsmeier <stefan.herbrechtsme...@weidmueller.com>
---

 meta/lib/oe/vendor/cargo.py | 121 ++++++++++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)
 create mode 100644 meta/lib/oe/vendor/cargo.py

diff --git a/meta/lib/oe/vendor/cargo.py b/meta/lib/oe/vendor/cargo.py
new file mode 100644
index 0000000000..4d0a0034f3
--- /dev/null
+++ b/meta/lib/oe/vendor/cargo.py
@@ -0,0 +1,121 @@
+# Copyright (C) 2024-2025 Weidmueller Interface GmbH & Co. KG
+# Stefan Herbrechtsmeier <stefan.herbrechtsme...@weidmueller.com>
+#
+# SPDX-License-Identifier: MIT
+#
+import json
+import os
+import tomllib
+import bb
+import oe.vendor
+from bb.fetch2 import URI
+from . import ResolveError
+
+VENDOR_TYPE = "cargo"
+
+VENDOR_DIR = "vendor/cargo"
+
+def escape(path):
+    return re.sub(r'([A-Z])', lambda m: '!' + m.group(1).lower(), path)
+
+def determine_subdir(name, version):
+    return f"{name}-{version}"
+
+def determine_uri_path(path, name, version):
+    path = path.rstrip("/")
+    return f"{path}/api/v1/crates/{name}/{version}/download"
+
+def determine_downloadfilename(name, version):
+    filename = f"{name}-{version}.crate"
+    return oe.vendor.determine_downloadfilename(VENDOR_TYPE, filename)
+
+def extend_uri(uri, name, version, subdir, checksum_name=None,
+               checksum_value=None):
+    uri.path = determine_uri_path(uri.path, name, version)
+    params = uri.params
+    params["subdir"] = subdir
+    params["downloadfilename"] = determine_downloadfilename(name, version)
+    if checksum_name and checksum_value:
+        params[checksum_name] = checksum_value
+
+def determine_src_uri(registry, name, version, subdir):
+    uri = URI(registry)
+    extend_uri(uri, name, version, subdir)
+    return str(uri)
+
+def parse_lock_file(lock_file, function):
+    try:
+        with open(lock_file, "rb") as f:
+            crates = tomllib.load(f)
+    except Exception as e:
+        raise ResolveError(f"Invalid file: {str(e)}", lock_file)
+
+    for data in crates.get("package", []):
+        if "source" not in data:
+            continue
+
+        function(data)
+
+def resolve_src_uris(lock_file, registry, base_subdir, vendor_subdir):
+    src_uris = []
+
+    def resolve_src_uri(data):
+        name =  data.get('name')
+        version = data.get('version')
+        source = data.get("source")
+
+        if source.startswith("registry"):
+            checksum_name = "sha256sum"
+            checksum_value = data.get('checksum')
+            uri = URI(source[9:])
+            if (source[9:] == "https://github.com/rust-lang/crates.io-index";):
+                uri = URI(registry)
+                params = uri.params
+                params["name"] = name
+                params["version"] = version
+                params["type"] = VENDOR_TYPE
+                subdir = os.path.join(base_subdir, vendor_subdir)
+                extend_uri(uri, name, version, subdir, checksum_name,
+                           checksum_value)
+            else:
+                raise ResolveError(f"Unsupported cargo registry: {source}",
+                                   lock_file)
+
+        elif source.startswith("git"):
+            repository, _, revision = source.partition("#")
+            uri = URI(repository)
+            params = uri.params
+            scheme, _, protocol = uri.scheme.partition("+")
+            if protocol:
+                params["protocol"] = protocol
+                uri.scheme = scheme
+            params["nobranch"] = "1"
+            subdir = determine_subdir(name, version)
+            params["subdir"] = os.path.join(base_subdir, vendor_subdir, subdir)
+            params["rev"] = revision
+        else:
+            raise ResolveError(f"Unsupported dependency: {name}", lock_file)
+
+        src_uris.append(str(uri))
+
+    parse_lock_file(lock_file, resolve_src_uri)
+
+    return src_uris
+
+def populate_vendor(lock_file, rootdir):
+    def populate_checksum(data):
+        name =  data.get('name')
+        version = data.get('version')
+        source = data.get("source")
+        chechsum = data.get('checksum')
+
+        if source.startswith("registry"):
+            subdir = determine_subdir(name, version)
+            filepath = os.path.join(rootdir, subdir, ".cargo-checksum.json")
+            with open(filepath, "w") as f:
+                json.dump({
+                    "files": {},
+                    "package": chechsum
+                }, f)
+
+    parse_lock_file(lock_file, populate_checksum)
-- 
2.39.5

-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#211132): 
https://lists.openembedded.org/g/openembedded-core/message/211132
Mute This Topic: https://lists.openembedded.org/mt/111123523/21656
Group Owner: openembedded-core+ow...@lists.openembedded.org
Unsubscribe: https://lists.openembedded.org/g/openembedded-core/unsub 
[arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to