Skip to content

Commit 6dedcb8

Browse files
committed
WIP: cargo: Add workspace support
1 parent a3934d2 commit 6dedcb8

File tree

14 files changed

+327
-51
lines changed

14 files changed

+327
-51
lines changed

mesonbuild/cargo/interpreter.py

Lines changed: 183 additions & 43 deletions
Large diffs are not rendered by default.

mesonbuild/cargo/manifest.py

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ def fixup_meson_varname(name: str) -> str:
4343
return name.replace('-', '_')
4444

4545

46-
def _raw_to_dataclass(raw: T.Dict[str, T.Any], cls: T.Type[_DI], msg: str, **kwargs: T.Callable[[T.Any], object]) -> _DI:
46+
def _raw_to_dataclass(raw: T.Dict[str, T.Any], cls: T.Type[_DI], msg: str, raw_from_workspace: T.Optional[T.Dict[str, T.Any]] = None, **kwargs: T.Callable[[T.Any], object]) -> _DI:
4747
"""Convert and validate raw cargo mappings to a Python dataclass.
4848
49+
* Inherit values from the workspace.
4950
* Replaces any `-` with `_` in the keys.
5051
* Remove and warn on keys that are coming from cargo, but are unknown to
5152
our representations.
@@ -59,7 +60,13 @@ def _raw_to_dataclass(raw: T.Dict[str, T.Any], cls: T.Type[_DI], msg: str, **kwa
5960
unexpected: T.Set[str] = set()
6061
known = {x.name for x in dataclasses.fields(cls)}
6162
result: T.Dict[str, T.Any] = {}
63+
if raw.get('workspace', False):
64+
del raw['workspace']
65+
for k, v in raw_from_workspace.items():
66+
raw.setdefault(k, v)
6267
for k, v in raw.items():
68+
if isinstance(v, dict) and v.get('workspace', False):
69+
v = raw_from_workspace[k]
6370
k = fixup_meson_varname(k)
6471
if k not in known:
6572
unexpected.add(k)
@@ -113,8 +120,9 @@ def api(self) -> str:
113120
return version.api(self.version)
114121

115122
@classmethod
116-
def from_raw(cls, raw: T.Dict[str, T.Any]) -> Self:
117-
return _raw_to_dataclass(raw, cls, f'Package entry {raw["name"]}')
123+
def from_raw(cls, raw: T.Dict[str, T.Any], workspace: T.Optional[Workspace] = None) -> Self:
124+
raw_from_workspace = workspace.package if workspace else None
125+
return _raw_to_dataclass(raw, cls, f'Package entry {raw["name"]}', raw_from_workspace)
118126

119127
@dataclasses.dataclass
120128
class SystemDependency:
@@ -195,12 +203,20 @@ def meson_version(self) -> T.List[str]:
195203
return version.convert(self.version) if self.version else []
196204

197205
@classmethod
198-
def from_raw(cls, name: str, raw: T.Union[T.Dict[str, T.Any], str]) -> Dependency:
206+
def from_raw(cls, name: str, raw: T.Union[T.Dict[str, T.Any], str], workspace: T.Optional[Workspace] = None, member_path: str = '') -> Dependency:
199207
"""Create a dependency from a raw cargo dictionary"""
200208
if isinstance(raw, str):
201209
return cls(name, raw)
210+
raw_from_workspace = workspace.dependencies.get(name) if workspace else None
211+
if raw_from_workspace is not None:
212+
name = raw_from_workspace.get('package', name)
213+
if 'features' in raw:
214+
raw['features'] += raw_from_workspace.get('features', [])
215+
if 'path' in raw_from_workspace:
216+
raw_from_workspace = raw_from_workspace.copy()
217+
raw_from_workspace['path'] = os.path.relpath(raw_from_workspace['path'], member_path)
202218
raw.setdefault('package', name)
203-
return _raw_to_dataclass(raw, cls, f'Dependency entry {name}')
219+
return _raw_to_dataclass(raw, cls, f'Dependency entry {name}', raw_from_workspace)
204220

205221

206222
@dataclasses.dataclass
@@ -322,13 +338,15 @@ def system_dependencies(self) -> T.Dict[str, SystemDependency]:
322338
return {k: SystemDependency.from_raw(k, v) for k, v in self.package.metadata.get('system-deps', {}).items()}
323339

324340
@classmethod
325-
def from_raw(cls, raw: T.Dict[str, T.Any]) -> Manifest:
341+
def from_raw(cls, raw: T.Dict[str, T.Any], workspace: T.Optional[Workspace] = None, member_path: str = '') -> Manifest:
326342
name = raw['package']['name']
327343
raw.setdefault('lib', {'name': name})
344+
328345
def dependencies_from_raw(x: T.Dict[str, T.Any]) -> T.Dict[str, Dependency]:
329-
return {k: Dependency.from_raw(k, v) for k, v in x.items()}
346+
return {k: Dependency.from_raw(k, v, workspace, member_path) for k, v in x.items()}
347+
330348
return _raw_to_dataclass(raw, cls, f'Manifest {name}',
331-
package=lambda x: Package.from_raw(x),
349+
package=lambda x: Package.from_raw(x, workspace),
332350
dependencies=dependencies_from_raw,
333351
dev_dependencies=dependencies_from_raw,
334352
build_dependencies=dependencies_from_raw,
@@ -340,6 +358,46 @@ def dependencies_from_raw(x: T.Dict[str, T.Any]) -> T.Dict[str, Dependency]:
340358
target=lambda x: {k: dependencies_from_raw(v.get('dependencies', {})) for k, v in x.items()})
341359

342360

361+
@dataclasses.dataclass
362+
class Workspace:
363+
364+
"""Cargo Workspace definition.
365+
"""
366+
367+
resolver: str = '2'
368+
members: T.List[str] = dataclasses.field(default_factory=list)
369+
exclude: T.List[str] = dataclasses.field(default_factory=list)
370+
default_members: T.List[str] = dataclasses.field(default_factory=list)
371+
package: T.Dict[str, T.Any] = dataclasses.field(default_factory=dict)
372+
dependencies: T.Dict[str, T.Dict[str, T.Any]] = dataclasses.field(default_factory=dict)
373+
lints: T.Dict[str, T.Any] = dataclasses.field(default_factory=dict)
374+
metadata: T.Dict[str, T.Any] = dataclasses.field(default_factory=dict)
375+
376+
root_package: T.Optional[Manifest] = None
377+
378+
@classmethod
379+
def from_raw(cls, raw: T.Dict[str, T.Any]) -> Workspace:
380+
extra_members: T.List[str] = []
381+
382+
def dependency_from_raw(x: T.Dict[str, T.Any]) -> T.Dict[str, T.Any]:
383+
if isinstance(x, str):
384+
return {'version': x}
385+
path = x.get('path')
386+
if path:
387+
extra_members.append(path)
388+
return x
389+
390+
ws = _raw_to_dataclass(raw['workspace'], cls, 'Workspace',
391+
dependencies=lambda x: {k: dependency_from_raw(v) for k, v in x.items()})
392+
ws.members.extend(extra_members)
393+
394+
if 'package' in raw:
395+
del raw['workspace']
396+
ws.root_package = Manifest.from_raw(raw, ws, member_path='.')
397+
398+
return ws
399+
400+
343401
@dataclasses.dataclass
344402
class CargoLockPackage:
345403

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
project('cargo workspace', 'c', 'rust')
2+
3+
foo_rs = dependency('foo-1-rs')
4+
e = executable('test-foo-1-rs', 'test_foo_1.rs',
5+
dependencies: [foo_rs],
6+
)
7+
test('test-foo-1-rs', e)
8+
9+
foo_cdylib = dependency('foo-1-cdylib')
10+
e = executable('test-foo-1-cdylib', 'test_foo_1.c',
11+
dependencies: [foo_cdylib],
12+
)
13+
test('test-foo-1-rs', e)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[wrap-file]
2+
method=cargo
3+
4+
[provide]
5+
dependency_names=foo-1-rs
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[workspace]
2+
members = [
3+
"src/foo",
4+
"src/member1"
5+
]
6+
default-members = ["src/foo"]
7+
8+
[workspace.package]
9+
version = "1.0"
10+
11+
[workspace.dependencies]
12+
member1 = { path="./src/member1" }
13+
member2 = { path="src/member2", features = ["f1"] }
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "foo"
3+
version.workspace = true
4+
5+
[lib]
6+
crate-type = ["lib", "cdylib"]
7+
8+
[dependencies]
9+
m1 = { path="../member1", package="member1" }
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extern crate m1;
2+
3+
#[no_mangle]
4+
pub extern "C" fn foo() -> i32 {
5+
m1::member1() + 1
6+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
pub fn foo() -> i32 {
2+
member1::member1() + 1
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[package]
2+
name = "member1"
3+
version.workspace = true
4+
5+
[dependencies]
6+
member2 = { workspace = true, features=["f2"] }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extern crate member2;
2+
3+
pub fn member1() -> i32 {
4+
member2::member2() + 1
5+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[package]
2+
name = "member2"
3+
version.workspace = true
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#[cfg(feature = "f1")]
2+
#[cfg(feature = "f2")]
3+
pub fn member2() -> i32 {
4+
1
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extern int foo(void);
2+
3+
int main(void) {
4+
return foo() == 3 ? 0 : 1;
5+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extern crate foo;
2+
3+
pub fn main() {
4+
assert!(foo::foo() == 3);
5+
}

0 commit comments

Comments
 (0)