1+ use std:: path:: Path ;
12use std:: path:: PathBuf ;
23
34use anyhow:: Context ;
@@ -9,8 +10,12 @@ use config::ConfigError;
910use helpers:: generic_input;
1011use helpers:: generic_select;
1112use idf_im_lib:: get_log_directory;
13+ use idf_im_lib:: idf_config:: IdfConfig ;
1214use idf_im_lib:: settings:: Settings ;
1315use idf_im_lib:: utils:: is_valid_idf_directory;
16+ use idf_im_lib:: utils:: find_by_name_and_extension;
17+ use idf_im_lib:: utils:: parse_esp_idf_json;
18+ use idf_im_lib:: utils:: EspIdfConfig ;
1419use idf_im_lib:: version_manager:: remove_single_idf_version;
1520use idf_im_lib:: version_manager:: select_idf_version;
1621use log:: debug;
@@ -316,13 +321,128 @@ pub async fn run_cli(cli: Cli) -> anyhow::Result<()> {
316321 }
317322 }
318323 }
319- Commands :: Discover => {
320- // TODO:Implement version discovery
321- unimplemented ! ( "Version discovery not implemented yet" ) ;
322- println ! ( "Discovering available versions... (This can take couple of minutes)" ) ;
323- let idf_dirs = idf_im_lib:: version_manager:: find_esp_idf_folders ( "/" ) ;
324+ Commands :: Discover { path } => {
325+ info ! ( "Discovering available versions... (This can take couple of minutes)" ) ;
326+ let path = path. unwrap_or_else ( || {
327+ let default_path = match std:: env:: consts:: OS {
328+ "windows" => {
329+ "C:\\ " . to_string ( )
330+ }
331+ _ => {
332+ "/" . to_string ( )
333+ }
334+ } ;
335+
336+
337+ debug ! ( "No path provided, using default: {}" , default_path) ;
338+ default_path
339+ } ) ;
340+ // first parse existing esp_idf.json (using parse_esp_idf_json) || previous VSCode installations
341+ info ! ( "Searching for esp_idf.json files..." ) ;
342+ let search_patch = Path :: new ( & path) ;
343+ let esp_idf_json_path = find_by_name_and_extension (
344+ search_patch,
345+ "esp_idf" ,
346+ "json" ,
347+ ) ;
348+ if esp_idf_json_path. is_empty ( ) {
349+ info ! ( "No esp_idf.json found" ) ;
350+ } else {
351+ info ! ( "Found {} esp_idf.json files:" , esp_idf_json_path. len( ) ) ;
352+ }
353+ for path in esp_idf_json_path {
354+ info ! ( "- {} " , & path) ;
355+ match std:: env:: consts:: OS {
356+ "windows" => {
357+ // On Windows, we need to fix every installation from VSCode
358+ info ! ( "Parsing esp_idf.json at: {}" , path) ;
359+ let idf_json_path = Path :: new ( & path) ;
360+ let json_str = std:: fs:: read_to_string ( idf_json_path) . unwrap ( ) ;
361+ let config: EspIdfConfig = match serde_json:: from_str ( & json_str) {
362+ Ok ( config) => config,
363+ Err ( e) => {
364+ error ! ( "Failed to parse config file: {}" , e) ;
365+ continue ;
366+ }
367+ } ;
368+ for ( _key, value) in config. idf_installed {
369+ let idf_path = value. path ;
370+ fix_command ( Some ( idf_path) ) . await ?;
371+ }
372+ }
373+ _ => {
374+ match parse_esp_idf_json ( & path) {
375+ Ok ( _) => {
376+ info ! ( "Parsed config: {:?}" , path) ;
377+ }
378+ Err ( err) => {
379+ info ! ( "Failed to parse esp_idf.json: {}" , err) ;
380+ }
381+ }
382+ }
383+ }
384+ }
385+ // second try to find tool_set_config.json (using parse_tool_set_config) || previous Eclipse installations
386+ info ! ( "Searching for tool_set_config.json files..." ) ;
387+ let tool_set_config_path = find_by_name_and_extension (
388+ search_patch,
389+ "tool_set_config" ,
390+ "json" ,
391+ ) ;
392+ if tool_set_config_path. is_empty ( ) {
393+ info ! ( "No tool_set_config.json found" ) ;
394+ } else {
395+ info ! ( "Found {} tool_set_config.json files:" , tool_set_config_path. len( ) ) ;
396+ }
397+ for path in tool_set_config_path {
398+ info ! ( "- {} " , & path) ;
399+ match idf_im_lib:: utils:: parse_tool_set_config ( & path) {
400+ Ok ( _) => {
401+ info ! ( "Parsed config: {:?}" , path) ;
402+ }
403+ Err ( err) => {
404+ info ! ( "Failed to parse tool_set_config.json: {}" , err) ;
405+ }
406+ }
407+ }
408+ // third try to find IDF directories (using find_esp_idf_folders) || previous instalation from cli
409+ info ! ( "Searching for any other IDF directories..." ) ;
410+ let idf_dirs = idf_im_lib:: version_manager:: find_esp_idf_folders ( & path) ;
411+ if idf_dirs. is_empty ( ) {
412+ info ! ( "No IDF directories found" ) ;
413+ } else {
414+ info ! ( "Found {} IDF directories:" , idf_dirs. len( ) ) ;
415+ }
416+ let config = match idf_im_lib:: version_manager:: get_esp_ide_config ( ) {
417+ Ok ( config) => {
418+ if config. idf_installed . is_empty ( ) {
419+ debug ! (
420+ "No versions found. Every discovered version can be imported."
421+ ) ;
422+ }
423+ config
424+ }
425+ Err ( _err) => {
426+ debug ! ( "No ide config found. New will be created." ) ;
427+ IdfConfig :: default ( )
428+ }
429+ } ;
430+ let mut paths_to_add = vec ! [ ] ;
324431 for dir in idf_dirs {
325- println ! ( "Found IDF directory: {}" , dir) ;
432+ info ! ( "- {} " , & dir) ;
433+ if config. clone ( ) . is_path_in_config ( dir. clone ( ) ) {
434+ info ! ( "Already present!" ) ;
435+ } else {
436+ info ! ( "Can be added..." ) ;
437+ paths_to_add. push ( dir) ;
438+ }
439+ }
440+ if paths_to_add. is_empty ( ) {
441+ info ! ( "No new IDF directories found to add." ) ;
442+ return Ok ( ( ) ) ;
443+ } else {
444+ info ! ( "Found {} new IDF directories available to add:" , paths_to_add. len( ) ) ;
445+ info ! ( "You can add them using `eim install` command with the `--path` option." ) ;
326446 }
327447 Ok ( ( ) )
328448 }
@@ -434,87 +554,7 @@ pub async fn run_cli(cli: Cli) -> anyhow::Result<()> {
434554 }
435555 }
436556 Commands :: Fix { path } => {
437- let path_to_fix = if path. is_some ( ) {
438- // If a path is provided, fix the IDF installation at that path
439- let path = path. unwrap ( ) ;
440- if is_valid_idf_directory ( & path) {
441- PathBuf :: from ( path)
442- } else {
443- error ! ( "Invalid IDF directory: {}" , path) ;
444- return Err ( anyhow:: anyhow!( "Invalid IDF directory: {}" , path) ) ;
445- }
446- } else {
447- match idf_im_lib:: version_manager:: list_installed_versions ( ) {
448- Ok ( versions) => {
449- if versions. is_empty ( ) {
450- warn ! ( "No versions installed" ) ;
451- return Ok ( ( ) ) ;
452- } else {
453- let options = versions. iter ( ) . map ( |v| v. path . clone ( ) ) . collect ( ) ;
454- let version_path = match helpers:: generic_select (
455- "Which version do you want to fix?" ,
456- & options,
457- ) {
458- Ok ( selected) => selected,
459- Err ( err) => {
460- error ! ( "Error: {}" , err) ;
461- return Err ( anyhow:: anyhow!( err) ) ;
462- }
463- } ;
464- PathBuf :: from ( version_path)
465- }
466- }
467- Err ( err) => {
468- debug ! ( "Error: {}" , err) ;
469- return Err ( anyhow:: anyhow!( "No versions found. Use eim install to install a new ESP-IDF version." ) ) ;
470- }
471- }
472- } ;
473- info ! ( "Fixing IDF installation at path: {}" , path_to_fix. display( ) ) ;
474- // The fix logic is just instalation with use of existing repository
475- let mut version_name = None ;
476- match idf_im_lib:: version_manager:: list_installed_versions ( ) {
477- Ok ( versions) => {
478- for v in versions {
479- if v. path == path_to_fix. to_str ( ) . unwrap ( ) {
480- info ! ( "Found existing IDF version: {}" , v. name) ;
481- // Remove the existing activation script and eim_idf.json entry
482- match remove_single_idf_version ( & v. name , true ) {
483- Ok ( _) => {
484- info ! ( "Removed existing IDF version from eim_idf.json: {}" , v. name) ;
485- version_name = Some ( v. name . clone ( ) ) ;
486- }
487- Err ( err) => {
488- error ! ( "Failed to remove existing IDF version {}: {}" , v. name, err) ;
489- }
490- }
491- }
492- }
493- }
494- Err ( _) => {
495- info ! ( "Failed to list installed versions. Using default naming." ) ;
496- }
497- }
498-
499- let mut settings = Settings :: default ( ) ;
500- settings. path = Some ( path_to_fix. clone ( ) ) ;
501- settings. non_interactive = Some ( true ) ;
502- settings. version_name = version_name;
503- settings. install_all_prerequisites = Some ( true ) ;
504- settings. config_file_save_path = None ;
505- let result = wizard:: run_wizzard_run ( settings) . await ;
506- match result {
507- Ok ( r) => {
508- info ! ( "Fix result: {:?}" , r) ;
509- info ! ( "Successfully fixed IDF installation at {}" , path_to_fix. display( ) ) ;
510- }
511- Err ( err) => {
512- error ! ( "Failed to fix IDF installation: {}" , err) ;
513- return Err ( anyhow:: anyhow!( err) ) ;
514- }
515- }
516- info ! ( "Now you can start using IDF tools" ) ;
517- Ok ( ( ) )
557+ fix_command ( path) . await
518558 }
519559 #[ cfg( feature = "gui" ) ]
520560 Commands :: Gui ( _install_args) => {
@@ -525,3 +565,87 @@ pub async fn run_cli(cli: Cli) -> anyhow::Result<()> {
525565 }
526566 }
527567}
568+
569+ async fn fix_command ( path : Option < String > ) -> anyhow:: Result < ( ) > {
570+ let path_to_fix = if path. is_some ( ) {
571+ // If a path is provided, fix the IDF installation at that path
572+ let path = path. unwrap ( ) ;
573+ if is_valid_idf_directory ( & path) {
574+ PathBuf :: from ( path)
575+ } else {
576+ error ! ( "Invalid IDF directory: {}" , path) ;
577+ return Err ( anyhow:: anyhow!( "Invalid IDF directory: {}" , path) ) ;
578+ }
579+ } else {
580+ match idf_im_lib:: version_manager:: list_installed_versions ( ) {
581+ Ok ( versions) => {
582+ if versions. is_empty ( ) {
583+ warn ! ( "No versions installed" ) ;
584+ return Ok ( ( ) ) ;
585+ } else {
586+ let options = versions. iter ( ) . map ( |v| v. path . clone ( ) ) . collect ( ) ;
587+ let version_path = match helpers:: generic_select (
588+ "Which version do you want to fix?" ,
589+ & options,
590+ ) {
591+ Ok ( selected) => selected,
592+ Err ( err) => {
593+ error ! ( "Error: {}" , err) ;
594+ return Err ( anyhow:: anyhow!( err) ) ;
595+ }
596+ } ;
597+ PathBuf :: from ( version_path)
598+ }
599+ }
600+ Err ( err) => {
601+ debug ! ( "Error: {}" , err) ;
602+ return Err ( anyhow:: anyhow!( "No versions found. Use eim install to install a new ESP-IDF version." ) ) ;
603+ }
604+ }
605+ } ;
606+ info ! ( "Fixing IDF installation at path: {}" , path_to_fix. display( ) ) ;
607+ // The fix logic is just instalation with use of existing repository
608+ let mut version_name = None ;
609+ match idf_im_lib:: version_manager:: list_installed_versions ( ) {
610+ Ok ( versions) => {
611+ for v in versions {
612+ if v. path == path_to_fix. to_str ( ) . unwrap ( ) {
613+ info ! ( "Found existing IDF version: {}" , v. name) ;
614+ // Remove the existing activation script and eim_idf.json entry
615+ match remove_single_idf_version ( & v. name , true ) {
616+ Ok ( _) => {
617+ info ! ( "Removed existing IDF version from eim_idf.json: {}" , v. name) ;
618+ version_name = Some ( v. name . clone ( ) ) ;
619+ }
620+ Err ( err) => {
621+ error ! ( "Failed to remove existing IDF version {}: {}" , v. name, err) ;
622+ }
623+ }
624+ }
625+ }
626+ }
627+ Err ( _) => {
628+ info ! ( "Failed to list installed versions. Using default naming." ) ;
629+ }
630+ }
631+
632+ let mut settings = Settings :: default ( ) ;
633+ settings. path = Some ( path_to_fix. clone ( ) ) ;
634+ settings. non_interactive = Some ( true ) ;
635+ settings. version_name = version_name;
636+ settings. install_all_prerequisites = Some ( true ) ;
637+ settings. config_file_save_path = None ; // Do not save config file in fix mode
638+ let result = wizard:: run_wizzard_run ( settings) . await ;
639+ match result {
640+ Ok ( r) => {
641+ info ! ( "Fix result: {:?}" , r) ;
642+ info ! ( "Successfully fixed IDF installation at {}" , path_to_fix. display( ) ) ;
643+ }
644+ Err ( err) => {
645+ error ! ( "Failed to fix IDF installation: {}" , err) ;
646+ return Err ( anyhow:: anyhow!( err) ) ;
647+ }
648+ }
649+ info ! ( "Now you can start using IDF tools" ) ;
650+ Ok ( ( ) )
651+ }
0 commit comments