-
Notifications
You must be signed in to change notification settings - Fork 2
EIM-112: Added the ping check for mirrors #271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 6 commits
fb25292
e1fdabf
10b9c32
5c82fad
c82dbe9
84263b0
550bdd1
98cc3be
6e94a10
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,14 +1,18 @@ | ||
| use std::path::PathBuf; | ||
|
|
||
| use crate::cli::helpers::{ | ||
| first_defaulted_multiselect, generic_confirm, generic_input, generic_select, run_with_spinner, | ||
| use idf_im_lib::{ | ||
| settings::Settings, | ||
| system_dependencies, | ||
| utils::{mirror_entries_to_display, sorted_mirror_entries, url_from_display_line}, | ||
| }; | ||
| use idf_im_lib::settings::Settings; | ||
| use idf_im_lib::system_dependencies; | ||
| use log::{debug, info}; | ||
| use rust_i18n::t; | ||
|
|
||
| // no runtime creation here; we run inside the app's existing Tokio runtime | ||
| use crate::cli::helpers::generic_confirm_with_default; | ||
| use crate::cli::helpers::{ | ||
| first_defaulted_multiselect, generic_confirm, generic_input, generic_select, run_with_spinner, | ||
| }; | ||
|
|
||
| pub async fn select_target() -> Result<Vec<String>, String> { | ||
| let mut available_targets = idf_im_lib::idf_versions::get_avalible_targets().await?; | ||
|
|
@@ -176,49 +180,100 @@ pub fn check_and_install_python( | |
| Ok(()) | ||
| } | ||
|
|
||
| pub fn select_mirrors(mut config: Settings) -> Result<Settings, String> { | ||
| if (config.wizard_all_questions.unwrap_or_default() | ||
| || config.idf_mirror.is_none() | ||
| || config.is_default("idf_mirror")) | ||
| && config.non_interactive == Some(false) | ||
| { | ||
| config.idf_mirror = Some(generic_select( | ||
| "wizard.idf.mirror", | ||
| &idf_im_lib::get_idf_mirrors_list() | ||
| .iter() | ||
| .map(|&s| s.to_string()) | ||
| .collect(), | ||
| )?) | ||
| } | ||
| async fn select_single_mirror<FGet, FSet>( | ||
| config: &mut Settings, | ||
| field_name: &str, // e.g. "idf_mirror" | ||
| get_value: FGet, // e.g. |c: &Settings| &c.idf_mirror | ||
| set_value: FSet, // e.g. |c: &mut Settings, v| c.idf_mirror = Some(v) | ||
| candidates: Vec<String>, // list of mirror URLs | ||
| wizard_key: &str, // e.g. "wizard.idf.mirror" | ||
| log_prefix: &str, // e.g. "IDF", "Tools", "PyPI" | ||
| ) -> Result<(), String> | ||
| where | ||
| FGet: Fn(&Settings) -> &Option<String>, | ||
| FSet: Fn(&mut Settings, String), | ||
| { | ||
| let interactive = config.non_interactive == Some(false); | ||
| let wizard_all = config.wizard_all_questions.unwrap_or_default(); | ||
| let current = get_value(config); | ||
| let needs_value = current.is_none() || config.is_default(field_name); | ||
|
|
||
| if (config.wizard_all_questions.unwrap_or_default() | ||
| || config.mirror.is_none() | ||
| || config.is_default("mirror")) | ||
| && config.non_interactive == Some(false) | ||
| { | ||
| config.mirror = Some(generic_select( | ||
| "wizard.tools.mirror", | ||
| &idf_im_lib::get_idf_tools_mirrors_list() | ||
| .iter() | ||
| .map(|&s| s.to_string()) | ||
| .collect(), | ||
| )?) | ||
| } | ||
| // Measure and sort mirrors by latency | ||
| let entries = sorted_mirror_entries(candidates).await; | ||
|
|
||
| if (config.wizard_all_questions.unwrap_or_default() | ||
| || config.pypi_mirror.is_none() | ||
| || config.is_default("pypi_mirror")) | ||
| && config.non_interactive == Some(false) | ||
| { | ||
| config.pypi_mirror = Some(generic_select( | ||
| "wizard.pypi.mirror", | ||
| &idf_im_lib::get_pypi_mirrors_list() | ||
| .iter() | ||
| .map(|&s| s.to_string()) | ||
| .collect(), | ||
| )?) | ||
| if interactive && (wizard_all || needs_value) { | ||
| // Interactive mode: show list and let user pick | ||
| let display = mirror_entries_to_display(&entries); | ||
| let selected = generic_select(wizard_key, &display)?; | ||
| let url = url_from_display_line(&selected); | ||
| set_value(config, url); | ||
| } else if needs_value { | ||
| // Non-interactive or wizard not requesting this: pick best automatically | ||
| if let Some((url, score)) = entries.first() { | ||
| if *score == u32::MAX { | ||
| info!("Selected {log_prefix} mirror: {url} (timeout)"); | ||
| } else { | ||
| info!("Selected {log_prefix} mirror: {url} ({score} ms)"); | ||
| } | ||
| set_value(config, url.clone()); | ||
| } | ||
| } | ||
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| pub async fn select_mirrors(mut config: Settings) -> Result<Settings, String> { | ||
| // IDF mirror | ||
| let idf_candidates: Vec<String> = idf_im_lib::get_idf_mirrors_list() | ||
|
||
| .iter() | ||
| .map(|&s| s.to_string()) | ||
| .collect(); | ||
|
|
||
| select_single_mirror( | ||
| &mut config, | ||
| "idf_mirror", | ||
| |c: &Settings| &c.idf_mirror, | ||
| |c: &mut Settings, v| c.idf_mirror = Some(v), | ||
| idf_candidates, | ||
| "wizard.idf.mirror", | ||
| "IDF", | ||
| ) | ||
| .await?; | ||
|
|
||
| // Tools mirror | ||
| let tools_candidates: Vec<String> = idf_im_lib::get_idf_tools_mirrors_list() | ||
| .iter() | ||
| .map(|&s| s.to_string()) | ||
| .collect(); | ||
|
|
||
| select_single_mirror( | ||
| &mut config, | ||
| "mirror", | ||
| |c: &Settings| &c.tools_mirror, | ||
| |c: &mut Settings, v| c.tools_mirror = Some(v), | ||
| tools_candidates, | ||
| "wizard.tools.mirror", | ||
| "Tools", | ||
| ) | ||
| .await?; | ||
|
|
||
| // PyPI mirror | ||
| let pypi_candidates: Vec<String> = idf_im_lib::get_pypi_mirrors_list() | ||
| .iter() | ||
| .map(|&s| s.to_string()) | ||
| .collect(); | ||
|
|
||
| select_single_mirror( | ||
| &mut config, | ||
| "pypi_mirror", | ||
| |c: &Settings| &c.pypi_mirror, | ||
| |c: &mut Settings, v| c.pypi_mirror = Some(v), | ||
| pypi_candidates, | ||
| "wizard.pypi.mirror", | ||
| "PyPI", | ||
| ) | ||
| .await?; | ||
|
|
||
| Ok(config) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -311,14 +311,27 @@ pub async fn setup_tools( | |
| } | ||
| } | ||
| }; | ||
| let default_mirror = settings.tools_mirror.as_deref().unwrap(); | ||
| let mirror_latency_map = settings.get_tools_mirror_latency_map().await.unwrap(); | ||
| let best_mirror = mirror_latency_map | ||
| .iter() | ||
| .min_by_key(|(_, latency)| *latency) | ||
| .unwrap() | ||
| .0 | ||
| .clone(); | ||
| let mirror = match best_mirror.is_empty() { | ||
| true => default_mirror, | ||
| false => best_mirror.as_str(), | ||
| }; | ||
|
|
||
|
|
||
| // Use the library's setup_tools function | ||
| let installed_tools_list = idf_tools::setup_tools( | ||
| &tools, | ||
| settings.target.clone().unwrap_or_default(), | ||
| &PathBuf::from(&tool_setup.download_dir), | ||
| &PathBuf::from(&tool_setup.install_dir), | ||
| settings.mirror.as_deref(), | ||
| Some(mirror), | ||
| progress_callback, | ||
| ) | ||
| .await | ||
|
|
@@ -353,6 +366,19 @@ pub async fn setup_tools( | |
| } | ||
| }; | ||
|
|
||
| let default_pypi_mirror = settings.pypi_mirror.as_deref().unwrap(); | ||
| let pypi_mirror_latency_map = settings.get_pypi_mirror_latency_map().await.unwrap(); | ||
| let best_pypi_mirror = pypi_mirror_latency_map | ||
| .iter() | ||
| .min_by_key(|(_, latency)| *latency) | ||
| .unwrap() | ||
|
||
| .0 | ||
| .clone(); | ||
| let pypi_mirror = match best_pypi_mirror.is_empty() { | ||
| true => default_pypi_mirror, | ||
| false => best_pypi_mirror.as_str(), | ||
| }; | ||
|
|
||
| // Install Python environment | ||
| match idf_im_lib::python_utils::install_python_env( | ||
| &paths, | ||
|
|
@@ -361,7 +387,7 @@ pub async fn setup_tools( | |
| true, //TODO: actually read from config | ||
| &settings.idf_features.clone().unwrap_or_default(), | ||
| offline_archive_dir, // Offline archive directory | ||
| &settings.pypi_mirror, // PyPI mirror | ||
| &Some(pypi_mirror.to_string()), // PyPI mirror | ||
| ).await { | ||
| Ok(_) => { | ||
| info!("Python environment installed"); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is non idiomatic way and also it's reversing the current logic. Curently when non_insteractive is None the wizard work in interactive mode in your case it's the opposite.
just use unwarp_or_default() as all the settings has implemented defaults.