summaryrefslogtreecommitdiff
path: root/mesonbuild
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2025-06-03 12:00:05 +0200
committerDylan Baker <dylan@pnwbakers.com>2025-08-01 07:55:49 -0700
commit824f6fccf35dc46f17cff9da0639d23614ccba64 (patch)
tree17d6d3a7af6742d166e2e1165a67b7410868c082 /mesonbuild
parent939cfa6dd16743a296d772136cc338e2148ee7e5 (diff)
downloadmeson-824f6fccf35dc46f17cff9da0639d23614ccba64.tar.gz
cargo: move TypedDicts for Cargo.toml to "raw" module
Fix a few issues: * Cargo.lock's version is an int * Different BuildTargets have different types for the argument of from_raw Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'mesonbuild')
-rw-r--r--mesonbuild/cargo/interpreter.py46
-rw-r--r--mesonbuild/cargo/manifest.py177
-rw-r--r--mesonbuild/cargo/raw.py179
3 files changed, 208 insertions, 194 deletions
diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py
index b6d0817cd..e3918ba7f 100644
--- a/mesonbuild/cargo/interpreter.py
+++ b/mesonbuild/cargo/interpreter.py
@@ -26,7 +26,7 @@ from ..wrap.wrap import PackageDefinition
if T.TYPE_CHECKING:
from typing_extensions import Protocol, Self
- from . import manifest
+ from . import manifest, raw
from .. import mparser
from ..environment import Environment
from ..interpreterbase import SubProject
@@ -40,6 +40,8 @@ if T.TYPE_CHECKING:
manifest.FixedDependency, manifest.FixedLibTarget,
manifest.FixedBuildTarget)
+_R = T.TypeVar('_R', bound='raw._BaseBuildTarget')
+
_EXTRA_KEYS_WARNING = (
"This may (unlikely) be an error in the cargo manifest, or may be a missing "
@@ -61,15 +63,15 @@ def fixup_meson_varname(name: str) -> str:
# Pylance can figure out that these do not, in fact, overlap, but mypy can't
@T.overload
-def _fixup_raw_mappings(d: manifest.BuildTarget) -> manifest.FixedBuildTarget: ... # type: ignore
+def _fixup_raw_mappings(d: raw.BuildTarget) -> manifest.FixedBuildTarget: ... # type: ignore
@T.overload
-def _fixup_raw_mappings(d: manifest.LibTarget) -> manifest.FixedLibTarget: ... # type: ignore
+def _fixup_raw_mappings(d: raw.LibTarget) -> manifest.FixedLibTarget: ... # type: ignore
@T.overload
-def _fixup_raw_mappings(d: manifest.Dependency) -> manifest.FixedDependency: ...
+def _fixup_raw_mappings(d: raw.Dependency) -> manifest.FixedDependency: ...
-def _fixup_raw_mappings(d: T.Union[manifest.BuildTarget, manifest.LibTarget, manifest.Dependency]
+def _fixup_raw_mappings(d: T.Union[raw.BuildTarget, raw.LibTarget, raw.Dependency]
) -> T.Union[manifest.FixedBuildTarget, manifest.FixedLibTarget,
manifest.FixedDependency]:
"""Fixup raw cargo mappings to ones more suitable for python to consume.
@@ -153,7 +155,7 @@ class Package:
self.api = _version_to_api(self.version)
@classmethod
- def from_raw(cls, raw: manifest.Package) -> Self:
+ def from_raw(cls, raw: raw.Package) -> Self:
pkg = T.cast('manifest.FixedPackage',
{fixup_meson_varname(k): v for k, v in raw.items()})
pkg = _handle_unknown_keys(pkg, cls, f'Package entry {pkg["name"]}')
@@ -233,7 +235,7 @@ class Dependency:
raise MesonException(f'Cannot determine minimum API version from {self.version}.')
@classmethod
- def from_raw(cls, name: str, raw: manifest.DependencyV) -> Dependency:
+ def from_raw(cls, name: str, raw: raw.DependencyV) -> Dependency:
"""Create a dependency from a raw cargo dictionary"""
if isinstance(raw, str):
return cls(name, version.convert(raw))
@@ -242,7 +244,7 @@ class Dependency:
@dataclasses.dataclass
-class BuildTarget:
+class BuildTarget(T.Generic[_R]):
name: str
crate_type: T.List[manifest.CRATE_TYPE] = dataclasses.field(default_factory=lambda: ['lib'])
@@ -270,13 +272,13 @@ class BuildTarget:
plugin: bool = False
@classmethod
- def from_raw(cls, raw: manifest.BuildTarget) -> Self:
+ def from_raw(cls, raw: raw.BuildTarget) -> Self:
name = raw.get('name', '<anonymous>')
build = _handle_unknown_keys(_fixup_raw_mappings(raw), cls, f'Binary entry {name}')
return cls(**build)
@dataclasses.dataclass
-class Library(BuildTarget):
+class Library(BuildTarget['raw.LibTarget']):
"""Representation of a Cargo Library Entry."""
@@ -288,20 +290,20 @@ class Library(BuildTarget):
doc_scrape_examples: bool = True
@classmethod
- def from_raw(cls, raw: manifest.LibTarget, fallback_name: str) -> Self: # type: ignore[override]
+ def from_raw(cls, raw: raw.LibTarget, fallback_name: str) -> Self: # type: ignore[override]
+ if 'name' not in raw:
+ raw['name'] = fallback_name
fixed = _fixup_raw_mappings(raw)
# We need to set the name field if it's not set manually, including if
# other fields are set in the lib section
- if 'name' not in fixed:
- fixed['name'] = fallback_name
fixed = _handle_unknown_keys(fixed, cls, f'Library entry {fixed["name"]}')
return cls(**fixed)
@dataclasses.dataclass
-class Binary(BuildTarget):
+class Binary(BuildTarget['raw.BuildTarget']):
"""Representation of a Cargo Bin Entry."""
@@ -309,7 +311,7 @@ class Binary(BuildTarget):
@dataclasses.dataclass
-class Test(BuildTarget):
+class Test(BuildTarget['raw.BuildTarget']):
"""Representation of a Cargo Test Entry."""
@@ -317,7 +319,7 @@ class Test(BuildTarget):
@dataclasses.dataclass
-class Benchmark(BuildTarget):
+class Benchmark(BuildTarget['raw.BuildTarget']):
"""Representation of a Cargo Benchmark Entry."""
@@ -325,7 +327,7 @@ class Benchmark(BuildTarget):
@dataclasses.dataclass
-class Example(BuildTarget):
+class Example(BuildTarget['raw.BuildTarget']):
"""Representation of a Cargo Example Entry."""
@@ -365,7 +367,7 @@ class Manifest:
self.system_dependencies = {k: SystemDependency.from_raw(k, v) for k, v in self.package.metadata.get('system-deps', {}).items()}
-def _convert_manifest(raw_manifest: manifest.Manifest, subdir: str, path: str = '') -> Manifest:
+def _convert_manifest(raw_manifest: raw.Manifest, subdir: str, path: str = '') -> Manifest:
return Manifest(
Package.from_raw(raw_manifest['package']),
{k: Dependency.from_raw(k, v) for k, v in raw_manifest.get('dependencies', {}).items()},
@@ -503,9 +505,9 @@ class Interpreter:
manifest_ = self.manifests.get(subdir)
if not manifest_:
filename = os.path.join(self.environment.source_dir, subdir, 'Cargo.toml')
- raw = load_toml(filename)
- if 'package' in raw:
- raw_manifest = T.cast('manifest.Manifest', raw)
+ toml = load_toml(filename)
+ if 'package' in toml:
+ raw_manifest = T.cast('raw.Manifest', toml)
manifest_ = _convert_manifest(raw_manifest, subdir)
self.manifests[subdir] = manifest_
else:
@@ -821,7 +823,7 @@ def load_wraps(source_dir: str, subproject_dir: str) -> T.List[PackageDefinition
filename = os.path.join(source_dir, 'Cargo.lock')
if os.path.exists(filename):
try:
- cargolock = T.cast('manifest.CargoLock', load_toml(filename))
+ cargolock = T.cast('raw.CargoLock', load_toml(filename))
except TomlImplementationMissing as e:
mlog.warning('Failed to load Cargo.lock:', str(e), fatal=False)
return wraps
diff --git a/mesonbuild/cargo/manifest.py b/mesonbuild/cargo/manifest.py
index d95df7f4f..753979608 100644
--- a/mesonbuild/cargo/manifest.py
+++ b/mesonbuild/cargo/manifest.py
@@ -6,42 +6,9 @@
from __future__ import annotations
import typing as T
-from typing_extensions import Literal, TypedDict, Required
-
-EDITION = Literal['2015', '2018', '2021']
-CRATE_TYPE = Literal['bin', 'lib', 'dylib', 'staticlib', 'cdylib', 'rlib', 'proc-macro']
-
-Package = TypedDict(
- 'Package',
- {
- 'name': Required[str],
- 'version': Required[str],
- 'authors': T.List[str],
- 'edition': EDITION,
- 'rust-version': str,
- 'description': str,
- 'readme': str,
- 'license': str,
- 'license-file': str,
- 'keywords': T.List[str],
- 'categories': T.List[str],
- 'workspace': str,
- 'build': str,
- 'links': str,
- 'include': T.List[str],
- 'exclude': T.List[str],
- 'publish': bool,
- 'metadata': T.Dict[str, T.Dict[str, str]],
- 'default-run': str,
- 'autolib': bool,
- 'autobins': bool,
- 'autoexamples': bool,
- 'autotests': bool,
- 'autobenches': bool,
- },
- total=False,
-)
-"""A description of the Package Dictionary."""
+from typing_extensions import TypedDict, Required
+
+from .raw import EDITION, CRATE_TYPE
class FixedPackage(TypedDict, total=False):
@@ -73,32 +40,6 @@ class FixedPackage(TypedDict, total=False):
autobenches: bool
-class Badge(TypedDict):
-
- """An entry in the badge section."""
-
- status: Literal['actively-developed', 'passively-developed', 'as-is', 'experimental', 'deprecated', 'none']
-
-
-Dependency = TypedDict(
- 'Dependency',
- {
- 'version': str,
- 'registry': str,
- 'git': str,
- 'branch': str,
- 'rev': str,
- 'path': str,
- 'optional': bool,
- 'package': str,
- 'default-features': bool,
- 'features': T.List[str],
- },
- total=False,
-)
-"""An entry in the *dependencies sections."""
-
-
class FixedDependency(TypedDict, total=False):
"""An entry in the *dependencies sections, fixed up."""
@@ -115,38 +56,6 @@ class FixedDependency(TypedDict, total=False):
features: T.List[str]
-DependencyV = T.Union[Dependency, str]
-"""A Dependency entry, either a string or a Dependency Dict."""
-
-
-_BaseBuildTarget = TypedDict(
- '_BaseBuildTarget',
- {
- 'path': str,
- 'test': bool,
- 'doctest': bool,
- 'bench': bool,
- 'doc': bool,
- 'plugin': bool,
- 'proc-macro': bool,
- 'harness': bool,
- 'edition': EDITION,
- 'crate-type': T.List[CRATE_TYPE],
- 'required-features': T.List[str],
- },
- total=False,
-)
-
-
-class BuildTarget(_BaseBuildTarget, total=False):
-
- name: Required[str]
-
-class LibTarget(_BaseBuildTarget, total=False):
-
- name: str
-
-
class _BaseFixedBuildTarget(TypedDict, total=False):
path: str
test: bool
@@ -162,86 +71,10 @@ class _BaseFixedBuildTarget(TypedDict, total=False):
class FixedBuildTarget(_BaseFixedBuildTarget, total=False):
- name: str
-
-class FixedLibTarget(_BaseFixedBuildTarget, total=False):
-
name: Required[str]
- proc_macro: bool
-
-class Target(TypedDict):
- """Target entry in the Manifest File."""
-
- dependencies: T.Dict[str, DependencyV]
-
-
-class Workspace(TypedDict):
-
- """The representation of a workspace.
-
- In a vritual manifest the :attribute:`members` is always present, but in a
- project manifest, an empty workspace may be provided, in which case the
- workspace is implicitly filled in by values from the path based dependencies.
-
- the :attribute:`exclude` is always optional
- """
-
- members: T.List[str]
- exclude: T.List[str]
-
-
-Manifest = TypedDict(
- 'Manifest',
- {
- 'package': Required[Package],
- 'badges': T.Dict[str, Badge],
- 'dependencies': T.Dict[str, DependencyV],
- 'dev-dependencies': T.Dict[str, DependencyV],
- 'build-dependencies': T.Dict[str, DependencyV],
- 'lib': LibTarget,
- 'bin': T.List[BuildTarget],
- 'test': T.List[BuildTarget],
- 'bench': T.List[BuildTarget],
- 'example': T.List[BuildTarget],
- 'features': T.Dict[str, T.List[str]],
- 'target': T.Dict[str, Target],
- 'workspace': Workspace,
-
- # TODO: patch?
- # TODO: replace?
- },
- total=False,
-)
-"""The Cargo Manifest format."""
-
-
-class VirtualManifest(TypedDict):
-
- """The Representation of a virtual manifest.
-
- Cargo allows a root manifest that contains only a workspace, this is called
- a virtual manifest. This doesn't really map 1:1 with any meson concept,
- except perhaps the proposed "meta project".
- """
-
- workspace: Workspace
-
-class CargoLockPackage(TypedDict, total=False):
-
- """A description of a package in the Cargo.lock file format."""
+class FixedLibTarget(_BaseFixedBuildTarget, total=False):
name: str
- version: str
- source: str
- checksum: str
-
-
-class CargoLock(TypedDict, total=False):
-
- """A description of the Cargo.lock file format."""
-
- version: str
- package: T.List[CargoLockPackage]
- metadata: T.Dict[str, str]
+ proc_macro: bool
diff --git a/mesonbuild/cargo/raw.py b/mesonbuild/cargo/raw.py
new file mode 100644
index 000000000..f20fc0ef7
--- /dev/null
+++ b/mesonbuild/cargo/raw.py
@@ -0,0 +1,179 @@
+# SPDX-License-Identifier: Apache-2.0
+# Copyright © 2022-2024 Intel Corporation
+
+"""Type definitions for cargo manifest files."""
+
+from __future__ import annotations
+import typing as T
+
+from typing_extensions import Literal, TypedDict, Required
+
+EDITION = Literal['2015', '2018', '2021']
+CRATE_TYPE = Literal['bin', 'lib', 'dylib', 'staticlib', 'cdylib', 'rlib', 'proc-macro']
+
+Package = TypedDict(
+ 'Package',
+ {
+ 'name': Required[str],
+ 'version': Required[str],
+ 'authors': T.List[str],
+ 'edition': EDITION,
+ 'rust-version': str,
+ 'description': str,
+ 'readme': str,
+ 'license': str,
+ 'license-file': str,
+ 'keywords': T.List[str],
+ 'categories': T.List[str],
+ 'workspace': str,
+ 'build': str,
+ 'links': str,
+ 'include': T.List[str],
+ 'exclude': T.List[str],
+ 'publish': bool,
+ 'metadata': T.Dict[str, T.Dict[str, str]],
+ 'default-run': str,
+ 'autolib': bool,
+ 'autobins': bool,
+ 'autoexamples': bool,
+ 'autotests': bool,
+ 'autobenches': bool,
+ },
+ total=False,
+)
+"""A description of the Package Dictionary."""
+
+class Badge(TypedDict):
+
+ """An entry in the badge section."""
+
+ status: Literal['actively-developed', 'passively-developed', 'as-is', 'experimental', 'deprecated', 'none']
+
+
+Dependency = TypedDict(
+ 'Dependency',
+ {
+ 'version': str,
+ 'registry': str,
+ 'git': str,
+ 'branch': str,
+ 'rev': str,
+ 'path': str,
+ 'optional': bool,
+ 'package': str,
+ 'default-features': bool,
+ 'features': T.List[str],
+ },
+ total=False,
+)
+"""An entry in the *dependencies sections."""
+
+
+DependencyV = T.Union[Dependency, str]
+"""A Dependency entry, either a string or a Dependency Dict."""
+
+
+_BaseBuildTarget = TypedDict(
+ '_BaseBuildTarget',
+ {
+ 'path': str,
+ 'test': bool,
+ 'doctest': bool,
+ 'bench': bool,
+ 'doc': bool,
+ 'plugin': bool,
+ 'proc-macro': bool,
+ 'harness': bool,
+ 'edition': EDITION,
+ 'crate-type': T.List[CRATE_TYPE],
+ 'required-features': T.List[str],
+ },
+ total=False,
+)
+
+
+class BuildTarget(_BaseBuildTarget, total=False):
+
+ name: Required[str]
+
+
+class LibTarget(_BaseBuildTarget, total=False):
+
+ name: str
+
+
+class Target(TypedDict):
+
+ """Target entry in the Manifest File."""
+
+ dependencies: T.Dict[str, DependencyV]
+
+
+class Workspace(TypedDict):
+
+ """The representation of a workspace.
+
+ In a vritual manifest the :attribute:`members` is always present, but in a
+ project manifest, an empty workspace may be provided, in which case the
+ workspace is implicitly filled in by values from the path based dependencies.
+
+ the :attribute:`exclude` is always optional
+ """
+
+ members: T.List[str]
+ exclude: T.List[str]
+
+
+Manifest = TypedDict(
+ 'Manifest',
+ {
+ 'package': Required[Package],
+ 'badges': T.Dict[str, Badge],
+ 'dependencies': T.Dict[str, DependencyV],
+ 'dev-dependencies': T.Dict[str, DependencyV],
+ 'build-dependencies': T.Dict[str, DependencyV],
+ 'lib': LibTarget,
+ 'bin': T.List[BuildTarget],
+ 'test': T.List[BuildTarget],
+ 'bench': T.List[BuildTarget],
+ 'example': T.List[BuildTarget],
+ 'features': T.Dict[str, T.List[str]],
+ 'target': T.Dict[str, Target],
+ 'workspace': Workspace,
+
+ # TODO: patch?
+ # TODO: replace?
+ },
+ total=False,
+)
+"""The Cargo Manifest format."""
+
+
+class VirtualManifest(TypedDict):
+
+ """The Representation of a virtual manifest.
+
+ Cargo allows a root manifest that contains only a workspace, this is called
+ a virtual manifest. This doesn't really map 1:1 with any meson concept,
+ except perhaps the proposed "meta project".
+ """
+
+ workspace: Workspace
+
+class CargoLockPackage(TypedDict, total=False):
+
+ """A description of a package in the Cargo.lock file format."""
+
+ name: str
+ version: str
+ source: str
+ checksum: str
+
+
+class CargoLock(TypedDict, total=False):
+
+ """A description of the Cargo.lock file format."""
+
+ version: int
+ package: T.List[CargoLockPackage]
+ metadata: T.Dict[str, str]