@@ -13,8 +13,9 @@ use pet_core::{os_environment::EnvironmentApi, reporter::Reporter, Configuration
1313use pet_poetry:: Poetry ;
1414use pet_poetry:: PoetryLocator ;
1515use pet_python_utils:: cache:: set_cache_directory;
16- use pet_reporter:: { self , cache:: CacheReporter , stdio} ;
16+ use pet_reporter:: { self , cache:: CacheReporter , collect , stdio} ;
1717use resolve:: resolve_environment;
18+ use serde:: Serialize ;
1819use std:: path:: PathBuf ;
1920use std:: { collections:: BTreeMap , env, sync:: Arc , time:: SystemTime } ;
2021use tracing_subscriber:: { fmt, layer:: SubscriberExt , util:: SubscriberInitExt , EnvFilter } ;
@@ -73,6 +74,7 @@ pub struct FindOptions {
7374 pub workspace_only : bool ,
7475 pub cache_directory : Option < PathBuf > ,
7576 pub kind : Option < PythonEnvironmentKind > ,
77+ pub json : bool ,
7678}
7779
7880pub fn find_and_report_envs_stdio ( options : FindOptions ) {
@@ -103,17 +105,29 @@ pub fn find_and_report_envs_stdio(options: FindOptions) {
103105 locator. configure ( & config) ;
104106 }
105107
106- find_envs (
107- & options,
108- & locators,
109- config,
110- conda_locator. as_ref ( ) ,
111- poetry_locator. as_ref ( ) ,
112- & environment,
113- search_scope,
114- ) ;
115-
116- println ! ( "Completed in {}ms" , now. elapsed( ) . unwrap( ) . as_millis( ) )
108+ if options. json {
109+ find_envs_json (
110+ & options,
111+ & locators,
112+ config,
113+ conda_locator. as_ref ( ) ,
114+ poetry_locator. as_ref ( ) ,
115+ & environment,
116+ search_scope,
117+ ) ;
118+ } else {
119+ find_envs (
120+ & options,
121+ & locators,
122+ config,
123+ conda_locator. as_ref ( ) ,
124+ poetry_locator. as_ref ( ) ,
125+ & environment,
126+ search_scope,
127+ ) ;
128+
129+ println ! ( "Completed in {}ms" , now. elapsed( ) . unwrap( ) . as_millis( ) )
130+ }
117131}
118132
119133fn create_config ( options : & FindOptions ) -> Configuration {
@@ -257,7 +271,62 @@ fn find_envs(
257271 }
258272}
259273
260- pub fn resolve_report_stdio ( executable : PathBuf , verbose : bool , cache_directory : Option < PathBuf > ) {
274+ #[ derive( Serialize ) ]
275+ #[ serde( rename_all = "camelCase" ) ]
276+ struct JsonOutput {
277+ managers : Vec < pet_core:: manager:: EnvManager > ,
278+ environments : Vec < pet_core:: python_environment:: PythonEnvironment > ,
279+ }
280+
281+ fn find_envs_json (
282+ options : & FindOptions ,
283+ locators : & Arc < Vec < Arc < dyn Locator > > > ,
284+ config : Configuration ,
285+ conda_locator : & Conda ,
286+ poetry_locator : & Poetry ,
287+ environment : & dyn Environment ,
288+ search_scope : Option < SearchScope > ,
289+ ) {
290+ let collect_reporter = Arc :: new ( collect:: create_reporter ( ) ) ;
291+ let reporter = CacheReporter :: new ( collect_reporter. clone ( ) ) ;
292+
293+ find_and_report_envs ( & reporter, config, locators, environment, search_scope) ;
294+ if options. report_missing {
295+ let _ = conda_locator. find_and_report_missing_envs ( & reporter, None ) ;
296+ let _ = poetry_locator. find_and_report_missing_envs ( & reporter, None ) ;
297+ }
298+
299+ let managers = collect_reporter
300+ . managers
301+ . lock ( )
302+ . expect ( "managers mutex poisoned" )
303+ . clone ( ) ;
304+ let mut environments = collect_reporter
305+ . environments
306+ . lock ( )
307+ . expect ( "environments mutex poisoned" )
308+ . clone ( ) ;
309+
310+ if let Some ( kind) = options. kind {
311+ environments. retain ( |e| e. kind == Some ( kind) ) ;
312+ }
313+
314+ let output = JsonOutput {
315+ managers,
316+ environments,
317+ } ;
318+ println ! (
319+ "{}" ,
320+ serde_json:: to_string_pretty( & output) . expect( "failed to serialize environments as JSON" )
321+ ) ;
322+ }
323+
324+ pub fn resolve_report_stdio (
325+ executable : PathBuf ,
326+ verbose : bool ,
327+ cache_directory : Option < PathBuf > ,
328+ json : bool ,
329+ ) {
261330 // Initialize tracing for performance profiling (includes log compatibility)
262331 initialize_tracing ( verbose) ;
263332
@@ -287,19 +356,29 @@ pub fn resolve_report_stdio(executable: PathBuf, verbose: bool, cache_directory:
287356 }
288357
289358 if let Some ( result) = resolve_environment ( & executable, & locators, & environment) {
290- //
291- println ! ( "Environment found for {executable:?}" ) ;
292359 let env = & result. resolved . unwrap_or ( result. discovered ) ;
293- if let Some ( manager) = & env. manager {
294- reporter. report_manager ( manager) ;
360+ if json {
361+ println ! (
362+ "{}" ,
363+ serde_json:: to_string_pretty( env) . expect( "failed to serialize environment as JSON" )
364+ ) ;
365+ } else {
366+ println ! ( "Environment found for {executable:?}" ) ;
367+ if let Some ( manager) = & env. manager {
368+ reporter. report_manager ( manager) ;
369+ }
370+ reporter. report_environment ( env) ;
295371 }
296- reporter. report_environment ( env) ;
372+ } else if json {
373+ println ! ( "null" ) ;
297374 } else {
298375 println ! ( "No environment found for {executable:?}" ) ;
299376 }
300377
301- println ! (
302- "Resolve completed in {}ms" ,
303- now. elapsed( ) . unwrap( ) . as_millis( )
304- )
378+ if !json {
379+ println ! (
380+ "Resolve completed in {}ms" ,
381+ now. elapsed( ) . unwrap( ) . as_millis( )
382+ )
383+ }
305384}
0 commit comments