@@ -44,7 +44,13 @@ def fixup_meson_varname(name: str) -> str:
44
44
return name .replace ('-' , '_' )
45
45
46
46
47
- def _depv_to_dep (depv : raw .DependencyV ) -> raw .Dependency :
47
+ @T .overload
48
+ def _depv_to_dep (depv : raw .FromWorkspace ) -> raw .FromWorkspace : ...
49
+
50
+ @T .overload
51
+ def _depv_to_dep (depv : raw .DependencyV ) -> raw .Dependency : ...
52
+
53
+ def _depv_to_dep (depv : T .Union [raw .FromWorkspace , raw .DependencyV ]) -> T .Union [raw .FromWorkspace , raw .Dependency ]:
48
54
return {'version' : depv } if isinstance (depv , str ) else depv
49
55
50
56
@@ -85,6 +91,51 @@ def _raw_to_dataclass(raw: T.Mapping[str, object], cls: T.Type[_DI],
85
91
return cls (** new_dict )
86
92
87
93
94
+ @T .overload
95
+ def _inherit_from_workspace (raw : raw .Package ,
96
+ raw_from_workspace : T .Optional [T .Mapping [str , object ]],
97
+ msg : str ,
98
+ ** kwargs : T .Callable [[T .Any , T .Any ], object ]) -> raw .Package : ...
99
+
100
+ @T .overload
101
+ def _inherit_from_workspace (raw : T .Union [raw .FromWorkspace , raw .Dependency ],
102
+ raw_from_workspace : T .Optional [T .Mapping [str , object ]],
103
+ msg : str ,
104
+ ** kwargs : T .Callable [[T .Any , T .Any ], object ]) -> raw .Dependency : ...
105
+
106
+ def _inherit_from_workspace (raw_ : T .Union [raw .FromWorkspace , raw .Package , raw .Dependency ], # type: ignore[misc]
107
+ raw_from_workspace : T .Optional [T .Mapping [str , object ]],
108
+ msg : str ,
109
+ ** kwargs : T .Callable [[T .Any , T .Any ], object ]) -> T .Mapping [str , object ]:
110
+ # allow accesses by non-literal key below
111
+ raw = T .cast ('T.Mapping[str, object]' , raw_ )
112
+
113
+ if not raw_from_workspace :
114
+ if raw .get ('workspace' , False ) or \
115
+ any (isinstance (v , dict ) and v .get ('workspace' , False ) for v in raw ):
116
+ raise MesonException (f'Cargo.toml file requests { msg } from workspace' )
117
+
118
+ return raw
119
+
120
+ result = {k : v for k , v in raw .items () if k != 'workspace' }
121
+ for k , v in raw .items ():
122
+ if isinstance (v , dict ) and v .get ('workspace' , False ):
123
+ if k in raw_from_workspace :
124
+ result [k ] = raw_from_workspace [k ]
125
+ if k in kwargs :
126
+ result [k ] = kwargs [k ](v , result [k ])
127
+ else :
128
+ del result [k ]
129
+
130
+ if raw .get ('workspace' , False ):
131
+ for k , v in raw_from_workspace .items ():
132
+ if k not in result or k in kwargs :
133
+ if k in kwargs :
134
+ v = kwargs [k ](raw .get (k ), v )
135
+ result [k ] = v
136
+ return result
137
+
138
+
88
139
@dataclasses .dataclass
89
140
class Package :
90
141
@@ -124,7 +175,12 @@ def api(self) -> str:
124
175
return version .api (self .version )
125
176
126
177
@classmethod
127
- def from_raw (cls , raw_pkg : raw .Package ) -> Self :
178
+ def from_raw (cls , raw_pkg : raw .Package , workspace : T .Optional [Workspace ] = None ) -> Self :
179
+ raw_ws_pkg = None
180
+ if workspace is not None :
181
+ raw_ws_pkg = workspace .package
182
+
183
+ raw_pkg = _inherit_from_workspace (raw_pkg , raw_ws_pkg , f'Package entry { raw_pkg ["name" ]} ' )
128
184
return _raw_to_dataclass (raw_pkg , cls , f'Package entry { raw_pkg ["name" ]} ' )
129
185
130
186
@dataclasses .dataclass
@@ -204,15 +260,24 @@ def api(self) -> str:
204
260
raise MesonException (f'Cannot determine minimum API version from { self .version } .' )
205
261
206
262
@classmethod
207
- def from_raw_dict (cls , name : str , raw_dep : raw .Dependency ) -> Dependency :
263
+ def from_raw_dict (cls , name : str , raw_dep : T .Union [raw .FromWorkspace , raw .Dependency ], member_path : str = '' , raw_ws_dep : T .Optional [raw .Dependency ] = None ) -> Dependency :
264
+ raw_dep = _inherit_from_workspace (raw_dep , raw_ws_dep ,
265
+ f'Dependency entry { name } ' ,
266
+ path = lambda pkg_path , ws_path : os .path .relpath (ws_path , member_path ),
267
+ features = lambda pkg_path , ws_path : (pkg_path or []) + (ws_path or []))
208
268
raw_dep .setdefault ('package' , name )
209
269
return _raw_to_dataclass (raw_dep , cls , f'Dependency entry { name } ' )
210
270
211
271
@classmethod
212
- def from_raw (cls , name : str , raw_depv : raw .DependencyV ) -> Dependency :
272
+ def from_raw (cls , name : str , raw_depv : T . Union [ raw .FromWorkspace , raw . DependencyV ], member_path : str = '' , workspace : T . Optional [ Workspace ] = None ) -> Dependency :
213
273
"""Create a dependency from a raw cargo dictionary or string"""
274
+ raw_ws_dep : T .Optional [raw .Dependency ] = None
275
+ if workspace is not None :
276
+ raw_ws_depv = workspace .dependencies .get (name , {})
277
+ raw_ws_dep = _depv_to_dep (raw_ws_depv )
278
+
214
279
raw_dep = _depv_to_dep (raw_depv )
215
- return cls .from_raw_dict (name , raw_dep )
280
+ return cls .from_raw_dict (name , raw_dep , member_path , raw_ws_dep )
216
281
217
282
218
283
@dataclasses .dataclass
@@ -362,29 +427,56 @@ def system_dependencies(self) -> T.Dict[str, SystemDependency]:
362
427
return {k : SystemDependency .from_raw (k , v ) for k , v in self .package .metadata .get ('system-deps' , {}).items ()}
363
428
364
429
@classmethod
365
- def from_raw (cls , raw : raw .Manifest , path : str = '' ) -> Self :
430
+ def from_raw (cls , raw : raw .Manifest , path : str = '' , workspace : T . Optional [ Workspace ] = None , member_path : str = '' ) -> Self :
366
431
# Libs are always auto-discovered and there's no other way to handle them,
367
432
# which is unfortunate for reproducability
368
- pkg = Package .from_raw (raw ['package' ])
433
+ pkg = Package .from_raw (raw ['package' ], workspace )
369
434
if pkg .autolib and 'lib' not in raw and \
370
435
os .path .exists (os .path .join (path , 'src/lib.rs' )):
371
436
raw ['lib' ] = {}
372
437
fixed = _raw_to_dataclass (raw , cls , f'Cargo.toml package { raw ["package" ]["name" ]} ' ,
373
438
package = lambda x : pkg ,
374
- dependencies = lambda x : {k : Dependency .from_raw (k , v ) for k , v in x .items ()},
375
- dev_dependencies = lambda x : {k : Dependency .from_raw (k , v ) for k , v in x .items ()},
376
- build_dependencies = lambda x : {k : Dependency .from_raw (k , v ) for k , v in x .items ()},
439
+ dependencies = lambda x : {k : Dependency .from_raw (k , v , member_path , workspace ) for k , v in x .items ()},
440
+ dev_dependencies = lambda x : {k : Dependency .from_raw (k , v , member_path , workspace ) for k , v in x .items ()},
441
+ build_dependencies = lambda x : {k : Dependency .from_raw (k , v , member_path , workspace ) for k , v in x .items ()},
377
442
lib = lambda x : Library .from_raw (x , raw ['package' ]['name' ]),
378
443
bin = lambda x : [Binary .from_raw (b ) for b in x ],
379
444
test = lambda x : [Test .from_raw (b ) for b in x ],
380
445
bench = lambda x : [Benchmark .from_raw (b ) for b in x ],
381
446
example = lambda x : [Example .from_raw (b ) for b in x ],
382
- target = lambda x : {k : {k2 : Dependency .from_raw (k2 , v2 ) for k2 , v2 in v .get ('dependencies' , {}).items ()}
447
+ target = lambda x : {k : {k2 : Dependency .from_raw (k2 , v2 , member_path , workspace ) for k2 , v2 in v .get ('dependencies' , {}).items ()}
383
448
for k , v in x .items ()})
384
449
fixed .path = path
385
450
return fixed
386
451
387
452
453
+ @dataclasses .dataclass
454
+ class Workspace :
455
+
456
+ """Cargo Workspace definition.
457
+ """
458
+
459
+ resolver : str = dataclasses .field (default_factory = lambda : '2' )
460
+ members : T .List [str ] = dataclasses .field (default_factory = list )
461
+ exclude : T .List [str ] = dataclasses .field (default_factory = list )
462
+ default_members : T .List [str ] = dataclasses .field (default_factory = list )
463
+
464
+ # inheritable settings are kept in raw format, for use with _inherit_from_workspace
465
+ package : T .Optional [raw .Package ] = None
466
+ dependencies : T .Dict [str , raw .Dependency ] = dataclasses .field (default_factory = dict )
467
+ lints : T .Dict [str , T .Any ] = dataclasses .field (default_factory = dict )
468
+ metadata : T .Dict [str , T .Any ] = dataclasses .field (default_factory = dict )
469
+
470
+ # A workspace can also have a root package.
471
+ root_package : T .Optional [Manifest ] = dataclasses .field (init = False )
472
+
473
+ @classmethod
474
+ def from_raw (cls , raw : raw .VirtualManifest ) -> Workspace :
475
+ ws_raw = raw ['workspace' ]
476
+ fixed = _raw_to_dataclass (ws_raw , cls , 'Workspace' )
477
+ return fixed
478
+
479
+
388
480
@dataclasses .dataclass
389
481
class CargoLockPackage :
390
482
0 commit comments