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