mirror of
https://github.com/esp-rs/espup.git
synced 2025-09-29 22:01:07 +00:00
commit
1b605ca442
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -453,6 +453,7 @@ dependencies = [
|
||||
"strum_macros",
|
||||
"tar",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"toml",
|
||||
"update-informer",
|
||||
"xz2",
|
||||
|
@ -36,6 +36,7 @@ serde = { version = "1.0.146", features = ["derive"] }
|
||||
miette = "5.4.1"
|
||||
regex = "1.7.0"
|
||||
serde_json = "1.0.87"
|
||||
thiserror = "1.0.37"
|
||||
update-informer = "0.5.0"
|
||||
|
||||
[target.aarch64-unknown-linux-gnu.dependencies]
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{host_triple::HostTriple, targets::Target, toolchain::rust::XtensaRust};
|
||||
use crate::{error::Error, host_triple::HostTriple, targets::Target, toolchain::rust::XtensaRust};
|
||||
use directories_next::ProjectDirs;
|
||||
use miette::{ErrReport, IntoDiagnostic, Result, WrapErr};
|
||||
use miette::{IntoDiagnostic, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
@ -31,31 +31,34 @@ pub struct Config {
|
||||
|
||||
impl Config {
|
||||
/// Load the config from config file
|
||||
pub fn load() -> Result<Self> {
|
||||
pub fn load() -> Result<Self, Error> {
|
||||
let dirs = ProjectDirs::from("rs", "esp", "espup").unwrap();
|
||||
let file = dirs.config_dir().join("espup.toml");
|
||||
|
||||
let config = if let Ok(data) = read(file) {
|
||||
toml::from_slice(&data).into_diagnostic()?
|
||||
let config = if let Ok(data) = read(&file) {
|
||||
toml::from_slice(&data)
|
||||
.into_diagnostic()
|
||||
.map_err(|_| Error::FailedToDeserialize)?
|
||||
} else {
|
||||
return Err(ErrReport::msg("No config file found"));
|
||||
return Err(Error::FileNotFound(file.to_string_lossy().into_owned()));
|
||||
};
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
/// Save the config to file
|
||||
pub fn save(&self) -> Result<()> {
|
||||
pub fn save(&self) -> Result<(), Error> {
|
||||
let dirs = ProjectDirs::from("rs", "esp", "espup").unwrap();
|
||||
let file = dirs.config_dir().join("espup.toml");
|
||||
|
||||
let serialized = toml::to_string(&self.clone())
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to serialize config")?;
|
||||
.map_err(|_| Error::FailedToSerialize)?;
|
||||
create_dir_all(file.parent().unwrap())
|
||||
.into_diagnostic()
|
||||
.wrap_err("Failed to create config directory")?;
|
||||
.map_err(|e| Error::FailedToCreateConfigFile(e.to_string()))?;
|
||||
write(&file, serialized)
|
||||
.into_diagnostic()
|
||||
.wrap_err_with(|| format!("Failed to write config to {}", file.display()))
|
||||
.map_err(|_| Error::FailedToWrite(file.display().to_string()))?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
81
src/error.rs
Normal file
81
src/error.rs
Normal file
@ -0,0 +1,81 @@
|
||||
use crate::emoji;
|
||||
|
||||
#[derive(Debug, miette::Diagnostic, thiserror::Error)]
|
||||
pub enum Error {
|
||||
// Host Triple
|
||||
#[diagnostic(code(espup::host_triple::unsupported_host_triple))]
|
||||
#[error("{} Host triple '{0}' is not supported", emoji::ERROR)]
|
||||
UnsupportedHostTriple(String),
|
||||
// Target
|
||||
#[diagnostic(code(espup::targets::unsupported_target))]
|
||||
#[error("{} Target '{0}' is not supported", emoji::ERROR)]
|
||||
UnsupportedTarget(String),
|
||||
// Config
|
||||
#[diagnostic(code(espup::config::file_not_found))]
|
||||
#[error("{} No config file found in '{0}'", emoji::ERROR)]
|
||||
FileNotFound(String),
|
||||
#[diagnostic(code(espup::config::failed_to_deserialize))]
|
||||
#[error("{} Failed to deserialize config", emoji::ERROR)]
|
||||
FailedToDeserialize,
|
||||
#[diagnostic(code(espup::config::failed_to_serialize))]
|
||||
#[error("{} Failed to serialize config", emoji::ERROR)]
|
||||
FailedToSerialize,
|
||||
#[diagnostic(code(espup::config::failed_to_create_config_file))]
|
||||
#[error("{} Failed to create config directory", emoji::ERROR)]
|
||||
FailedToCreateConfigFile(String),
|
||||
#[diagnostic(code(espup::config::failed_to_write))]
|
||||
#[error("{} Failed to write config to '{0}'", emoji::ERROR)]
|
||||
FailedToWrite(String),
|
||||
// Toolchain
|
||||
#[error(transparent)]
|
||||
IoError(#[from] std::io::Error),
|
||||
#[error(transparent)]
|
||||
RewquestError(#[from] reqwest::Error),
|
||||
#[diagnostic(code(espup::toolchain::failed_to_create_directory))]
|
||||
#[error("{} Creating directory '{0}' failed", emoji::ERROR)]
|
||||
FailedToCreateDirectory(String),
|
||||
#[diagnostic(code(espup::toolchain::unsupported_file_extension))]
|
||||
#[error("{} Unsuported file extension: '{0}'", emoji::ERROR)]
|
||||
UnsuportedFileExtension(String),
|
||||
// Toolchain - Rust
|
||||
#[diagnostic(code(espup::toolchain::rust::failed_to_get_latest_version))]
|
||||
#[error("{} Failed To serialize Json from string.", emoji::ERROR)]
|
||||
FailedToSerializeJson,
|
||||
#[diagnostic(code(espup::toolchain::rust::xtensa_rust_already_installed))]
|
||||
#[error("{} Previous installation of Rust Toolchain exists in: '{0}'. Please, remove the directory before new installation.", emoji::ERROR)]
|
||||
XtensaToolchainAlreadyInstalled(String),
|
||||
#[diagnostic(code(espup::toolchain::rust::invalid_version))]
|
||||
#[error(
|
||||
"{} Invalid toolchain version '{0}', must be in the form of '<major>.<minor>.<patch>.<subpatch>'",
|
||||
emoji::ERROR
|
||||
)]
|
||||
InvalidXtensaToolchanVersion(String),
|
||||
#[diagnostic(code(espup::toolchain::rust::detection_error))]
|
||||
#[error("{} Error detecting rustup: {0}", emoji::ERROR)]
|
||||
RustupDetectionError(String),
|
||||
#[error(transparent)]
|
||||
CmdError(#[from] embuild::cmd::CmdError),
|
||||
// Toolchain - ESP-IDF
|
||||
#[diagnostic(code(espup::toolchain::espidf::failed_to_instatiate_cmake))]
|
||||
#[error("{} Failed to add CMake to ESP-IDF tools", emoji::ERROR)]
|
||||
FailedToInstantiateCmake,
|
||||
#[diagnostic(code(espup::toolchain::espidf::failed_to_create_esp_idf_install_closure))]
|
||||
#[error("{} Failed to create ESP-IDF install closure", emoji::ERROR)]
|
||||
FailedToCreateEspIdfInstallClosure,
|
||||
#[diagnostic(code(espup::toolchain::espidf::failed_to_install_esp_idf))]
|
||||
#[error("{} Failed to install ESP-IDF", emoji::ERROR)]
|
||||
FailedToInstallEspIdf,
|
||||
// Main
|
||||
#[diagnostic(code(espup::wrong_windows_arguments))]
|
||||
#[error(
|
||||
"{} When installing esp-idf in Windows, only --targets \"all\" is supported.",
|
||||
emoji::ERROR
|
||||
)]
|
||||
WrongWindowsArguments,
|
||||
#[diagnostic(code(espup::failed_to_remove_directory))]
|
||||
#[error(
|
||||
"{} Failed to remove '{0}' direcretory. Please, manually verify that the directory is properly removed.",
|
||||
emoji::ERROR
|
||||
)]
|
||||
FailedToRemoveDirectory(String),
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
use crate::emoji;
|
||||
use anyhow::{Context, Result};
|
||||
use crate::error::Error;
|
||||
use guess_host_triple::guess_host_triple;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
@ -30,17 +29,14 @@ pub enum HostTriple {
|
||||
}
|
||||
|
||||
/// Parse the host triple if specified, otherwise guess it.
|
||||
pub fn get_host_triple(host_triple_arg: Option<String>) -> Result<HostTriple> {
|
||||
if let Some(host_triple_arg) = host_triple_arg {
|
||||
HostTriple::from_str(&host_triple_arg).context(format!(
|
||||
"{} Host triple '{}' is not supported.",
|
||||
emoji::ERROR,
|
||||
host_triple_arg,
|
||||
))
|
||||
pub fn get_host_triple(host_triple_arg: Option<String>) -> Result<HostTriple, Error> {
|
||||
let host_triple = if let Some(host_triple) = &host_triple_arg {
|
||||
host_triple
|
||||
} else {
|
||||
HostTriple::from_str(guess_host_triple().unwrap())
|
||||
.context(format!("{} Unable to guess host triple.", emoji::ERROR,))
|
||||
}
|
||||
guess_host_triple().unwrap()
|
||||
};
|
||||
|
||||
HostTriple::from_str(host_triple).map_err(|_| Error::UnsupportedHostTriple(host_triple.into()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1,5 +1,6 @@
|
||||
pub mod config;
|
||||
pub mod emoji;
|
||||
pub mod error;
|
||||
pub mod host_triple;
|
||||
pub mod targets;
|
||||
pub mod toolchain;
|
||||
|
38
src/main.rs
38
src/main.rs
@ -1,4 +1,3 @@
|
||||
use anyhow::{bail, Result};
|
||||
use clap::Parser;
|
||||
use directories_next::ProjectDirs;
|
||||
use dirs::home_dir;
|
||||
@ -9,6 +8,7 @@ use embuild::{
|
||||
use espup::{
|
||||
config::Config,
|
||||
emoji,
|
||||
error::Error,
|
||||
host_triple::get_host_triple,
|
||||
logging::initialize_logger,
|
||||
targets::{parse_targets, Target},
|
||||
@ -25,6 +25,7 @@ use espup::{
|
||||
update::check_for_update,
|
||||
};
|
||||
use log::{debug, info, warn};
|
||||
use miette::Result;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
fs::{remove_dir_all, remove_file, File},
|
||||
@ -128,7 +129,7 @@ pub struct UninstallOpts {
|
||||
}
|
||||
|
||||
/// Installs the Rust for ESP chips environment
|
||||
fn install(args: InstallOpts) -> Result<()> {
|
||||
fn install(args: InstallOpts) -> Result<(), Error> {
|
||||
initialize_logger(&args.log_level);
|
||||
check_for_update(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
|
||||
info!("{} Installing esp-rs", emoji::DISC);
|
||||
@ -233,9 +234,7 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
targets,
|
||||
xtensa_rust,
|
||||
};
|
||||
if let Err(e) = config.save() {
|
||||
bail!("{} Failed to save config {:#}", emoji::ERROR, e);
|
||||
}
|
||||
config.save()?;
|
||||
|
||||
info!("{} Installation successfully completed!", emoji::CHECK);
|
||||
warn!(
|
||||
@ -246,7 +245,7 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Uninstalls the Rust for ESP chips environment
|
||||
fn uninstall(args: UninstallOpts) -> Result<()> {
|
||||
fn uninstall(args: UninstallOpts) -> Result<(), Error> {
|
||||
initialize_logger(&args.log_level);
|
||||
check_for_update(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
|
||||
|
||||
@ -304,7 +303,7 @@ fn uninstall(args: UninstallOpts) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Updates Xtensa Rust toolchain.
|
||||
fn update(args: UpdateOpts) -> Result<()> {
|
||||
fn update(args: UpdateOpts) -> Result<(), Error> {
|
||||
initialize_logger(&args.log_level);
|
||||
check_for_update(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
|
||||
|
||||
@ -343,15 +342,13 @@ fn update(args: UpdateOpts) -> Result<()> {
|
||||
config.xtensa_rust = Some(xtensa_rust);
|
||||
}
|
||||
|
||||
if let Err(e) = config.save() {
|
||||
bail!("{} Failed to save config {:#}", emoji::ERROR, e);
|
||||
}
|
||||
config.save()?;
|
||||
|
||||
info!("{} Update successfully completed!", emoji::CHECK);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
fn main() -> Result<(), Error> {
|
||||
match Cli::parse().subcommand {
|
||||
SubCommand::Install(args) => install(*args),
|
||||
SubCommand::Update(args) => update(args),
|
||||
@ -360,7 +357,7 @@ fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
/// Deletes dist folder.
|
||||
fn clear_dist_folder() -> Result<()> {
|
||||
fn clear_dist_folder() -> Result<(), Error> {
|
||||
let dist_path = PathBuf::from(get_dist_path(""));
|
||||
if dist_path.exists() {
|
||||
info!("{} Clearing dist folder", emoji::WRENCH);
|
||||
@ -370,7 +367,7 @@ fn clear_dist_folder() -> Result<()> {
|
||||
}
|
||||
|
||||
/// Returns the absolute path to the export file, uses the DEFAULT_EXPORT_FILE if no arg is provided.
|
||||
fn get_export_file(export_file: Option<PathBuf>) -> Result<PathBuf> {
|
||||
fn get_export_file(export_file: Option<PathBuf>) -> Result<PathBuf, Error> {
|
||||
if let Some(export_file) = export_file {
|
||||
if export_file.is_absolute() {
|
||||
Ok(export_file)
|
||||
@ -385,7 +382,7 @@ fn get_export_file(export_file: Option<PathBuf>) -> Result<PathBuf> {
|
||||
}
|
||||
|
||||
/// Creates the export file with the necessary environment variables.
|
||||
fn export_environment(export_file: &PathBuf, exports: &[String]) -> Result<()> {
|
||||
fn export_environment(export_file: &PathBuf, exports: &[String]) -> Result<(), Error> {
|
||||
info!("{} Creating export file", emoji::WRENCH);
|
||||
let mut file = File::create(export_file)?;
|
||||
for e in exports.iter() {
|
||||
@ -413,17 +410,18 @@ fn export_environment(export_file: &PathBuf, exports: &[String]) -> Result<()> {
|
||||
|
||||
#[cfg(windows)]
|
||||
/// For Windows, we need to check that we are installing all the targets if we are installing esp-idf.
|
||||
pub fn check_arguments(targets: &HashSet<Target>, esp_idf_version: &Option<String>) -> Result<()> {
|
||||
if esp_idf_version.is_some()
|
||||
|
||||
pub fn check_arguments(
|
||||
targets: &HashSet<Target>,
|
||||
espidf_version: &Option<String>,
|
||||
) -> Result<(), Error> {
|
||||
if espidf_version.is_some()
|
||||
&& (!targets.contains(&Target::ESP32)
|
||||
|| !targets.contains(&Target::ESP32C3)
|
||||
|| !targets.contains(&Target::ESP32S2)
|
||||
|| !targets.contains(&Target::ESP32S3))
|
||||
{
|
||||
bail!(
|
||||
"{} When installing esp-idf in Windows, only --targets \"all\" is supported.",
|
||||
emoji::ERROR
|
||||
);
|
||||
return Err(Error::WrongWindowsArguments);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -1,7 +1,6 @@
|
||||
//! ESP32 chip variants support.
|
||||
|
||||
use crate::emoji;
|
||||
use anyhow::Context;
|
||||
use crate::{emoji, error::Error};
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashSet, str::FromStr};
|
||||
@ -26,7 +25,7 @@ pub enum Target {
|
||||
}
|
||||
|
||||
/// Returns a vector of Chips from a comma or space separated string.
|
||||
pub fn parse_targets(targets_str: &str) -> Result<HashSet<Target>, String> {
|
||||
pub fn parse_targets(targets_str: &str) -> Result<HashSet<Target>, Error> {
|
||||
debug!("{} Parsing targets: {}", emoji::DEBUG, targets_str);
|
||||
|
||||
let targets_str = targets_str.to_lowercase();
|
||||
@ -35,18 +34,14 @@ pub fn parse_targets(targets_str: &str) -> Result<HashSet<Target>, String> {
|
||||
let targets: HashSet<Target> = if targets_str.contains("all") {
|
||||
Target::iter().collect()
|
||||
} else {
|
||||
targets_str
|
||||
.split([',', ' '])
|
||||
.map(|target| {
|
||||
Target::from_str(target)
|
||||
.context(format!(
|
||||
"{} Target '{}' is not supported",
|
||||
emoji::ERROR,
|
||||
target
|
||||
))
|
||||
.unwrap()
|
||||
})
|
||||
.collect()
|
||||
let mut targets = HashSet::new();
|
||||
for target in targets_str.split([',', ' ']) {
|
||||
targets.insert(
|
||||
Target::from_str(target).map_err(|_| Error::UnsupportedTarget(target.into()))?,
|
||||
);
|
||||
}
|
||||
|
||||
targets
|
||||
};
|
||||
|
||||
debug!("{} Parsed targets: {:?}", emoji::DEBUG, targets);
|
||||
@ -56,38 +51,33 @@ pub fn parse_targets(targets_str: &str) -> Result<HashSet<Target>, String> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::targets::{parse_targets, Target};
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[test]
|
||||
#[allow(unused_variables)]
|
||||
fn test_parse_targets() {
|
||||
assert_eq!(
|
||||
parse_targets("esp32"),
|
||||
Ok([Target::ESP32].into_iter().collect())
|
||||
);
|
||||
assert_eq!(
|
||||
parse_targets("esp32,esp32s2"),
|
||||
Ok([Target::ESP32, Target::ESP32S2].into_iter().collect())
|
||||
);
|
||||
assert_eq!(
|
||||
parse_targets("esp32s3 esp32"),
|
||||
Ok([Target::ESP32S3, Target::ESP32].into_iter().collect())
|
||||
);
|
||||
assert_eq!(
|
||||
parse_targets("esp32s3,esp32,esp32c3"),
|
||||
Ok([Target::ESP32S3, Target::ESP32, Target::ESP32C3]
|
||||
.into_iter()
|
||||
.collect())
|
||||
);
|
||||
assert_eq!(
|
||||
parse_targets("all"),
|
||||
Ok([
|
||||
Target::ESP32,
|
||||
Target::ESP32S2,
|
||||
Target::ESP32S3,
|
||||
Target::ESP32C2,
|
||||
Target::ESP32C3,
|
||||
]
|
||||
let targets: HashSet<Target> = [Target::ESP32].into_iter().collect();
|
||||
assert!(matches!(parse_targets("esp32"), Ok(targets)));
|
||||
let targets: HashSet<Target> = [Target::ESP32, Target::ESP32S2].into_iter().collect();
|
||||
assert!(matches!(parse_targets("esp32,esp32s2"), Ok(targets)));
|
||||
let targets: HashSet<Target> = [Target::ESP32S3, Target::ESP32].into_iter().collect();
|
||||
assert!(matches!(parse_targets("esp32s3 esp32"), Ok(targets)));
|
||||
let targets: HashSet<Target> = [Target::ESP32S3, Target::ESP32, Target::ESP32C3]
|
||||
.into_iter()
|
||||
.collect())
|
||||
);
|
||||
.collect();
|
||||
assert!(matches!(
|
||||
parse_targets("esp32s3,esp32,esp32c3"),
|
||||
Ok(targets)
|
||||
));
|
||||
let targets: HashSet<Target> = [
|
||||
Target::ESP32,
|
||||
Target::ESP32S2,
|
||||
Target::ESP32S3,
|
||||
Target::ESP32C2,
|
||||
Target::ESP32C3,
|
||||
]
|
||||
.into_iter()
|
||||
.collect();
|
||||
assert!(matches!(parse_targets("all"), Ok(targets)));
|
||||
}
|
||||
}
|
||||
|
@ -2,18 +2,19 @@
|
||||
|
||||
use crate::{
|
||||
emoji,
|
||||
error::Error,
|
||||
targets::Target,
|
||||
toolchain::{
|
||||
gcc::{get_toolchain_name, get_ulp_toolchain_name},
|
||||
get_home_dir,
|
||||
},
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
use embuild::{espidf, espidf::EspIdfRemote, git};
|
||||
use log::{debug, info};
|
||||
use std::collections::HashSet;
|
||||
use miette::Result;
|
||||
use std::{
|
||||
collections::hash_map::DefaultHasher,
|
||||
collections::HashSet,
|
||||
env,
|
||||
fs::remove_dir_all,
|
||||
hash::{Hash, Hasher},
|
||||
@ -64,18 +65,22 @@ pub struct EspIdfRepo {
|
||||
|
||||
impl EspIdfRepo {
|
||||
/// Installs esp-idf.
|
||||
pub fn install(self) -> Result<Vec<String>> {
|
||||
pub fn install(self) -> Result<Vec<String>, Error> {
|
||||
let cmake_generator = DEFAULT_CMAKE_GENERATOR;
|
||||
let mut exports: Vec<String> = Vec::new();
|
||||
|
||||
// A closure to specify which tools `idf-tools.py` should install.
|
||||
let make_tools = move |repo: &git::Repository,
|
||||
version: &Result<espidf::EspIdfVersion>|
|
||||
-> Result<Vec<espidf::Tools>> {
|
||||
version: &anyhow::Result<espidf::EspIdfVersion>|
|
||||
-> anyhow::Result<Vec<espidf::Tools>> {
|
||||
let version_str = match version {
|
||||
Ok(v) => format!("v{v}"),
|
||||
Err(_) => "(unknown version)".to_string(),
|
||||
};
|
||||
info!(
|
||||
"{} Using esp-idf {} at '{}'",
|
||||
emoji::INFO,
|
||||
espidf::EspIdfVersion::format(version),
|
||||
version_str,
|
||||
repo.worktree().display()
|
||||
);
|
||||
|
||||
@ -99,7 +104,8 @@ impl EspIdfRepo {
|
||||
subtools.push("cmake".to_string())
|
||||
}
|
||||
_ => {
|
||||
tools.push(espidf::Tools::cmake()?);
|
||||
tools
|
||||
.push(espidf::Tools::cmake().map_err(|_| Error::FailedToInstantiateCmake)?);
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
@ -119,13 +125,15 @@ impl EspIdfRepo {
|
||||
|
||||
Ok(tools)
|
||||
};
|
||||
let install = |esp_idf_origin: espidf::EspIdfOrigin| -> Result<espidf::EspIdf> {
|
||||
espidf::Installer::new(esp_idf_origin)
|
||||
.install_dir(Some(self.install_path.clone()))
|
||||
.with_tools(make_tools)
|
||||
.install()
|
||||
.context("Could not install esp-idf")
|
||||
};
|
||||
|
||||
let install =
|
||||
|esp_idf_origin: espidf::EspIdfOrigin| -> anyhow::Result<espidf::EspIdf, Error> {
|
||||
espidf::Installer::new(esp_idf_origin)
|
||||
.install_dir(Some(self.install_path.clone()))
|
||||
.with_tools(make_tools)
|
||||
.install()
|
||||
.map_err(|_| Error::FailedToCreateEspIdfInstallClosure)
|
||||
};
|
||||
|
||||
let repo = espidf::EspIdfRemote {
|
||||
git_ref: espidf::parse_esp_idf_git_ref(&self.version),
|
||||
@ -134,7 +142,7 @@ impl EspIdfRepo {
|
||||
|
||||
let espidf_origin = espidf::EspIdfOrigin::Managed(repo.clone());
|
||||
#[cfg(unix)]
|
||||
let espidf = install(espidf_origin)?;
|
||||
let espidf = install(espidf_origin).map_err(|_| Error::FailedToInstallEspIdf)?;
|
||||
#[cfg(windows)]
|
||||
install(espidf_origin)?;
|
||||
let espidf_dir = get_install_path(repo);
|
||||
|
@ -2,13 +2,14 @@
|
||||
|
||||
use crate::{
|
||||
emoji,
|
||||
error::Error,
|
||||
host_triple::HostTriple,
|
||||
targets::Target,
|
||||
toolchain::{download_file, espidf::get_tool_path},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use embuild::espidf::EspIdfVersion;
|
||||
use log::{debug, info, warn};
|
||||
use miette::Result;
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
path::{Path, PathBuf},
|
||||
@ -43,7 +44,7 @@ impl Gcc {
|
||||
}
|
||||
|
||||
/// Installs the gcc toolchain.
|
||||
pub fn install(&self) -> Result<()> {
|
||||
pub fn install(&self) -> Result<(), Error> {
|
||||
let target_dir = format!("{}/{}-{}", self.toolchain_name, self.release, self.version);
|
||||
let gcc_path = get_tool_path(&target_dir);
|
||||
let extension = get_artifact_extension(&self.host_triple);
|
||||
@ -140,7 +141,7 @@ pub fn get_ulp_toolchain_name(target: Target, version: Option<&EspIdfVersion>) -
|
||||
pub fn install_gcc_targets(
|
||||
targets: &HashSet<Target>,
|
||||
host_triple: &HostTriple,
|
||||
) -> Result<Vec<String>> {
|
||||
) -> Result<Vec<String>, Error> {
|
||||
info!("{} Installing gcc for build targets", emoji::WRENCH);
|
||||
let mut exports: Vec<String> = Vec::new();
|
||||
for target in targets {
|
||||
|
@ -2,11 +2,12 @@
|
||||
|
||||
use crate::{
|
||||
emoji,
|
||||
error::Error,
|
||||
host_triple::HostTriple,
|
||||
toolchain::{download_file, espidf::get_tool_path},
|
||||
};
|
||||
use anyhow::{Ok, Result};
|
||||
use log::{info, warn};
|
||||
use miette::Result;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const DEFAULT_LLVM_REPOSITORY: &str = "https://github.com/espressif/llvm-project/releases/download";
|
||||
@ -48,7 +49,7 @@ impl Llvm {
|
||||
}
|
||||
|
||||
/// Installs the LLVM toolchain.
|
||||
pub fn install(&self) -> Result<Vec<String>> {
|
||||
pub fn install(&self) -> Result<Vec<String>, Error> {
|
||||
let mut exports: Vec<String> = Vec::new();
|
||||
|
||||
if Path::new(&self.path).exists() {
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::emoji;
|
||||
use anyhow::{bail, Result};
|
||||
use crate::{emoji, error::Error};
|
||||
use dirs::home_dir;
|
||||
use flate2::bufread::GzDecoder;
|
||||
use log::info;
|
||||
use miette::Result;
|
||||
use std::{
|
||||
fs::{create_dir_all, File},
|
||||
io::{copy, BufReader},
|
||||
@ -27,7 +27,7 @@ pub fn download_file(
|
||||
file_name: &str,
|
||||
output_directory: &str,
|
||||
uncompress: bool,
|
||||
) -> Result<String> {
|
||||
) -> Result<String, Error> {
|
||||
let file_path = format!("{}/{}", output_directory, file_name);
|
||||
if Path::new(&file_path).exists() {
|
||||
info!("{} Using cached file: '{}'", emoji::INFO, file_path);
|
||||
@ -39,11 +39,7 @@ pub fn download_file(
|
||||
output_directory
|
||||
);
|
||||
if let Err(_e) = create_dir_all(output_directory) {
|
||||
bail!(
|
||||
"{} Creating directory '{}' failed",
|
||||
emoji::ERROR,
|
||||
output_directory
|
||||
);
|
||||
return Err(Error::FailedToCreateDirectory(output_directory.to_string()));
|
||||
}
|
||||
}
|
||||
info!(
|
||||
@ -86,11 +82,7 @@ pub fn download_file(
|
||||
archive.unpack(output_directory).unwrap();
|
||||
}
|
||||
_ => {
|
||||
bail!(
|
||||
"{} Unsuported file extension: '{}'",
|
||||
emoji::ERROR,
|
||||
extension
|
||||
);
|
||||
return Err(Error::UnsuportedFileExtension(extension.to_string()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2,12 +2,13 @@
|
||||
|
||||
use crate::{
|
||||
emoji,
|
||||
error::Error,
|
||||
host_triple::HostTriple,
|
||||
toolchain::{download_file, espidf::get_dist_path, get_home_dir},
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
use embuild::cmd;
|
||||
use log::{debug, info, warn};
|
||||
use miette::Result;
|
||||
use regex::Regex;
|
||||
use reqwest::header;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -48,7 +49,7 @@ pub struct XtensaRust {
|
||||
|
||||
impl XtensaRust {
|
||||
/// Get the latest version of Xtensa Rust toolchain.
|
||||
pub fn get_latest_version() -> Result<String> {
|
||||
pub fn get_latest_version() -> Result<String, Error> {
|
||||
let mut headers = header::HeaderMap::new();
|
||||
headers.insert("Accept", "application/vnd.github.v3+json".parse().unwrap());
|
||||
|
||||
@ -62,7 +63,8 @@ impl XtensaRust {
|
||||
.headers(headers)
|
||||
.send()?
|
||||
.text()?;
|
||||
let json: serde_json::Value = serde_json::from_str(&res)?;
|
||||
let json: serde_json::Value =
|
||||
serde_json::from_str(&res).map_err(|_| Error::FailedToSerializeJson)?;
|
||||
let mut version = json["tag_name"].to_string();
|
||||
|
||||
version.retain(|c| c != 'v' && c != '"');
|
||||
@ -72,17 +74,15 @@ impl XtensaRust {
|
||||
}
|
||||
|
||||
/// Installs the Xtensa Rust toolchain.
|
||||
pub fn install(&self) -> Result<()> {
|
||||
pub fn install(&self) -> Result<(), Error> {
|
||||
#[cfg(unix)]
|
||||
let toolchain_path = self.toolchain_destination.clone();
|
||||
#[cfg(windows)]
|
||||
let toolchain_path = self.toolchain_destination.clone().join("esp");
|
||||
if toolchain_path.exists() {
|
||||
bail!(
|
||||
"{} The previous installation of Rust Toolchain exists in: '{}'. Please, remove the directory before the new installation.",
|
||||
emoji::WARN,
|
||||
toolchain_path.display()
|
||||
);
|
||||
return Err(Error::XtensaToolchainAlreadyInstalled(
|
||||
toolchain_path.display().to_string(),
|
||||
));
|
||||
}
|
||||
info!(
|
||||
"{} Installing Xtensa Rust {} toolchain",
|
||||
@ -178,20 +178,17 @@ impl XtensaRust {
|
||||
}
|
||||
|
||||
/// Parses the version of the Xtensa toolchain.
|
||||
pub fn parse_version(arg: &str) -> Result<String> {
|
||||
pub fn parse_version(arg: &str) -> Result<String, Error> {
|
||||
debug!("{} Parsing Xtensa Rust version: {}", emoji::DEBUG, arg);
|
||||
let re = Regex::new(RE_TOOLCHAIN_VERSION).unwrap();
|
||||
if !re.is_match(arg) {
|
||||
bail!(
|
||||
"{} Invalid toolchain version, must be in the form of '<major>.<minor>.<patch>.<subpatch>'",
|
||||
emoji::ERROR
|
||||
);
|
||||
return Err(Error::InvalidXtensaToolchanVersion(arg.to_string()));
|
||||
}
|
||||
Ok(arg.to_string())
|
||||
}
|
||||
|
||||
/// Removes the Xtensa Rust toolchain.
|
||||
pub fn uninstall(&self) -> Result<()> {
|
||||
pub fn uninstall(&self) -> Result<(), Error> {
|
||||
info!("{} Uninstalling Xtensa Rust toolchain", emoji::WRENCH);
|
||||
remove_dir_all(&self.toolchain_destination)?;
|
||||
Ok(())
|
||||
@ -206,7 +203,7 @@ pub struct Crate {
|
||||
|
||||
impl Crate {
|
||||
/// Installs a crate.
|
||||
pub fn install(&self) -> Result<()> {
|
||||
pub fn install(&self) -> Result<(), Error> {
|
||||
#[cfg(unix)]
|
||||
let crate_path = format!("{}/bin/{}", get_cargo_home().display(), self.name);
|
||||
#[cfg(windows)]
|
||||
@ -233,7 +230,7 @@ impl Crate {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn install_extra_crates(crates: &HashSet<Crate>) -> Result<()> {
|
||||
pub fn install_extra_crates(crates: &HashSet<Crate>) -> Result<(), Error> {
|
||||
debug!(
|
||||
"{} Installing the following crates: {:#?}",
|
||||
emoji::DEBUG,
|
||||
@ -263,8 +260,8 @@ pub fn get_rustup_home() -> PathBuf {
|
||||
}
|
||||
|
||||
/// Checks if rustup and the proper nightly version are installed. If rustup is not installed,
|
||||
/// it bails. If nigthly version is not installed, proceed to install it.
|
||||
pub fn check_rust_installation(nightly_version: &str) -> Result<()> {
|
||||
/// it returns an error. If nigthly version is not installed, proceed to install it.
|
||||
pub fn check_rust_installation(nightly_version: &str) -> Result<(), Error> {
|
||||
info!("{} Checking existing Rust installation", emoji::WRENCH);
|
||||
|
||||
match cmd!("rustup", "toolchain", "list")
|
||||
@ -284,7 +281,7 @@ pub fn check_rust_installation(nightly_version: &str) -> Result<()> {
|
||||
warn!("{} rustup was not found.", emoji::WARN);
|
||||
install_rustup(nightly_version)?;
|
||||
} else {
|
||||
bail!("{} Error detecting rustup: {}", emoji::ERROR, e);
|
||||
return Err(Error::RustupDetectionError(e.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -293,7 +290,7 @@ pub fn check_rust_installation(nightly_version: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Installs rustup
|
||||
fn install_rustup(nightly_version: &str) -> Result<()> {
|
||||
fn install_rustup(nightly_version: &str) -> Result<(), Error> {
|
||||
#[cfg(windows)]
|
||||
let rustup_init_path = download_file(
|
||||
"https://win.rustup.rs/x86_64".to_string(),
|
||||
@ -359,7 +356,7 @@ fn install_rustup(nightly_version: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Installs the RiscV target.
|
||||
pub fn install_riscv_target(nightly_version: &str) -> Result<()> {
|
||||
pub fn install_riscv_target(nightly_version: &str) -> Result<(), Error> {
|
||||
info!("{} Installing Riscv target", emoji::WRENCH);
|
||||
cmd!(
|
||||
"rustup",
|
||||
@ -383,7 +380,7 @@ pub fn install_riscv_target(nightly_version: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Installs the desired version of the nightly toolchain.
|
||||
fn install_rust_nightly(version: &str) -> Result<()> {
|
||||
fn install_rust_nightly(version: &str) -> Result<(), Error> {
|
||||
info!("{} Installing {} toolchain", emoji::WRENCH, version);
|
||||
cmd!(
|
||||
"rustup",
|
||||
|
Loading…
x
Reference in New Issue
Block a user