feat: add metadata resolve in module

This commit is contained in:
2026-08-03 16:05:08 +08:00
parent 52bd89ad6e
commit 6f1c5312e0
3 changed files with 161 additions and 33 deletions
+2 -2
View File
@@ -1,7 +1,7 @@
import logging
from . import cli
from .archiver import Archiver
from .metadata import Metadata
from .metadata import MetadataExtractor
from .renders.cmake import CMakeProperties, CMakeRender
@@ -12,7 +12,7 @@ def main() -> None:
logging.basicConfig(format='[%(levelname)s] %(message)s', level=logging.INFO)
# build metadata
metadata = Metadata(opts.manifest)
metadata = MetadataExtractor(opts.manifest)
# create distribution
+125 -7
View File
@@ -1,8 +1,11 @@
import json
import os
import subprocess
from typing import Any
from dataclasses import dataclass
from pathlib import Path
from typing import Any
import tomli
from semver import Version
# YYC MARK:
@@ -13,20 +16,134 @@ import tomli
# So we use the upstream of official `toml` package, i.e. `tomli` as our solution.
# And according to the document if `tomli`, the version starting support TOML 1.1 syntax is 2.4.0.
_TOKEN_PACKAGES: str = "packages"
_TOKEN_PACKAGE_MANIFEST_PATH: str = "manifest_path"
_TOKEN_TARGET_DIRECTORY: str = "target_directory"
@dataclass(frozen=True)
class MetadataHeader:
from_path: str
to_path: str
def __post_init__(self) -> None:
if self.from_path == "":
raise ValueError("header asset 'from' must not be empty")
@staticmethod
def from_dict(d: dict[str, Any]) -> "MetadataHeader":
from_path = d.get("from")
if from_path is None:
raise ValueError("header asset is missing required key 'from'")
if not isinstance(from_path, str):
raise TypeError("header asset 'from' must be a string")
to_path = d.get("to", "")
if not isinstance(to_path, str):
raise TypeError("header asset 'to' must be a string")
return MetadataHeader(from_path=from_path, to_path=to_path)
@dataclass(frozen=True)
class MetadataCMake:
namespace_name: str | None
target_name: str | None
@staticmethod
def from_dict(d: dict[str, Any]) -> "MetadataCMake":
namespace_name = d.get("namespace_name")
if namespace_name is not None and not isinstance(namespace_name, str):
raise TypeError("cmake 'namespace_name' must be a string or None")
target_name = d.get("target_name")
if target_name is not None and not isinstance(target_name, str):
raise TypeError("cmake 'target_name' must be a string or None")
return MetadataCMake(namespace_name=namespace_name, target_name=target_name)
@dataclass(frozen=True)
class MetadataPkgConfig:
name: str | None
description: str | None
@staticmethod
def from_dict(d: dict[str, Any]) -> "MetadataPkgConfig":
name = d.get("name")
if name is not None and not isinstance(name, str):
raise TypeError("pkgconfig 'name' must be a string or None")
description = d.get("description")
if description is not None and not isinstance(description, str):
raise TypeError("pkgconfig 'description' must be a string or None")
return MetadataPkgConfig(name=name, description=description)
@dataclass(frozen=True)
class Metadata:
min_version: Version | None
headers: tuple[MetadataHeader, ...]
cmake: MetadataCMake | None
pkgconfig: MetadataPkgConfig | None
@staticmethod
def from_dict(d: dict[str, Any]) -> "Metadata":
raw_min_version = d.get("min_version")
if raw_min_version is not None:
if not isinstance(raw_min_version, str):
raise TypeError("min_version must be a string")
try:
min_version = Version.parse(raw_min_version)
except ValueError as e:
raise ValueError(f"invalid min_version {raw_min_version!r}: {e}") from e
else:
min_version = None
raw_headers = d.get("headers")
if raw_headers is None:
raise ValueError(
"headers is required (use an empty list to distribute no headers)"
)
if not isinstance(raw_headers, list):
raise TypeError("headers must be a list")
headers_list: list[MetadataHeader] = []
for i, item in enumerate(raw_headers):
if not isinstance(item, dict):
raise TypeError(f"headers[{i}] must be a table")
headers_list.append(MetadataHeader.from_dict(item))
headers = tuple(headers_list)
raw_cmake = d.get("cmake")
if raw_cmake is not None:
if not isinstance(raw_cmake, dict):
raise TypeError("cmake must be a table")
cmake = MetadataCMake.from_dict(raw_cmake)
else:
cmake = None
raw_pkgconfig = d.get("pkgconfig")
if raw_pkgconfig is not None:
if not isinstance(raw_pkgconfig, dict):
raise TypeError("pkgconfig must be a table")
pkgconfig = MetadataPkgConfig.from_dict(raw_pkgconfig)
else:
pkgconfig = None
return Metadata(
min_version=min_version,
headers=headers,
cmake=cmake,
pkgconfig=pkgconfig,
)
class MetadataExtractor:
__cargo_toml_path: Path
__cargo_metadata: dict[str, Any]
__cargo_toml: dict[str, Any]
def __init__(self, cargo_toml: Path) -> None:
self.__cargo_toml_path = cargo_toml
self.__cargo_toml = Metadata.__extract_cargo_toml(cargo_toml)
self.__cargo_metadata = Metadata.__extract_cargo_metadata(cargo_toml)
self.__cargo_toml = MetadataExtractor.__extract_cargo_toml(cargo_toml)
self.__cargo_metadata = MetadataExtractor.__extract_cargo_metadata(cargo_toml)
def extract_omrf_metadata(self) -> Metadata:
omrf = self.__cargo_toml.get("package", {}).get("metadata", {}).get("omrf")
if not isinstance(omrf, dict):
raise ValueError("[package.metadata.omrf] is required")
return Metadata.from_dict(omrf)
@staticmethod
def __extract_cargo_toml(cargo_toml: Path) -> dict[str, Any]:
@@ -35,8 +152,9 @@ class Metadata:
@staticmethod
def __extract_cargo_metadata(cargo_toml: Path) -> dict[str, Any]:
cargo_bin = os.getenv("OMRF_PACKER_CARGO", "cargo")
cmd = [
"cargo",
cargo_bin,
"metadata",
"--no-deps",
"--format-version",