Skip to content

Commit f9d20bb

Browse files
committed
find all esp-idf instances and evaluate which one to process
IDF installed using eim or eclipse can be discovered parsing function for esp_idf.json file added POSIX discovery mvp updated activation script creation improved export paths in old version discovery added tool_set.json file parsing to the discovery returned the parse_tool_set_config back to working state updated according to changes in the scripts location Documentation update to add the discovery command reworked the vscode discovery according to new approach to isntallation removed unused code updated the discovery command help Fixed discovery tools paths improved windows debugging part of discovery and venv creation creating venv using proper python discovery disabled for vscode installed IDF on windows
1 parent 5f0f0a4 commit f9d20bb

File tree

8 files changed

+437
-138
lines changed

8 files changed

+437
-138
lines changed

docs/src/cli_commands.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ These options can be used with any command:
3030
| `remove` | Remove a specific ESP-IDF version |
3131
| `purge` | Purge all ESP-IDF installations |
3232
| `import` | Import existing ESP-IDF installation using tools_set_config.json |
33-
| `discover` | Discover available ESP-IDF versions (not implemented yet) |
33+
| `discover` | Discover available ESP-IDF versions |
34+
| `gui` | Run the ESP-IDF Installer GUI with arguments passed through command line |
3435

3536
## Command Details
3637

@@ -139,10 +140,10 @@ If `PATH` is not provided, the command will inform you that no config file was s
139140
Discover available ESP-IDF versions (not implemented yet).
140141
141142
```bash
142-
eim discover
143+
eim discover [PATH]
143144
```
144145
145-
This command is planned to discover ESP-IDF installations on your system but is not yet implemented.
146+
This command searches for previously installed ESP-IDF versions on your system. If PATH is not provided, the command will search from the root of the filesystem. For any found versions where automatic import is possible, they will be imported into EIM's management. For other found versions that cannot be automatically imported, the command will suggest the appropriate `eim install` command to allow the user to manually reinstall them.
146147
147148
### Fix Command
148149

src-tauri/src/cli/cli_args.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,11 @@ pub enum Commands {
6565
version: Option<String>,
6666
},
6767

68-
/// Discover available ESP-IDF versions (not implemented yet)
69-
Discover,
68+
/// Discover available ESP-IDF versions
69+
Discover {
70+
#[arg(help = "Discover available ESP-IDF versions and imports them")]
71+
path: Option<String>,
72+
},
7073

7174
/// Remove specific ESP-IDF version
7275
Remove {

src-tauri/src/cli/mod.rs

Lines changed: 211 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::path::Path;
12
use std::path::PathBuf;
23

34
use anyhow::Context;
@@ -9,8 +10,12 @@ use config::ConfigError;
910
use helpers::generic_input;
1011
use helpers::generic_select;
1112
use idf_im_lib::get_log_directory;
13+
use idf_im_lib::idf_config::IdfConfig;
1214
use idf_im_lib::settings::Settings;
1315
use 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;
1419
use idf_im_lib::version_manager::remove_single_idf_version;
1520
use idf_im_lib::version_manager::select_idf_version;
1621
use 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

Comments
 (0)