11use std:: fmt:: Write ;
22use std:: path:: Path ;
33
4- use anyhow:: Result ;
4+ use anyhow:: { Context , Result } ;
55use owo_colors:: OwoColorize ;
66
77use uv_cache:: { Cache , Refresh } ;
88use uv_client:: BaseClientBuilder ;
99use uv_configuration:: { Concurrency , DependencyGroupsWithDefaults , DryRun } ;
1010use uv_preview:: { Preview , PreviewFeature } ;
1111use uv_python:: { PythonDownloads , PythonPreference , PythonRequest } ;
12- use uv_resolver:: { Lock , Metadata } ;
12+ use uv_resolver:: Metadata ;
1313use uv_settings:: PythonInstallMirrors ;
1414use uv_warnings:: warn_user;
15- use uv_workspace:: { DiscoveryOptions , VirtualProject , Workspace , WorkspaceCache } ;
15+ use uv_workspace:: { DiscoveryOptions , VirtualProject , WorkspaceCache } ;
1616
1717use crate :: commands:: pip:: loggers:: DefaultResolveLogger ;
1818use crate :: commands:: project:: lock:: { LockMode , LockOperation } ;
1919use crate :: commands:: project:: lock_target:: LockTarget ;
20- use crate :: commands:: project:: { ProjectError , ProjectInterpreter , UniversalState , WorkspacePython } ;
20+ use crate :: commands:: project:: {
21+ ProjectEnvironment , ProjectError , ProjectInterpreter , UniversalState , WorkspacePython ,
22+ } ;
2123use crate :: commands:: { ExitStatus , diagnostics} ;
2224use crate :: printer:: Printer ;
2325use crate :: settings:: { FrozenSource , LockCheck , ResolverSettings } ;
2426
27+ use super :: module_owners:: collect_module_owners;
28+
2529/// Display metadata about the workspace.
2630pub ( crate ) async fn metadata (
2731 project_dir : & Path ,
2832 lock_check : LockCheck ,
2933 frozen : Option < FrozenSource > ,
3034 dry_run : DryRun ,
3135 refresh : Refresh ,
36+ module_owners : bool ,
3237 python : Option < String > ,
3338 install_mirrors : PythonInstallMirrors ,
3439 settings : ResolverSettings ,
@@ -54,38 +59,37 @@ pub(crate) async fn metadata(
5459 . await ?;
5560 let target = LockTarget :: Workspace ( virtual_project. workspace ( ) ) ;
5661
62+ // Don't enable any groups' requires-python for interpreter discovery.
63+ let groups = DependencyGroupsWithDefaults :: none ( ) ;
64+ let workspace_python = WorkspacePython :: from_request (
65+ python. as_deref ( ) . map ( PythonRequest :: parse) ,
66+ Some ( virtual_project. workspace ( ) ) ,
67+ & groups,
68+ project_dir,
69+ no_config,
70+ )
71+ . await ?;
72+ let interpreter = ProjectInterpreter :: discover (
73+ virtual_project. workspace ( ) ,
74+ & groups,
75+ workspace_python,
76+ & client_builder,
77+ python_preference,
78+ python_downloads,
79+ & install_mirrors,
80+ false ,
81+ Some ( false ) ,
82+ cache,
83+ printer,
84+ preview,
85+ )
86+ . await ?
87+ . into_interpreter ( ) ;
88+
5789 // Determine the lock mode.
58- let interpreter;
5990 let mode = if let Some ( frozen_source) = frozen {
6091 LockMode :: Frozen ( frozen_source. into ( ) )
6192 } else {
62- // Don't enable any groups' requires-python for interpreter discovery
63- let groups = DependencyGroupsWithDefaults :: none ( ) ;
64- let workspace_python = WorkspacePython :: from_request (
65- python. as_deref ( ) . map ( PythonRequest :: parse) ,
66- Some ( virtual_project. workspace ( ) ) ,
67- & groups,
68- project_dir,
69- no_config,
70- )
71- . await ?;
72- interpreter = ProjectInterpreter :: discover (
73- virtual_project. workspace ( ) ,
74- & groups,
75- workspace_python,
76- & client_builder,
77- python_preference,
78- python_downloads,
79- & install_mirrors,
80- false ,
81- Some ( false ) ,
82- cache,
83- printer,
84- preview,
85- )
86- . await ?
87- . into_interpreter ( ) ;
88-
8993 if let LockCheck :: Enabled ( lock_check) = lock_check {
9094 LockMode :: Locked ( & interpreter, lock_check)
9195 } else if dry_run. enabled ( ) {
@@ -117,7 +121,46 @@ pub(crate) async fn metadata(
117121 )
118122 . await
119123 {
120- Ok ( lock) => print_lock_as_metadata ( virtual_project. workspace ( ) , & lock. into_lock ( ) , printer) ,
124+ Ok ( lock) => {
125+ let lock = lock. into_lock ( ) ;
126+ let mut export = Metadata :: from_lock ( virtual_project. workspace ( ) , & lock) ?;
127+ if module_owners {
128+ let environment = ProjectEnvironment :: get_or_init (
129+ virtual_project. workspace ( ) ,
130+ & groups,
131+ python. as_deref ( ) . map ( PythonRequest :: parse) ,
132+ & install_mirrors,
133+ & client_builder,
134+ python_preference,
135+ python_downloads,
136+ false ,
137+ no_config,
138+ Some ( false ) ,
139+ cache,
140+ DryRun :: Disabled ,
141+ printer,
142+ preview,
143+ )
144+ . await ?;
145+ let module_owners = collect_module_owners (
146+ virtual_project. workspace ( ) ,
147+ & lock,
148+ & environment,
149+ & settings,
150+ & client_builder,
151+ & state,
152+ & concurrency,
153+ cache,
154+ workspace_cache,
155+ preview,
156+ )
157+ . await
158+ . context ( "Failed to collect module owners" ) ?;
159+ export = export. with_module_owners ( module_owners) ;
160+ }
161+
162+ print_metadata ( & export, printer)
163+ }
121164 Err ( err @ ProjectError :: LockMismatch ( ..) ) => {
122165 writeln ! ( printer. stderr( ) , "{}" , err. to_string( ) . bold( ) ) ?;
123166 Ok ( ExitStatus :: Failure )
@@ -131,13 +174,7 @@ pub(crate) async fn metadata(
131174 }
132175}
133176
134- fn print_lock_as_metadata (
135- workspace : & Workspace ,
136- lock : & Lock ,
137- printer : Printer ,
138- ) -> Result < ExitStatus > {
139- let export = Metadata :: from_lock ( workspace, lock) ?;
140-
177+ fn print_metadata ( export : & Metadata , printer : Printer ) -> Result < ExitStatus > {
141178 writeln ! ( printer. stdout( ) , "{}" , export. to_json( ) ?) ?;
142179
143180 Ok ( ExitStatus :: Success )
0 commit comments