Skip to content
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

EIM-68 enabled non-interactive mode #69

Merged
merged 4 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions src/cli_args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,19 @@ pub struct Cli {
help = "Should the installer recurse into submodules of the ESP-IDF repository (default true) "
)]
pub recurse_submodules: Option<bool>,

#[arg(
short = 'a',
long,
help = "Should the installer attempt to install all missing prerequisites (default false). This flag only affects Windows platforms as we do not offer prerequisites for other platforms. "
)]
pub install_all_prerequisites: Option<bool>,

#[arg(
long,
help = "if set, the installer will as it's very last move save the configuration to the specified file path. This file can than be used to repeat the instalation with the same settings."
)]
pub config_file_save_path: Option<String>,
}

impl IntoIterator for Cli {
Expand Down Expand Up @@ -168,6 +181,14 @@ impl IntoIterator for Cli {
"recurse_submodules".to_string(),
self.recurse_submodules.map(Into::into),
),
(
"install_all_prerequisites".to_string(),
self.install_all_prerequisites.map(Into::into),
),
(
"config_file_save_path".to_string(),
self.config_file_save_path.map(Into::into),
),
]
.into_iter()
}
Expand Down
48 changes: 31 additions & 17 deletions src/wizard/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,17 +194,26 @@ fn add_to_shell_rc(content: &str) -> Result<(), String> {
}

async fn select_targets_and_versions(mut config: Settings) -> Result<Settings, String> {
if config.target.is_none() {
if (config.wizard_all_questions.unwrap_or_default()
|| config.target.is_none()
|| config.is_default("target"))
&& config.non_interactive == Some(false)
{
config.target = Some(select_target().await?);
}
let target = config.target.clone().unwrap();
let target = config.target.clone().unwrap_or_default();
debug!("Selected target: {:?}", target);

if config.idf_versions.is_none() {
config.idf_versions = Some(select_idf_version(&target[0]).await?);
// here the non-interactive flag is passed to the inner function
if config.wizard_all_questions.unwrap_or_default()
|| config.idf_versions.is_none()
|| config.is_default("idf_versions")
{
config.idf_versions =
Some(select_idf_version(&target[0], config.non_interactive.unwrap_or_default()).await?);
// TODO: handle multiple targets
}
let idf_versions = config.idf_versions.clone().unwrap();
let idf_versions = config.idf_versions.clone().unwrap_or_default();
debug!("Selected idf version: {:?}", idf_versions);

Ok(config)
Expand All @@ -215,6 +224,7 @@ pub struct DownloadConfig {
pub idf_version: String,
pub idf_mirror: Option<String>,
pub recurse_submodules: Option<bool>,
pub non_interactive: Option<bool>,
}

pub enum DownloadError {
Expand Down Expand Up @@ -261,8 +271,6 @@ pub fn download_idf(config: DownloadConfig) -> Result<(), DownloadError> {
}
});

// let progress_bar = create_progress_bar();

let tag = if config.idf_version == "master" {
None
} else {
Expand Down Expand Up @@ -293,7 +301,13 @@ pub fn download_idf(config: DownloadConfig) -> Result<(), DownloadError> {
handle.join().unwrap();
Ok(())
}
Err(err) => handle_download_error(err),
Err(err) => {
if config.non_interactive == Some(true) {
Ok(())
} else {
handle_download_error(err)
}
}
}
}

Expand Down Expand Up @@ -432,18 +446,17 @@ fn get_and_validate_idf_tools_path(
pub async fn run_wizzard_run(mut config: Settings) -> Result<(), String> {
debug!("Config entering wizard: {:?}", config);

if let Some(non_interactive) = config.non_interactive {
if non_interactive {
panic!("Non interactive instalation not yet supported.");
// panic!("Running Wizard in non-interactive mode is not supported.");
}
}

// Check prerequisites
check_and_install_prerequisites()?;
check_and_install_prerequisites(
config.non_interactive.unwrap_or_default(),
config.install_all_prerequisites.unwrap_or_default(),
)?;

// Python sanity check
check_and_install_python()?;
check_and_install_python(
config.non_interactive.unwrap_or_default(),
config.install_all_prerequisites.unwrap_or_default(),
)?;

// select target & idf version
config = select_targets_and_versions(config).await?;
Expand All @@ -470,6 +483,7 @@ pub async fn run_wizzard_run(mut config: Settings) -> Result<(), String> {
idf_version: idf_version.to_string(),
idf_mirror: config.idf_mirror.clone(),
recurse_submodules: config.recurse_submodules,
non_interactive: config.non_interactive,
};

match download_idf(download_config) {
Expand Down
124 changes: 89 additions & 35 deletions src/wizard/prompts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,23 @@ pub async fn select_target() -> Result<Vec<String>, String> {
first_defaulted_multiselect("wizard.select_target.prompt", &available_targets)
}

pub async fn select_idf_version(target: &str) -> Result<Vec<String>, String> {
pub async fn select_idf_version(
target: &str,
non_interactive: bool,
) -> Result<Vec<String>, String> {
let mut avalible_versions = if target == "all" {
//todo process vector of targets
idf_im_lib::idf_versions::get_idf_names().await
} else {
idf_im_lib::idf_versions::get_idf_name_by_target(&target.to_string().to_lowercase()).await
};
avalible_versions.push("master".to_string());
first_defaulted_multiselect("wizard.select_idf_version.prompt", &avalible_versions)
if non_interactive {
debug!("Non-interactive mode, selecting first available IDF version.");
return Ok(vec![avalible_versions.first().unwrap().clone()]);
} else {
first_defaulted_multiselect("wizard.select_idf_version.prompt", &avalible_versions)
}
}

fn check_prerequisites() -> Result<Vec<String>, String> {
Expand All @@ -40,8 +48,15 @@ fn check_prerequisites() -> Result<Vec<String>, String> {
Err(err) => Err(err),
}
}
pub fn check_and_install_prerequisites() -> Result<(), String> {
let unsatisfied_prerequisites = run_with_spinner(check_prerequisites)?;
pub fn check_and_install_prerequisites(
non_interactive: bool,
install_all_prerequisites: bool,
) -> Result<(), String> {
let unsatisfied_prerequisites = if non_interactive {
check_prerequisites()?
} else {
run_with_spinner(check_prerequisites)?
};
if !unsatisfied_prerequisites.is_empty() {
info!(
"{}",
Expand All @@ -51,8 +66,14 @@ pub fn check_and_install_prerequisites() -> Result<(), String> {
)
);
if std::env::consts::OS == "windows" {
//TODO: remove afte prerequisities install fix in linux
if generic_confirm("prerequisites.install.prompt").map_err(|e| e.to_string())? {
let res = if !install_all_prerequisites && !non_interactive {
generic_confirm("prerequisites.install.prompt")
} else if install_all_prerequisites {
Ok(true)
} else {
Ok(false)
};
if res.map_err(|e| e.to_string())? {
system_dependencies::install_prerequisites(unsatisfied_prerequisites)
.map_err(|e| e.to_string())?;

Expand Down Expand Up @@ -100,12 +121,28 @@ fn python_sanity_check(python: Option<&str>) -> Result<(), String> {
Err(t!("python.sanitycheck.fail").to_string())
}
}
pub fn check_and_install_python() -> Result<(), String> {
pub fn check_and_install_python(
non_interactive: bool,
install_all_prerequisites: bool,
) -> Result<(), String> {
info!("{}", t!("python.sanitycheck.info"));
if let Err(err) = run_with_spinner(|| python_sanity_check(None)) {
let check_result = if non_interactive {
python_sanity_check(None)
} else {
run_with_spinner(|| python_sanity_check(None))
};
if let Err(err) = check_result {
if std::env::consts::OS == "windows" {
info!("{}", t!("python.sanitycheck.fail"));
if generic_confirm("pythhon.install.prompt").map_err(|e| e.to_string())? {
let res = if !install_all_prerequisites && !non_interactive {
generic_confirm("pythhon.install.prompt")
} else if install_all_prerequisites {
Ok(true)
} else {
Ok(false)
};

if res.map_err(|e| e.to_string())? {
system_dependencies::install_prerequisites(vec!["[email protected]".to_string()])
.map_err(|e| e.to_string())?;
let scp = system_dependencies::get_scoop_path();
Expand Down Expand Up @@ -138,51 +175,68 @@ pub fn check_and_install_python() -> Result<(), String> {
}

pub fn select_mirrors(mut config: Settings) -> Result<Settings, String> {
config.idf_mirror = match config.idf_mirror {
Some(mirror) => Some(mirror),
None => Some(generic_select(
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(),
)?),
};
)?)
}

config.mirror = match config.mirror {
Some(mirror) => Some(mirror),
None => Some(generic_select(
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(),
)?),
};
)?)
}

Ok(config)
}

pub fn select_installation_path(mut config: Settings) -> Result<Settings, String> {
if config.path.is_none() {
let default_path = if std::env::consts::OS == "windows" {
"C:\\esp\\".to_string()
} else {
format!("{}/.espressif", dirs::home_dir().unwrap().display())
};
let mut installation_path = PathBuf::new();
let path = generic_input(
if (config.wizard_all_questions.unwrap_or_default()
|| config.path.is_none()
|| config.is_default("path"))
&& config.non_interactive == Some(false)
{
let path = match generic_input(
"wizard.instalation_path.prompt",
"wizard.instalation_path.unselected",
&default_path,
)
.unwrap();

installation_path.push(path);
config.path = Some(installation_path.clone());
&config.path.clone().unwrap_or_default().to_str().unwrap(),
) {
Ok(path) => PathBuf::from(path),
Err(e) => {
log::error!("Error: {}", e);
config.path.clone().unwrap_or_default()
}
};
config.path = Some(path);
}

Ok(config)
}

pub fn save_config_if_desired(config: &Settings) -> Result<(), String> {
if let Ok(true) = generic_confirm("wizard.after_install.save_config.prompt") {
let res =
if config.non_interactive.unwrap_or_default() && config.config_file_save_path.is_some() {
debug!("Saving config in non-interactive mode.");
Ok(true)
} else if config.non_interactive.unwrap_or_default() {
debug!("Skipping config save in non-interactive mode.");
Ok(false)
} else {
generic_confirm("wizard.after_install.save_config.prompt")
};
if let Ok(true) = res {
config
.save("eim_config.toml")
.save()
.map_err(|e| format!("{} {:?}", t!("wizard.after_install.config.save_failed"), e))?;
println!("{}", t!("wizard.after_install.config.saved"));
}
Expand Down
Loading