diff --git a/Cargo.lock b/Cargo.lock index 758640e..4e248d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,9 +31,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.65" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" [[package]] name = "atty" @@ -144,9 +144,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.15" +version = "4.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf8832993da70a4c6d13c581f4463c2bdda27b9bf1c5498dc4365543abe6d6f" +checksum = "335867764ed2de42325fafe6d18b8af74ba97ee0c590fa016f157535b42ab04b" dependencies = [ "atty", "bitflags", @@ -159,9 +159,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.0.13" +version = "4.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f169caba89a7d512b5418b09864543eeb4d497416c917d7137863bd2076ad" +checksum = "16a1b0f6422af32d5da0c58e2703320f379216ee70198241c84173a8c5ac28f3" dependencies = [ "heck", "proc-macro-error", @@ -297,6 +297,16 @@ dependencies = [ "subtle", ] +[[package]] +name = "directories-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + [[package]] name = "dirs" version = "4.0.0" @@ -317,6 +327,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "either" version = "1.8.0" @@ -400,18 +421,23 @@ dependencies = [ "anyhow", "clap", "console", + "directories-next", "dirs", "embuild", "env_logger", "flate2", "guess_host_triple", "log", + "miette", "openssl", + "regex", "reqwest", + "serde", "strum", "strum_macros", "tar", "tempfile", + "toml", "xz2", "zip", ] @@ -790,6 +816,29 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miette" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28d6092d7e94a90bb9ea8e6c26c99d5d112d49dda2afdb4f7ea8cf09e1a5a6d" +dependencies = [ + "miette-derive", + "once_cell", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2485ed7d1fe80704928e3eb86387439609bd0c6bb96db8208daa364cfd1e09" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "mime" version = "0.3.16" @@ -1195,18 +1244,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.145" +version = "1.0.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +checksum = "6df50b7a60a0ad48e1b42eb38373eac8ff785d619fb14db917b4e63d5439361f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.145" +version = "1.0.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +checksum = "a714fd32ba1d66047ce7d53dabd809e9922d538f9047de13cc4cffca47b36205" dependencies = [ "proc-macro2", "quote", @@ -1466,6 +1515,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + [[package]] name = "tower-service" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index f2f69c4..1db7143 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,11 @@ Tool for installing and maintaining ESP Rust environment. """ keywords = ["esp", "esp-rs", "embedded", "cli", "xtensa", "espidf"] categories = ["command-line-utilities", "development-tools", "embedded"] +rust-version = "1.62" [dependencies] anyhow = "*" -clap = { version = "4.0.15", features = ["derive"] } +clap = { version = "4.0.18", features = ["derive"] } dirs = "*" flate2 = "1.0.22" guess_host_triple = "0.1.3" @@ -29,6 +30,11 @@ env_logger = "0.9.0" embuild = { version = "0.30.4", features = ["espidf", "git"] } strum = { version = "0.24", features = ["derive"] } strum_macros = "0.24.3" +toml = "0.5.9" +directories-next = "2.0.0" +serde = { version = "1.0.146", features = ["derive"] } +miette = "5.3.0" +regex = "1.6.0" [target.aarch64-unknown-linux-gnu.dependencies] openssl = { version = "0.10", features = ["vendored"] } @@ -39,5 +45,5 @@ bin-dir = "{ bin }{ binary-ext }" pkg-fmt = "zip" [profile.release] -lto = "thin" +lto = "thin" strip = true diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..403e302 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,61 @@ +use crate::{host_triple::HostTriple, targets::Target, toolchain::rust_toolchain::RustToolchain}; +use directories_next::ProjectDirs; +use miette::{ErrReport, IntoDiagnostic, Result, WrapErr}; +use serde::{Deserialize, Serialize}; +use std::{ + collections::HashSet, + fs::{create_dir_all, read, write}, + path::PathBuf, +}; + +/// Deserialized contents of a configuration file +#[derive(Debug, Deserialize, Serialize, Default, Clone)] +pub struct Config { + // /// ESP-IDF version + pub espidf_version: Option, + /// Destination of the generated export file. + pub export_file: PathBuf, + /// Extra crates to installed. + pub extra_crates: HashSet, + /// Host triple + pub host_triple: HostTriple, + /// LLVM toolchain path. + pub llvm_path: PathBuf, + /// Nightly Rust toolchain version. + pub nightly_version: String, + /// List of targets instaled. + pub targets: HashSet, + /// Xtensa Rust toolchain. + pub xtensa_toolchain: RustToolchain, +} + +impl Config { + /// Load the config from config file + pub fn load() -> Result { + 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()? + } else { + return Err(ErrReport::msg("No config file found")); + }; + Ok(config) + } + + /// Save the config to file + pub fn save(&self) -> Result<()> { + 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")?; + create_dir_all(file.parent().unwrap()) + .into_diagnostic() + .wrap_err("Failed to create config directory")?; + write(&file, serialized) + .into_diagnostic() + .wrap_err_with(|| format!("Failed to write config to {}", file.display())) + } +} diff --git a/src/host_triple.rs b/src/host_triple.rs index 44e533f..5f16ccd 100644 --- a/src/host_triple.rs +++ b/src/host_triple.rs @@ -1,15 +1,17 @@ use crate::emoji; use anyhow::{Context, Result}; use guess_host_triple::guess_host_triple; +use serde::{Deserialize, Serialize}; use std::str::FromStr; use strum::Display; use strum_macros::EnumString; -#[derive(Display, Debug, Clone, EnumString)] +#[derive(Display, Debug, Clone, EnumString, Deserialize, Serialize, Default)] pub enum HostTriple { /// 64-bit Linux #[strum(serialize = "x86_64-unknown-linux-gnu")] - X86_64UnknownLinuxGnu = 0, + #[default] + X86_64UnknownLinuxGnu, /// ARM64 Linux #[strum(serialize = "aarch64-unknown-linux-gnu")] Aarch64UnknownLinuxGnu, diff --git a/src/lib.rs b/src/lib.rs index 106ebee..c319d8f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +pub mod config; pub mod emoji; pub mod host_triple; pub mod targets; diff --git a/src/main.rs b/src/main.rs index 21905b5..f80f62e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,12 @@ -#[cfg(windows)] -use anyhow::bail; -use anyhow::Result; +use anyhow::{bail, Result}; use clap::Parser; -use embuild::espidf::{parse_esp_idf_git_ref, EspIdfRemote}; +use directories_next::ProjectDirs; +use embuild::{ + cmd, + espidf::{parse_esp_idf_git_ref, EspIdfRemote}, +}; use espup::{ + config::Config, emoji, host_triple::get_host_triple, logging::initialize_logger, @@ -12,26 +15,29 @@ use espup::{ espidf::{ get_dist_path, get_install_path, get_tool_path, EspIdfRepo, DEFAULT_GIT_REPOSITORY, }, - gcc_toolchain::install_gcc_targets, + gcc_toolchain::{get_toolchain_name, install_gcc_targets}, llvm_toolchain::LlvmToolchain, - rust_toolchain::{ - check_rust_installation, get_rustup_home, install_riscv_target, RustCrate, - RustToolchain, - }, + rust_toolchain::{check_rust_installation, install_riscv_target, RustCrate, RustToolchain}, }, }; use log::{debug, info, warn}; +use regex::Regex; use std::{ collections::HashSet, - fs::{remove_dir_all, File}, + fs::{remove_dir_all, remove_file, File}, io::Write, - path::PathBuf, + path::{Path, PathBuf}, }; #[cfg(windows)] const DEFAULT_EXPORT_FILE: &str = "export-esp.ps1"; #[cfg(not(windows))] const DEFAULT_EXPORT_FILE: &str = "export-esp.sh"; +/// Xtensa Toolchain version regex. +const RE_TOOLCHAIN_VERSION: &str = r"^(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)?$"; +/// Latest Xtensa Toolchain version. +const LATEST_TOOLCHAIN_VERSION: &str = "1.64.0.0"; + #[derive(Parser)] #[command( name = "espup", @@ -96,7 +102,7 @@ pub struct InstallOpts { #[arg(short = 't', long, default_value = "all")] pub targets: String, /// Xtensa Rust toolchain version. - #[arg(short = 'v', long, default_value = "1.64.0.0")] + #[arg(short = 'v', long, default_value = LATEST_TOOLCHAIN_VERSION, value_parser = parse_version)] pub toolchain_version: String, } @@ -109,34 +115,30 @@ pub struct UpdateOpts { #[arg(short = 'l', long, default_value = "info", value_parser = ["debug", "info", "warn", "error"])] pub log_level: String, /// Xtensa Rust toolchain version. - #[arg(short = 'v', long, default_value = "1.64.0.0")] - pub toolchain_version: String, + #[arg(short = 'v', long, default_value = LATEST_TOOLCHAIN_VERSION, value_parser = parse_version)] + pub toolchain_version: Option, } #[derive(Debug, Parser)] pub struct UninstallOpts { - /// ESP-IDF version to uninstall. If empty, no esp-idf is uninstalled. Version format: - /// - /// - `commit:`: Uses the commit `` of the `esp-idf` repository. - /// - /// - `tag:`: Uses the tag `` of the `esp-idf` repository. - /// - /// - `branch:`: Uses the branch `` of the `esp-idf` repository. - /// - /// - `v.` or `.`: Uses the tag `v.` of the `esp-idf` repository. - /// - /// - ``: Uses the branch `` of the `esp-idf` repository. - #[arg(short = 'e', long, required = false)] - pub espidf_version: Option, /// Verbosity level of the logs. #[arg(short = 'l', long, default_value = "info", value_parser = ["debug", "info", "warn", "error"])] pub log_level: String, - /// Removes clang. - #[arg(short = 'c', long)] - pub remove_clang: bool, } -/// Installs esp-rs environment +/// Parses the version of the Xtensa toolchain. +fn parse_version(arg: &str) -> Result { + let re = Regex::new(RE_TOOLCHAIN_VERSION).unwrap(); + if !re.is_match(arg) { + bail!( + "{} Invalid toolchain version, must be in the form of '...'", + emoji::ERROR + ); + } + Ok(arg.to_string()) +} + +/// Installs the Rust for ESP chips environment fn install(args: InstallOpts) -> Result<()> { initialize_logger(&args.log_level); @@ -167,7 +169,7 @@ fn install(args: InstallOpts) -> Result<()> { targets, &args.espidf_version, export_file, - extra_crates, + &extra_crates, llvm, &args.nightly_version, rust_toolchain, @@ -189,11 +191,11 @@ fn install(args: InstallOpts) -> Result<()> { } if let Some(espidf_version) = &args.espidf_version { - let repo = EspIdfRepo::new(espidf_version, args.profile_minimal, targets); + let repo = EspIdfRepo::new(espidf_version, args.profile_minimal, &targets); exports.extend(repo.install()?); extra_crates.insert(RustCrate::new("ldproxy")); } else { - exports.extend(install_gcc_targets(targets, &host_triple)?); + exports.extend(install_gcc_targets(&targets, &host_triple)?); } debug!( @@ -201,7 +203,7 @@ fn install(args: InstallOpts) -> Result<()> { emoji::DEBUG, extra_crates ); - for extra_crate in extra_crates { + for extra_crate in &extra_crates { extra_crate.install()?; } @@ -211,6 +213,24 @@ fn install(args: InstallOpts) -> Result<()> { export_environment(&export_file, &exports)?; + let config = Config { + espidf_version: args.espidf_version, + export_file, + extra_crates: extra_crates + .iter() + .map(|x| x.name.clone()) + .collect::>(), + host_triple, + llvm_path: llvm.path, + nightly_version: args.nightly_version, + targets, + xtensa_toolchain: rust_toolchain, + }; + + if let Err(e) = config.save() { + bail!("{} Failed to save config {:#}", emoji::ERROR, e); + } + info!("{} Installation suscesfully completed!", emoji::CHECK); warn!( "{} Please, source the export file, as state above, to properly setup the environment!", @@ -219,64 +239,102 @@ fn install(args: InstallOpts) -> Result<()> { Ok(()) } -/// Uninstalls esp-rs environment +/// Uninstalls the Rust for ESP chips environment fn uninstall(args: UninstallOpts) -> Result<()> { initialize_logger(&args.log_level); info!("{} Uninstalling esp-rs", emoji::DISC); + let config = Config::load().unwrap(); debug!( "{} Arguments: - - Remove Clang: {} - - ESP-IDF version: {:#?}", + - Config: {:#?}", emoji::INFO, - &args.remove_clang, - &args.espidf_version, + config ); info!("{} Deleting Xtensa Rust toolchain", emoji::WRENCH); - remove_dir_all(get_rustup_home().join("toolchains").join("esp"))?; + remove_dir_all(config.xtensa_toolchain.toolchain_destination)?; - if args.remove_clang { - info!("{} Deleting Xtensa Clang", emoji::WRENCH); - remove_dir_all(PathBuf::from(get_tool_path("")).join("xtensa-esp32-elf-clang"))?; + info!("{} Deleting Xtensa LLVM", emoji::WRENCH); + remove_dir_all(config.llvm_path)?; + + if let Some(espidf_version) = config.espidf_version { + info!("{} Deleting ESP-IDF {}", emoji::WRENCH, espidf_version); + let repo = EspIdfRemote { + git_ref: parse_esp_idf_git_ref(&espidf_version), + repo_url: Some(DEFAULT_GIT_REPOSITORY.to_string()), + }; + remove_dir_all(get_install_path(repo).parent().unwrap())?; + } else { + info!("{} Deleting GCC targets", emoji::WRENCH); + for target in &config.targets { + let gcc_path = get_tool_path(&get_toolchain_name(target)); + remove_dir_all(gcc_path)?; + } + } + + info!("{} Uninstalling extra crates", emoji::WRENCH); + for extra_crate in &config.extra_crates { + cmd!("cargo", "uninstall", extra_crate).run()?; } clear_dist_folder()?; - if let Some(espidf_version) = &args.espidf_version { - info!("{} Deleting ESP-IDF", emoji::WRENCH); - let repo = EspIdfRemote { - git_ref: parse_esp_idf_git_ref(espidf_version), - repo_url: Some(DEFAULT_GIT_REPOSITORY.to_string()), - }; - remove_dir_all(get_install_path(repo).parent().unwrap())?; - } + info!("{} Deleting export file", emoji::WRENCH); + remove_file(Path::new(&config.export_file))?; + + info!("{} Deleting config file", emoji::WRENCH); + let conf_dirs = ProjectDirs::from("rs", "esp", "espup").unwrap(); + let conf_file = conf_dirs.config_dir().join("espup.toml"); + remove_file(conf_file)?; info!("{} Uninstallation suscesfully completed!", emoji::CHECK); Ok(()) } -/// Updates Xtensa Rust toolchain +/// Updates Xtensa Rust toolchain. fn update(args: UpdateOpts) -> Result<()> { initialize_logger(&args.log_level); info!("{} Updating Xtensa Rust toolchain", emoji::DISC); let host_triple = get_host_triple(args.default_host)?; + let mut config = Config::load().unwrap(); + let rust_toolchain: RustToolchain; + if let Some(toolchain_version) = args.toolchain_version { + rust_toolchain = RustToolchain::new(&toolchain_version, &host_triple); + } else { + rust_toolchain = RustToolchain::new(LATEST_TOOLCHAIN_VERSION, &host_triple); + } debug!( "{} Arguments: - Host triple: {} - - Toolchain version: {}", + - Toolchain version: {:#?} + - Config: {:#?}", emoji::INFO, host_triple, - &args.toolchain_version, + rust_toolchain, + config ); + if rust_toolchain.version == config.xtensa_toolchain.version { + info!( + "{} Toolchain '{}' is already up to date", + emoji::CHECK, + rust_toolchain.version + ); + return Ok(()); + } info!("{} Deleting previous Xtensa Rust toolchain", emoji::WRENCH); - remove_dir_all(get_rustup_home().join("toolchains").join("esp"))?; + remove_dir_all(&config.xtensa_toolchain.toolchain_destination)?; - let rust_toolchain = RustToolchain::new(&args.toolchain_version, &host_triple); rust_toolchain.install_xtensa_rust()?; + config.xtensa_toolchain = rust_toolchain; + + if let Err(e) = config.save() { + bail!("{} Failed to save config {:#}", emoji::ERROR, e); + } + info!("{} Update suscesfully completed!", emoji::CHECK); Ok(()) } diff --git a/src/targets.rs b/src/targets.rs index d1f8434..db27042 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -3,11 +3,12 @@ use crate::emoji; use anyhow::Context; use log::debug; +use serde::{Deserialize, Serialize}; use std::{collections::HashSet, str::FromStr}; use strum::Display; use strum_macros::EnumString; -#[derive(Clone, Copy, EnumString, PartialEq, Hash, Eq, Debug, Display)] +#[derive(Clone, Copy, EnumString, PartialEq, Hash, Eq, Debug, Display, Deserialize, Serialize)] pub enum Target { /// Xtensa LX7 based dual core #[strum(serialize = "esp32")] diff --git a/src/toolchain/espidf.rs b/src/toolchain/espidf.rs index 04e46c4..7302d96 100644 --- a/src/toolchain/espidf.rs +++ b/src/toolchain/espidf.rs @@ -48,7 +48,7 @@ pub enum Generator { NMakeMakefilesJOM, WatcomWMake, } -#[derive(Debug)] +#[derive(Debug, Clone, Default)] pub struct EspIdfRepo { /// The repository containing GCC sources. pub repository_url: String, @@ -82,7 +82,7 @@ impl EspIdfRepo { let mut tools = vec![]; let mut subtools = Vec::new(); for target in self.targets { - let gcc_toolchain_name = get_toolchain_name(target); + let gcc_toolchain_name = get_toolchain_name(&target); subtools.push(gcc_toolchain_name); let ulp_toolchain_name = get_ulp_toolchain_name(target, version.as_ref().ok()); @@ -163,7 +163,7 @@ impl EspIdfRepo { } /// Create a new instance with the proper arguments. - pub fn new(version: &str, minified: bool, targets: HashSet) -> EspIdfRepo { + pub fn new(version: &str, minified: bool, targets: &HashSet) -> EspIdfRepo { let install_path = PathBuf::from(get_tools_path()); debug!( "{} ESP-IDF install path: '{}'", @@ -175,7 +175,7 @@ impl EspIdfRepo { version: version.to_string(), minified, install_path, - targets, + targets: targets.clone(), } } } diff --git a/src/toolchain/gcc_toolchain.rs b/src/toolchain/gcc_toolchain.rs index 29984ab..507702b 100644 --- a/src/toolchain/gcc_toolchain.rs +++ b/src/toolchain/gcc_toolchain.rs @@ -18,7 +18,7 @@ const DEFAULT_GCC_REPOSITORY: &str = "https://github.com/espressif/crosstool-NG/ const DEFAULT_GCC_RELEASE: &str = "esp-2021r2-patch5"; const DEFAULT_GCC_VERSION: &str = "8_4_0"; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct GccToolchain { /// Host triple. pub host_triple: HostTriple, @@ -75,7 +75,7 @@ impl GccToolchain { } /// Create a new instance with default values and proper toolchain name. - pub fn new(target: Target, host_triple: &HostTriple) -> Self { + pub fn new(target: &Target, host_triple: &HostTriple) -> Self { Self { host_triple: host_triple.clone(), release: DEFAULT_GCC_RELEASE.to_string(), @@ -105,7 +105,7 @@ fn get_artifact_extension(host_triple: &HostTriple) -> &str { } /// Gets the toolchain name based on the Target -pub fn get_toolchain_name(target: Target) -> String { +pub fn get_toolchain_name(target: &Target) -> String { match target { Target::ESP32 => "xtensa-esp32-elf".to_string(), Target::ESP32S2 => "xtensa-esp32s2-elf".to_string(), @@ -138,7 +138,7 @@ pub fn get_ulp_toolchain_name(target: Target, version: Option<&EspIdfVersion>) - /// Installs GCC toolchain the selected targets. pub fn install_gcc_targets( - targets: HashSet, + targets: &HashSet, host_triple: &HostTriple, ) -> Result> { info!("{} Installing gcc for build targets", emoji::WRENCH); diff --git a/src/toolchain/llvm_toolchain.rs b/src/toolchain/llvm_toolchain.rs index b41768e..769d1af 100644 --- a/src/toolchain/llvm_toolchain.rs +++ b/src/toolchain/llvm_toolchain.rs @@ -12,7 +12,7 @@ use std::path::{Path, PathBuf}; const DEFAULT_LLVM_REPOSITORY: &str = "https://github.com/espressif/llvm-project/releases/download"; const DEFAULT_LLVM_15_VERSION: &str = "esp-15.0.0-20221014"; -#[derive(Debug)] +#[derive(Debug, Clone, Default)] pub struct LlvmToolchain { /// LLVM Toolchain file name. pub file_name: String, diff --git a/src/toolchain/rust_toolchain.rs b/src/toolchain/rust_toolchain.rs index 4689fb9..362ec77 100644 --- a/src/toolchain/rust_toolchain.rs +++ b/src/toolchain/rust_toolchain.rs @@ -8,13 +8,14 @@ use crate::{ use anyhow::{bail, Result}; use embuild::cmd; use log::{info, warn}; +use serde::{Deserialize, Serialize}; use std::fmt::Debug; use std::{env, path::PathBuf, process::Stdio}; const DEFAULT_XTENSA_RUST_REPOSITORY: &str = "https://github.com/esp-rs/rust-build/releases/download"; -#[derive(Debug)] +#[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct RustToolchain { /// Path to the cargo home directory. pub cargo_home: PathBuf, @@ -146,7 +147,7 @@ impl RustToolchain { } } -#[derive(Hash, Eq, PartialEq, Debug)] +#[derive(Hash, Eq, PartialEq, Debug, Clone, Serialize, Deserialize, Default)] pub struct RustCrate { /// Crate name. pub name: String,