Skip to content

Commit f0b644b

Browse files
committed
EIM-193 initial refactoring
EIM-193 checking installed tool version tools are now installed inside version named subfolder added docstrings to the new functions decompressing tools even if checksum fits (needed for offline installation) fixed tests
1 parent 36d5c50 commit f0b644b

File tree

7 files changed

+515
-491
lines changed

7 files changed

+515
-491
lines changed

src-tauri/locales/app.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ wizard.idf_path_exists.prompt:
138138
en: The path already exists. Do you want to proceed with installation without redownloading IDF?
139139
cn: 该路径已存在。是​​否要继续安装而不重新下载 IDF?
140140
wizard.tools_download.progress:
141-
en: Downloading tools
141+
en: Downloading tools to
142142
cn: 下载工具
143143
wizard.tool_download.progress:
144144
en: Downloading tool

src-tauri/src/cli/wizard.rs

Lines changed: 73 additions & 248 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use idf_im_lib::{ensure_path, DownloadProgress, ProgressMessage};
77
use indicatif::{ProgressBar, ProgressState, ProgressStyle};
88
use log::{debug, error, info, warn};
99
use rust_i18n::t;
10+
use std::collections::HashMap;
1011
use std::sync::mpsc;
1112
use std::thread;
1213
use std::{
@@ -28,181 +29,6 @@ use crate::cli::helpers::{
2829

2930
use crate::cli::prompts::*;
3031

31-
async fn download_tools(
32-
tools_file: ToolsFile,
33-
selected_chip: Vec<String>,
34-
destination_path: &str,
35-
mirror: Option<&str>,
36-
) -> Result<Vec<String>> {
37-
let tool_name_list: Vec<String> = tools_file
38-
.tools
39-
.iter()
40-
.map(|tool| tool.name.clone())
41-
.collect();
42-
info!(
43-
"{}: {:?}",
44-
t!("wizard.tools_download.progress"),
45-
tool_name_list
46-
);
47-
let list = idf_im_lib::idf_tools::filter_tools_by_target(tools_file.tools, &selected_chip);
48-
49-
let platform = match idf_im_lib::idf_tools::get_platform_identification(None) {
50-
Ok(platform) => platform,
51-
Err(err) => {
52-
if std::env::consts::OS == "windows" {
53-
// All this is for cases when on windows microsoft store creates "pseudolinks" for python
54-
let scp = idf_im_lib::system_dependencies::get_scoop_path();
55-
let usable_python = match scp {
56-
Some(path) => {
57-
let mut python_path = PathBuf::from(path);
58-
python_path.push("python3.exe");
59-
python_path.to_str().unwrap().to_string()
60-
}
61-
None => "python3.exe".to_string(),
62-
};
63-
match idf_im_lib::idf_tools::get_platform_identification(Some(&usable_python)) {
64-
Ok(platform) => platform,
65-
Err(err) => {
66-
error!("Unable to identify platform: {}", err);
67-
panic!("{}. {:?}", t!("wizard.tools_platform_error"), err);
68-
}
69-
}
70-
} else {
71-
panic!("{}. {:?}", t!("wizard.tools_platform_error"), err);
72-
}
73-
}
74-
};
75-
debug!("Python platform: {}", platform);
76-
let download_links = idf_im_lib::idf_tools::change_links_donwanload_mirror(
77-
idf_im_lib::idf_tools::get_download_link_by_platform(list, &platform),
78-
// Some("https://dl.espressif.com/github_assets"), // this switches mirror, should be parametrized
79-
mirror,
80-
)
81-
.into_iter()
82-
.collect::<Vec<_>>();
83-
let mut downloaded_tools: Vec<String> = vec![];
84-
for (tool_name, download_link) in download_links.iter() {
85-
info!("{}: {}", t!("wizard.tool_download.progress"), tool_name);
86-
87-
let (progress_tx, progress_rx) = mpsc::channel();
88-
89-
let progress_bar = ProgressBar::new(download_link.size);
90-
progress_bar.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})").unwrap()
91-
.with_key("eta", |state: &ProgressState, w: &mut dyn Write| write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap())
92-
.progress_chars("#>-"));
93-
94-
debug!("Download link: {}", download_link.url);
95-
debug!("destination: {}", destination_path);
96-
97-
let file_path = Path::new(&download_link.url);
98-
let filename: &str = file_path.file_name().unwrap().to_str().unwrap();
99-
100-
let full_file_path = Path::new(&destination_path).join(Path::new(filename));
101-
match idf_im_lib::verify_file_checksum(
102-
&download_link.sha256,
103-
full_file_path.to_str().unwrap(),
104-
) {
105-
Ok(true) => {
106-
downloaded_tools.push(filename.to_string()); // add it to the list for extraction even if it's already downloaded
107-
info!("{}", t!("wizard.tool_file.present"));
108-
progress_bar.finish();
109-
continue;
110-
}
111-
_ => {
112-
debug!("{}", t!("wizard.tool_file.missing"));
113-
}
114-
}
115-
let tn = tool_name.clone();
116-
let pb = progress_bar.clone();
117-
let progress_handle = {
118-
thread::spawn(move || {
119-
while let Ok(progress_msg) = progress_rx.recv() {
120-
match progress_msg {
121-
DownloadProgress::Progress(current, _total) => {
122-
pb.set_position(current);
123-
}
124-
DownloadProgress::Complete => {
125-
pb.finish();
126-
break;
127-
}
128-
DownloadProgress::Error(err) => {
129-
log::error!("Error downloading {}: {}", tn, err);
130-
break;
131-
}
132-
}
133-
}
134-
})
135-
};
136-
137-
match idf_im_lib::download_file(&download_link.url, destination_path, Some(progress_tx)).await {
138-
Ok(_) => {
139-
downloaded_tools.push(filename.to_string());
140-
progress_bar.finish();
141-
info!("{} {}", t!("wizard.tool.downloaded"), tool_name);
142-
}
143-
Err(err) => {
144-
error!("{}: {}", t!("wizard.tool.download_failed"), tool_name);
145-
error!("Error: {:?}", err);
146-
return Err(anyhow!("{}: {}", t!("wizard.tool.download_failed"), err));
147-
}
148-
}
149-
progress_handle.join().map_err(|e| anyhow::anyhow!("Progress reporting thread panicked: {:?}", e))?;
150-
match idf_im_lib::verify_file_checksum(
151-
&download_link.sha256,
152-
full_file_path.to_str().unwrap(),
153-
) {
154-
Ok(true) => {
155-
continue;
156-
}
157-
_ => {
158-
error!("{}", t!("wizard.tool.corupted"));
159-
match fs::remove_file(&full_file_path) {
160-
Ok(_) => {
161-
error!(
162-
"{}: {}",
163-
t!("wizard.tool.removed"),
164-
full_file_path.to_str().unwrap()
165-
);
166-
}
167-
Err(err) => {
168-
error!(
169-
"{}: {}: {}",
170-
t!("wizard.tool.remove_failed"),
171-
full_file_path.to_str().unwrap(),
172-
err
173-
);
174-
}
175-
};
176-
}
177-
}
178-
}
179-
Ok(downloaded_tools)
180-
}
181-
182-
fn extract_tools(tools: Vec<String>, source_path: &str, destination_path: &str) -> anyhow::Result<()> {
183-
let mut failed = false;
184-
for tool in tools.iter() {
185-
let mut archive_path = PathBuf::from(source_path);
186-
archive_path.push(tool);
187-
let out = idf_im_lib::decompress_archive(archive_path.to_str().unwrap(), destination_path);
188-
match out {
189-
Ok(_) => {
190-
info!("{}: {}", t!("wizard.tool.extracted"), tool);
191-
}
192-
Err(err) => {
193-
error!("{:?}", err);
194-
error!("{}: {}", t!("wizard.tool.extract_failed"), tool);
195-
failed = true;
196-
}
197-
}
198-
}
199-
if failed {
200-
Err(anyhow::anyhow!("Some tools failed to extract"))
201-
} else {
202-
Ok(())
203-
}
204-
}
205-
20632
fn add_to_shell_rc(content: &str) -> Result<(), String> {
20733
let shell = env::var("SHELL").unwrap_or_else(|_| String::from(""));
20834
let home = dirs::home_dir().unwrap();
@@ -352,7 +178,6 @@ pub fn download_idf(config: DownloadConfig) -> Result<(), DownloadError> {
352178
}
353179
}
354180
}
355-
356181
}
357182

358183
fn setup_directory(
@@ -427,68 +252,57 @@ async fn download_and_extract_tools(
427252
tools: &ToolsFile,
428253
download_dir: &PathBuf,
429254
install_dir: &PathBuf,
430-
) -> anyhow::Result<()> {
431-
let downloaded_tools_list = match download_tools(
432-
tools.clone(),
433-
config.target.clone().unwrap(),
434-
download_dir.to_str().unwrap(),
435-
config.mirror.as_deref(),
436-
)
437-
.await {
438-
Ok(list) => list,
439-
Err(err) => {
440-
error!("Failed to download tools: {}", err);
441-
return Err(anyhow!(err));
255+
) -> anyhow::Result<HashMap<String, (String, idf_im_lib::idf_tools::Download)>> {
256+
info!(
257+
"{}: {:?}",
258+
t!("wizard.tools_download.progress"),
259+
download_dir.display()
260+
);
261+
let progress_bar = ProgressBar::new(0);
262+
progress_bar.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})").unwrap()
263+
.with_key("eta", |state: &ProgressState, w: &mut dyn Write| write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap())
264+
.progress_chars("#>-"));
265+
266+
let progress_callback = move |progress: DownloadProgress| match progress {
267+
DownloadProgress::Progress(current, total) => {
268+
progress_bar.set_length(total);
269+
progress_bar.set_position(current);
270+
}
271+
DownloadProgress::Complete => {
272+
progress_bar.finish();
273+
}
274+
DownloadProgress::Error(err) => {
275+
progress_bar.abandon_with_message(format!("Error: {}", err));
276+
}
277+
DownloadProgress::Start(_) => {
278+
progress_bar.set_position(0);
279+
}
280+
DownloadProgress::Downloaded(url) => {
281+
if let Some(filename) = Path::new(&url).file_name().and_then(|f| f.to_str()) {
282+
info!("{} sucessfully downloaded", filename.to_string());
283+
}
284+
}
285+
DownloadProgress::Verified(url) => {
286+
if let Some(filename) = Path::new(&url).file_name().and_then(|f| f.to_str()) {
287+
info!("{} checksum verified", filename.to_string());
288+
}
289+
}
290+
DownloadProgress::Extracted(url) => {
291+
if let Some(filename) = Path::new(&url).file_name().and_then(|f| f.to_str()) {
292+
info!("{} sucessfully extracted", filename.to_string());
293+
}
442294
}
443295
};
444296

445-
extract_tools(
446-
downloaded_tools_list,
447-
download_dir.to_str().unwrap(),
448-
install_dir.to_str().unwrap(),
297+
idf_im_lib::idf_tools::setup_tools(
298+
tools,
299+
config.target.clone().unwrap(),
300+
download_dir,
301+
install_dir,
302+
config.mirror.as_deref(),
303+
progress_callback,
449304
)
450-
}
451-
452-
fn get_and_validate_idf_tools_path(
453-
config: &mut Settings,
454-
idf_path: &PathBuf,
455-
) -> Result<PathBuf, String> {
456-
let mut idf_tools_path = idf_path.clone();
457-
458-
if let Some(file) = config.idf_tools_path.clone() {
459-
idf_tools_path.push(&file);
460-
} else if config.wizard_all_questions.unwrap_or(false) {
461-
let name = generic_input(
462-
"wizard.idf_tools.prompt",
463-
"wizard.idf_tools.prompt.failure",
464-
DEFAULT_IDF_TOOLS_PY_LOCATION,
465-
)?;
466-
467-
idf_tools_path.push(&name);
468-
config.idf_tools_path = Some(name);
469-
} else {
470-
idf_tools_path.push(DEFAULT_IDF_TOOLS_PY_LOCATION); // TODO: defaults are in lib now
471-
config.idf_tools_path = Some(DEFAULT_IDF_TOOLS_PY_LOCATION.to_string());
472-
}
473-
474-
if fs::metadata(&idf_tools_path).is_err() {
475-
warn!("{}", t!("wizard.idf_tools.not_found"));
476-
let idf_tools_py_select = FolderSelect::with_theme(&create_theme())
477-
.with_prompt(t!("wizard.idf_tools.select.prompt"))
478-
.folder(idf_path.to_str().unwrap())
479-
.file(true)
480-
.interact()
481-
.map_err(|e| format!("Failed to select: {}", e))?;
482-
483-
if fs::metadata(&idf_tools_py_select).is_ok() {
484-
idf_tools_path = PathBuf::from(&idf_tools_py_select);
485-
config.idf_tools_path = Some(idf_tools_py_select);
486-
} else {
487-
return Err(t!("wizard.idf_tools.unreachable").to_string());
488-
}
489-
}
490-
491-
Ok(idf_tools_path)
305+
.await
492306
}
493307

494308
pub async fn run_wizzard_run(mut config: Settings) -> Result<(), String> {
@@ -583,28 +397,36 @@ pub async fn run_wizzard_run(mut config: Settings) -> Result<(), String> {
583397
let tools = idf_im_lib::idf_tools::read_and_parse_tools_file(&validated_file)
584398
.map_err(|err| format!("{}: {}", t!("wizard.tools_json.unparsable"), err))?;
585399

586-
match download_and_extract_tools(
400+
let installed_tools_list = match download_and_extract_tools(
587401
&config,
588402
&tools,
589403
&tool_download_directory,
590404
&tool_install_directory,
591405
)
592-
.await {
593-
Ok(_) => {
594-
info!("{}: {}", t!("wizard.tools.downloaded"), tools_json_file.display());
406+
.await
407+
{
408+
Ok(list) => {
409+
info!(
410+
"{}: {}",
411+
t!("wizard.tools.downloaded"),
412+
tools_json_file.display()
413+
);
414+
list
595415
}
596416
Err(err) => {
597417
error!("Failed to download and extract tools: {}", err);
598418
return Err(err.to_string());
599419
}
600-
}
420+
};
601421
match idf_im_lib::python_utils::install_python_env(
602-
&idf_version,
603-
&tool_install_directory,
604-
true, //TODO: actually read from config
605-
&idf_path,
606-
&config.idf_features.clone().unwrap_or_default(),
607-
).await {
422+
&idf_version,
423+
&tool_install_directory,
424+
true, //TODO: actually read from config
425+
&idf_path,
426+
&config.idf_features.clone().unwrap_or_default(),
427+
)
428+
.await
429+
{
608430
Ok(_) => {
609431
info!("Python environment installed");
610432
}
@@ -613,13 +435,16 @@ pub async fn run_wizzard_run(mut config: Settings) -> Result<(), String> {
613435
return Err(err.to_string());
614436
}
615437
};
616-
let idf_python_env_path = tool_install_directory.join("python").join(&idf_version).join("venv"); //todo: move to config
438+
let idf_python_env_path = tool_install_directory
439+
.join("python")
440+
.join(&idf_version)
441+
.join("venv"); //todo: move to config
617442
ensure_path(idf_python_env_path.to_str().unwrap())
618443
.map_err(|err| format!("Failed to create Python environment directory: {}", err))?;
619444

620-
let export_paths = idf_im_lib::idf_tools::get_tools_export_paths(
445+
let export_paths = idf_im_lib::idf_tools::get_tools_export_paths_from_list(
621446
tools,
622-
config.target.clone().unwrap().clone(),
447+
installed_tools_list,
623448
tool_install_directory.to_str().unwrap(),
624449
)
625450
.into_iter()

0 commit comments

Comments
 (0)