aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/cargo/interpreter.py
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/cargo/interpreter.py')
-rw-r--r--mesonbuild/cargo/interpreter.py530
1 files changed, 76 insertions, 454 deletions
diff --git a/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py
index af272a8..a0d4371 100644
--- a/mesonbuild/cargo/interpreter.py
+++ b/mesonbuild/cargo/interpreter.py
@@ -11,439 +11,30 @@ port will be required.
from __future__ import annotations
import dataclasses
-import importlib
-import json
import os
-import shutil
import collections
import urllib.parse
import itertools
import typing as T
-from . import builder
-from . import version
-from ..mesonlib import MesonException, Popen_safe
+from . import builder, version, cfg
+from .toml import load_toml, TomlImplementationMissing
+from .manifest import Manifest, CargoLock, fixup_meson_varname
+from ..mesonlib import MesonException, MachineChoice
from .. import coredata, mlog
from ..wrap.wrap import PackageDefinition
if T.TYPE_CHECKING:
- from types import ModuleType
-
- from typing_extensions import Protocol, Self
-
- from . import manifest
+ from . import raw
from .. import mparser
+ from .manifest import Dependency, SystemDependency
from ..environment import Environment
from ..interpreterbase import SubProject
+ from ..compilers.rust import RustCompiler
- # Copied from typeshed. Blarg that they don't expose this
- class DataclassInstance(Protocol):
- __dataclass_fields__: T.ClassVar[dict[str, dataclasses.Field[T.Any]]]
-
- _UnknownKeysT = T.TypeVar('_UnknownKeysT', manifest.FixedPackage,
- manifest.FixedDependency, manifest.FixedLibTarget,
- manifest.FixedBuildTarget)
-
-
-# tomllib is present in python 3.11, before that it is a pypi module called tomli,
-# we try to import tomllib, then tomli,
-# TODO: add a fallback to toml2json?
-tomllib: T.Optional[ModuleType] = None
-toml2json: T.Optional[str] = None
-for t in ['tomllib', 'tomli']:
- try:
- tomllib = importlib.import_module(t)
- break
- except ImportError:
- pass
-else:
- # TODO: it would be better to use an Executable here, which could be looked
- # up in the cross file or provided by a wrap. However, that will have to be
- # passed in externally, since we don't have (and I don't think we should),
- # have access to the `Environment` for that in this module.
- toml2json = shutil.which('toml2json')
-
-
-_EXTRA_KEYS_WARNING = (
- "This may (unlikely) be an error in the cargo manifest, or may be a missing "
- "implementation in Meson. If this issue can be reproduced with the latest "
- "version of Meson, please help us by opening an issue at "
- "https://github.com/mesonbuild/meson/issues. Please include the crate and "
- "version that is generating this warning if possible."
-)
-
-class TomlImplementationMissing(MesonException):
- pass
-
-
-def load_toml(filename: str) -> T.Dict[object, object]:
- if tomllib:
- with open(filename, 'rb') as f:
- raw = tomllib.load(f)
- else:
- if toml2json is None:
- raise TomlImplementationMissing('Could not find an implementation of tomllib, nor toml2json')
-
- p, out, err = Popen_safe([toml2json, filename])
- if p.returncode != 0:
- raise MesonException('toml2json failed to decode output\n', err)
-
- raw = json.loads(out)
-
- if not isinstance(raw, dict):
- raise MesonException("Cargo.toml isn't a dictionary? How did that happen?")
-
- return raw
-
-
-def fixup_meson_varname(name: str) -> str:
- """Fixup a meson variable name
-
- :param name: The name to fix
- :return: the fixed name
- """
- return name.replace('-', '_')
-
-
-# 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
-
-@T.overload
-def _fixup_raw_mappings(d: manifest.LibTarget) -> manifest.FixedLibTarget: ... # type: ignore
-
-@T.overload
-def _fixup_raw_mappings(d: manifest.Dependency) -> manifest.FixedDependency: ...
-
-def _fixup_raw_mappings(d: T.Union[manifest.BuildTarget, manifest.LibTarget, manifest.Dependency]
- ) -> T.Union[manifest.FixedBuildTarget, manifest.FixedLibTarget,
- manifest.FixedDependency]:
- """Fixup raw cargo mappings to ones more suitable for python to consume.
-
- This does the following:
- * replaces any `-` with `_`, cargo likes the former, but python dicts make
- keys with `-` in them awkward to work with
- * Convert Dependency versions from the cargo format to something meson
- understands
-
- :param d: The mapping to fix
- :return: the fixed string
- """
- raw = {fixup_meson_varname(k): v for k, v in d.items()}
- if 'version' in raw:
- assert isinstance(raw['version'], str), 'for mypy'
- raw['version'] = version.convert(raw['version'])
- return T.cast('T.Union[manifest.FixedBuildTarget, manifest.FixedLibTarget, manifest.FixedDependency]', raw)
-
-
-def _handle_unknown_keys(data: _UnknownKeysT, cls: T.Union[DataclassInstance, T.Type[DataclassInstance]],
- msg: str) -> _UnknownKeysT:
- """Remove and warn on keys that are coming from cargo, but are unknown to
- our representations.
-
- This is intended to give users the possibility of things proceeding when a
- new key is added to Cargo.toml that we don't yet handle, but to still warn
- them that things might not work.
-
- :param data: The raw data to look at
- :param cls: The Dataclass derived type that will be created
- :param msg: the header for the error message. Usually something like "In N structure".
- :return: The original data structure, but with all unknown keys removed.
- """
- unexpected = set(data) - {x.name for x in dataclasses.fields(cls)}
- if unexpected:
- mlog.warning(msg, 'has unexpected keys', '"{}".'.format(', '.join(sorted(unexpected))),
- _EXTRA_KEYS_WARNING)
- for k in unexpected:
- # Mypy and Pyright can't prove that this is okay
- del data[k] # type: ignore[misc]
- return data
-
-
-@dataclasses.dataclass
-class Package:
-
- """Representation of a Cargo Package entry, with defaults filled in."""
-
- name: str
- version: str
- description: T.Optional[str] = None
- resolver: T.Optional[str] = None
- authors: T.List[str] = dataclasses.field(default_factory=list)
- edition: manifest.EDITION = '2015'
- rust_version: T.Optional[str] = None
- documentation: T.Optional[str] = None
- readme: T.Optional[str] = None
- homepage: T.Optional[str] = None
- repository: T.Optional[str] = None
- license: T.Optional[str] = None
- license_file: T.Optional[str] = None
- keywords: T.List[str] = dataclasses.field(default_factory=list)
- categories: T.List[str] = dataclasses.field(default_factory=list)
- workspace: T.Optional[str] = None
- build: T.Optional[str] = None
- links: T.Optional[str] = None
- exclude: T.List[str] = dataclasses.field(default_factory=list)
- include: T.List[str] = dataclasses.field(default_factory=list)
- publish: bool = True
- metadata: T.Dict[str, T.Any] = dataclasses.field(default_factory=dict)
- default_run: T.Optional[str] = None
- autolib: bool = True
- autobins: bool = True
- autoexamples: bool = True
- autotests: bool = True
- autobenches: bool = True
- api: str = dataclasses.field(init=False)
-
- def __post_init__(self) -> None:
- self.api = _version_to_api(self.version)
-
- @classmethod
- def from_raw(cls, raw: manifest.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"]}')
- return cls(**pkg)
-
-@dataclasses.dataclass
-class SystemDependency:
-
- """ Representation of a Cargo system-deps entry
- https://docs.rs/system-deps/latest/system_deps
- """
-
- name: str
- version: T.List[str]
- optional: bool = False
- feature: T.Optional[str] = None
- feature_overrides: T.Dict[str, T.Dict[str, str]] = dataclasses.field(default_factory=dict)
-
- @classmethod
- def from_raw(cls, name: str, raw: T.Any) -> SystemDependency:
- if isinstance(raw, str):
- return cls(name, SystemDependency.convert_version(raw))
- name = raw.get('name', name)
- version = SystemDependency.convert_version(raw.get('version'))
- optional = raw.get('optional', False)
- feature = raw.get('feature')
- # Everything else are overrides when certain features are enabled.
- feature_overrides = {k: v for k, v in raw.items() if k not in {'name', 'version', 'optional', 'feature'}}
- return cls(name, version, optional, feature, feature_overrides)
-
- @staticmethod
- def convert_version(version: T.Optional[str]) -> T.List[str]:
- vers = version.split(',') if version is not None else []
- result: T.List[str] = []
- for v in vers:
- v = v.strip()
- if v[0] not in '><=':
- v = f'>={v}'
- result.append(v)
- return result
-
- def enabled(self, features: T.Set[str]) -> bool:
- return self.feature is None or self.feature in features
-
-@dataclasses.dataclass
-class Dependency:
-
- """Representation of a Cargo Dependency Entry."""
-
- name: dataclasses.InitVar[str]
- version: T.List[str]
- registry: T.Optional[str] = None
- git: T.Optional[str] = None
- branch: T.Optional[str] = None
- rev: T.Optional[str] = None
- path: T.Optional[str] = None
- optional: bool = False
- package: str = ''
- default_features: bool = True
- features: T.List[str] = dataclasses.field(default_factory=list)
- api: str = dataclasses.field(init=False)
-
- def __post_init__(self, name: str) -> None:
- self.package = self.package or name
- # Extract wanted API version from version constraints.
- api = set()
- for v in self.version:
- if v.startswith(('>=', '==')):
- api.add(_version_to_api(v[2:].strip()))
- elif v.startswith('='):
- api.add(_version_to_api(v[1:].strip()))
- if not api:
- self.api = '0'
- elif len(api) == 1:
- self.api = api.pop()
- else:
- raise MesonException(f'Cannot determine minimum API version from {self.version}.')
-
- @classmethod
- def from_raw(cls, name: str, raw: manifest.DependencyV) -> Dependency:
- """Create a dependency from a raw cargo dictionary"""
- if isinstance(raw, str):
- return cls(name, version.convert(raw))
- fixed = _handle_unknown_keys(_fixup_raw_mappings(raw), cls, f'Dependency entry {name}')
- return cls(name, **fixed)
-
-
-@dataclasses.dataclass
-class BuildTarget:
-
- name: str
- crate_type: T.List[manifest.CRATE_TYPE] = dataclasses.field(default_factory=lambda: ['lib'])
- path: dataclasses.InitVar[T.Optional[str]] = None
-
- # https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-test-field
- # True for lib, bin, test
- test: bool = True
-
- # https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-doctest-field
- # True for lib
- doctest: bool = False
-
- # https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-bench-field
- # True for lib, bin, benchmark
- bench: bool = True
-
- # https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-doc-field
- # True for libraries and binaries
- doc: bool = False
-
- harness: bool = True
- edition: manifest.EDITION = '2015'
- required_features: T.List[str] = dataclasses.field(default_factory=list)
- plugin: bool = False
-
- @classmethod
- def from_raw(cls, raw: manifest.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):
-
- """Representation of a Cargo Library Entry."""
-
- doctest: bool = True
- doc: bool = True
- path: str = os.path.join('src', 'lib.rs')
- proc_macro: bool = False
- crate_type: T.List[manifest.CRATE_TYPE] = dataclasses.field(default_factory=lambda: ['lib'])
- doc_scrape_examples: bool = True
-
- @classmethod
- def from_raw(cls, raw: manifest.LibTarget, fallback_name: str) -> Self: # type: ignore[override]
- 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):
-
- """Representation of a Cargo Bin Entry."""
-
- doc: bool = True
-
-
-@dataclasses.dataclass
-class Test(BuildTarget):
-
- """Representation of a Cargo Test Entry."""
-
- bench: bool = True
-
-
-@dataclasses.dataclass
-class Benchmark(BuildTarget):
-
- """Representation of a Cargo Benchmark Entry."""
-
- test: bool = True
-
-
-@dataclasses.dataclass
-class Example(BuildTarget):
-
- """Representation of a Cargo Example Entry."""
-
- crate_type: T.List[manifest.CRATE_TYPE] = dataclasses.field(default_factory=lambda: ['bin'])
-
-
-@dataclasses.dataclass
-class Manifest:
-
- """Cargo Manifest definition.
-
- Most of these values map up to the Cargo Manifest, but with default values
- if not provided.
-
- Cargo subprojects can contain what Meson wants to treat as multiple,
- interdependent, subprojects.
-
- :param path: the path within the cargo subproject.
- """
-
- package: Package
- dependencies: T.Dict[str, Dependency]
- dev_dependencies: T.Dict[str, Dependency]
- build_dependencies: T.Dict[str, Dependency]
- system_dependencies: T.Dict[str, SystemDependency] = dataclasses.field(init=False)
- lib: Library
- bin: T.List[Binary]
- test: T.List[Test]
- bench: T.List[Benchmark]
- example: T.List[Example]
- features: T.Dict[str, T.List[str]]
- target: T.Dict[str, T.Dict[str, Dependency]]
- path: str = ''
-
- def __post_init__(self) -> None:
- self.features.setdefault('default', [])
- 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:
- return Manifest(
- Package.from_raw(raw_manifest['package']),
- {k: Dependency.from_raw(k, v) for k, v in raw_manifest.get('dependencies', {}).items()},
- {k: Dependency.from_raw(k, v) for k, v in raw_manifest.get('dev-dependencies', {}).items()},
- {k: Dependency.from_raw(k, v) for k, v in raw_manifest.get('build-dependencies', {}).items()},
- Library.from_raw(raw_manifest.get('lib', {}), raw_manifest['package']['name']),
- [Binary.from_raw(b) for b in raw_manifest.get('bin', {})],
- [Test.from_raw(b) for b in raw_manifest.get('test', {})],
- [Benchmark.from_raw(b) for b in raw_manifest.get('bench', {})],
- [Example.from_raw(b) for b in raw_manifest.get('example', {})],
- raw_manifest.get('features', {}),
- {k: {k2: Dependency.from_raw(k2, v2) for k2, v2 in v.get('dependencies', {}).items()}
- for k, v in raw_manifest.get('target', {}).items()},
- path,
- )
-
-
-def _version_to_api(version: str) -> str:
- # x.y.z -> x
- # 0.x.y -> 0.x
- # 0.0.x -> 0
- vers = version.split('.')
- if int(vers[0]) != 0:
- return vers[0]
- elif len(vers) >= 2 and int(vers[1]) != 0:
- return f'0.{vers[1]}'
- return '0'
-
-
-def _dependency_name(package_name: str, api: str) -> str:
- basename = package_name[:-3] if package_name.endswith('-rs') else package_name
- return f'{basename}-{api}-rs'
+def _dependency_name(package_name: str, api: str, suffix: str = '-rs') -> str:
+ basename = package_name[:-len(suffix)] if package_name.endswith(suffix) else package_name
+ return f'{basename}-{api}{suffix}'
def _dependency_varname(package_name: str) -> str:
@@ -458,13 +49,13 @@ def _extra_deps_varname() -> str:
return 'extra_deps'
+@dataclasses.dataclass
class PackageState:
- def __init__(self, manifest: Manifest, downloaded: bool) -> None:
- self.manifest = manifest
- self.downloaded = downloaded
- self.features: T.Set[str] = set()
- self.required_deps: T.Set[str] = set()
- self.optional_deps_features: T.Dict[str, T.Set[str]] = collections.defaultdict(set)
+ manifest: Manifest
+ downloaded: bool = False
+ features: T.Set[str] = dataclasses.field(default_factory=set)
+ required_deps: T.Set[str] = dataclasses.field(default_factory=set)
+ optional_deps_features: T.Dict[str, T.Set[str]] = dataclasses.field(default_factory=lambda: collections.defaultdict(set))
@dataclasses.dataclass(frozen=True)
@@ -476,10 +67,16 @@ class PackageKey:
class Interpreter:
def __init__(self, env: Environment) -> None:
self.environment = env
+ self.host_rustc = T.cast('RustCompiler', self.environment.coredata.compilers[MachineChoice.HOST]['rust'])
# Map Cargo.toml's subdir to loaded manifest.
self.manifests: T.Dict[str, Manifest] = {}
# Map of cargo package (name + api) to its state
self.packages: T.Dict[PackageKey, PackageState] = {}
+ # Rustc's config
+ self.cfgs = self._get_cfgs()
+
+ def get_build_def_files(self) -> T.List[str]:
+ return [os.path.join(subdir, 'Cargo.toml') for subdir in self.manifests]
def interpret(self, subdir: str) -> mparser.CodeBlockNode:
manifest = self._load_manifest(subdir)
@@ -503,9 +100,7 @@ class Interpreter:
ast += self._create_dependencies(pkg, build)
ast += self._create_meson_subdir(build)
- # Libs are always auto-discovered and there's no other way to handle them,
- # which is unfortunate for reproducability
- if os.path.exists(os.path.join(self.environment.source_dir, subdir, pkg.manifest.path, pkg.manifest.lib.path)):
+ if pkg.manifest.lib:
for crate_type in pkg.manifest.lib.crate_type:
ast.extend(self._create_lib(pkg, build, crate_type))
@@ -526,6 +121,10 @@ class Interpreter:
self.environment.wrap_resolver.wraps[meson_depname].type is not None
pkg = PackageState(manifest, downloaded)
self.packages[key] = pkg
+ # Merge target specific dependencies that are enabled
+ for condition, dependencies in manifest.target.items():
+ if cfg.eval_cfg(condition, self.cfgs):
+ manifest.dependencies.update(dependencies)
# Fetch required dependencies recursively.
for depname, dep in manifest.dependencies.items():
if not dep.optional:
@@ -538,11 +137,12 @@ class Interpreter:
def _load_manifest(self, subdir: str) -> Manifest:
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)
- manifest_ = _convert_manifest(raw_manifest, subdir)
+ path = os.path.join(self.environment.source_dir, subdir)
+ filename = os.path.join(path, 'Cargo.toml')
+ toml = load_toml(filename)
+ if 'package' in toml:
+ raw_manifest = T.cast('raw.Manifest', toml)
+ manifest_ = Manifest.from_raw(raw_manifest, path)
self.manifests[subdir] = manifest_
else:
raise MesonException(f'{subdir}/Cargo.toml does not have [package] section')
@@ -599,6 +199,23 @@ class Interpreter:
else:
self._enable_feature(pkg, f)
+ def _get_cfgs(self) -> T.Dict[str, str]:
+ cfgs = self.host_rustc.get_cfgs().copy()
+ rustflags = self.environment.coredata.get_external_args(MachineChoice.HOST, 'rust')
+ rustflags_i = iter(rustflags)
+ for i in rustflags_i:
+ if i == '--cfg':
+ cfgs.append(next(rustflags_i))
+ return dict(self._split_cfg(i) for i in cfgs)
+
+ @staticmethod
+ def _split_cfg(cfg: str) -> T.Tuple[str, str]:
+ pair = cfg.split('=', maxsplit=1)
+ value = pair[1] if len(pair) > 1 else ''
+ if value and value[0] == '"':
+ value = value[1:-1]
+ return pair[0], value
+
def _create_project(self, pkg: PackageState, build: builder.Builder) -> T.List[mparser.BaseNode]:
"""Create the project() function call
@@ -608,6 +225,7 @@ class Interpreter:
"""
default_options: T.List[mparser.BaseNode] = []
default_options.append(build.string(f'rust_std={pkg.manifest.package.edition}'))
+ default_options.append(build.string(f'build.rust_std={pkg.manifest.package.edition}'))
if pkg.downloaded:
default_options.append(build.string('warning_level=0'))
@@ -643,8 +261,9 @@ class Interpreter:
return ast
def _create_system_dependency(self, name: str, dep: SystemDependency, build: builder.Builder) -> T.List[mparser.BaseNode]:
+ # TODO: handle feature_overrides
kw = {
- 'version': build.array([build.string(s) for s in dep.version]),
+ 'version': build.array([build.string(s) for s in dep.meson_version]),
'required': build.bool(not dep.optional),
}
varname = f'{fixup_meson_varname(name)}_system_dep'
@@ -671,7 +290,7 @@ class Interpreter:
def _create_dependency(self, dep: Dependency, build: builder.Builder) -> T.List[mparser.BaseNode]:
pkg = self._dep_package(dep)
kw = {
- 'version': build.array([build.string(s) for s in dep.version]),
+ 'version': build.array([build.string(s) for s in dep.meson_version]),
}
# Lookup for this dependency with the features we want in default_options kwarg.
#
@@ -747,7 +366,7 @@ class Interpreter:
build.block([build.function('subdir', [build.string('meson')])]))
]
- def _create_lib(self, pkg: PackageState, build: builder.Builder, crate_type: manifest.CRATE_TYPE) -> T.List[mparser.BaseNode]:
+ def _create_lib(self, pkg: PackageState, build: builder.Builder, crate_type: raw.CRATE_TYPE) -> T.List[mparser.BaseNode]:
dependencies: T.List[mparser.BaseNode] = []
dependency_map: T.Dict[mparser.BaseNode, mparser.BaseNode] = {}
for name in pkg.required_deps:
@@ -780,6 +399,9 @@ class Interpreter:
'rust_args': build.array(rust_args),
}
+ depname_suffix = '-rs' if crate_type in {'lib', 'rlib', 'proc-macro'} else f'-{crate_type}'
+ depname = _dependency_name(pkg.manifest.package.name, pkg.manifest.package.api, depname_suffix)
+
lib: mparser.BaseNode
if pkg.manifest.lib.proc_macro or crate_type == 'proc-macro':
lib = build.method('proc_macro', build.identifier('rust'), posargs, kwargs)
@@ -812,7 +434,8 @@ class Interpreter:
'link_with': build.identifier('lib'),
'variables': build.dict({
build.string('features'): build.string(','.join(pkg.features)),
- })
+ }),
+ 'version': build.string(pkg.manifest.package.version),
},
),
'dep'
@@ -821,7 +444,7 @@ class Interpreter:
'override_dependency',
build.identifier('meson'),
[
- build.string(_dependency_name(pkg.manifest.package.name, pkg.manifest.package.api)),
+ build.string(depname),
build.identifier('dep'),
],
),
@@ -835,24 +458,23 @@ 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))
+ toml = load_toml(filename)
except TomlImplementationMissing as e:
mlog.warning('Failed to load Cargo.lock:', str(e), fatal=False)
return wraps
- for package in cargolock['package']:
- name = package['name']
- version = package['version']
- subp_name = _dependency_name(name, _version_to_api(version))
- source = package.get('source')
- if source is None:
+ raw_cargolock = T.cast('raw.CargoLock', toml)
+ cargolock = CargoLock.from_raw(raw_cargolock)
+ for package in cargolock.package:
+ subp_name = _dependency_name(package.name, version.api(package.version))
+ if package.source is None:
# This is project's package, or one of its workspace members.
pass
- elif source == 'registry+https://github.com/rust-lang/crates.io-index':
- checksum = package.get('checksum')
+ elif package.source == 'registry+https://github.com/rust-lang/crates.io-index':
+ checksum = package.checksum
if checksum is None:
- checksum = cargolock['metadata'][f'checksum {name} {version} ({source})']
- url = f'https://crates.io/api/v1/crates/{name}/{version}/download'
- directory = f'{name}-{version}'
+ checksum = cargolock.metadata[f'checksum {package.name} {package.version} ({package.source})']
+ url = f'https://crates.io/api/v1/crates/{package.name}/{package.version}/download'
+ directory = f'{package.name}-{package.version}'
wraps.append(PackageDefinition.from_values(subp_name, subproject_dir, 'file', {
'directory': directory,
'source_url': url,
@@ -860,18 +482,18 @@ def load_wraps(source_dir: str, subproject_dir: str) -> T.List[PackageDefinition
'source_hash': checksum,
'method': 'cargo',
}))
- elif source.startswith('git+'):
- parts = urllib.parse.urlparse(source[4:])
+ elif package.source.startswith('git+'):
+ parts = urllib.parse.urlparse(package.source[4:])
query = urllib.parse.parse_qs(parts.query)
branch = query['branch'][0] if 'branch' in query else ''
revision = parts.fragment or branch
url = urllib.parse.urlunparse(parts._replace(params='', query='', fragment=''))
wraps.append(PackageDefinition.from_values(subp_name, subproject_dir, 'git', {
- 'directory': name,
+ 'directory': package.name,
'url': url,
'revision': revision,
'method': 'cargo',
}))
else:
- mlog.warning(f'Unsupported source URL in {filename}: {source}')
+ mlog.warning(f'Unsupported source URL in {filename}: {package.source}')
return wraps