mirror of
https://github.com/esp-rs/espup.git
synced 2025-09-27 04:40:27 +00:00
Merge branch 'main' into feature/doc-update
This commit is contained in:
commit
f3bdc714b0
103
Cargo.lock
generated
103
Cargo.lock
generated
@ -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.13"
|
||||
version = "4.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d64e88428747154bd8bc378d178377ef4dace7a5735ca1f3855be72f2c2cb5"
|
||||
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,17 +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",
|
||||
]
|
||||
@ -789,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"
|
||||
@ -928,9 +978,9 @@ checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff"
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.3.2"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8"
|
||||
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
@ -939,9 +989,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pbkdf2"
|
||||
version = "0.10.1"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7"
|
||||
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"hmac",
|
||||
@ -1194,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",
|
||||
@ -1465,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"
|
||||
@ -1759,9 +1818,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "0.6.2"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf225bcf73bb52cbb496e70475c7bd7a3f769df699c0020f6c7bd9a96dcf0b8d"
|
||||
checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"byteorder",
|
||||
@ -1779,18 +1838,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.10.2+zstd.1.5.2"
|
||||
version = "0.11.2+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f4a6bd64f22b5e3e94b4e238669ff9f10815c27a5180108b849d24174a83847"
|
||||
checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "4.1.6+zstd.1.5.2"
|
||||
version = "5.0.2+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94b61c51bb270702d6167b8ce67340d2754b088d0c091b06e593aa772c3ee9bb"
|
||||
checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"zstd-sys",
|
||||
@ -1798,9 +1857,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "1.6.3+zstd.1.5.2"
|
||||
version = "2.0.1+zstd.1.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8"
|
||||
checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
|
11
Cargo.toml
11
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.10", features = ["derive"] }
|
||||
clap = { version = "4.0.18", features = ["derive"] }
|
||||
dirs = "*"
|
||||
flate2 = "1.0.22"
|
||||
guess_host_triple = "0.1.3"
|
||||
@ -28,6 +29,12 @@ log = "0.4.17"
|
||||
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"] }
|
||||
@ -41,5 +48,5 @@ bin-dir = "{ bin }{ binary-ext }"
|
||||
pkg-fmt = "zip"
|
||||
|
||||
[profile.release]
|
||||
lto = "thin"
|
||||
lto = "thin"
|
||||
strip = true
|
||||
|
15
README.md
15
README.md
@ -3,6 +3,7 @@
|
||||
[](https://github.com/esp-rs/espup/actions/workflows/ci.yaml)
|
||||
[](https://github.com/esp-rs/espup/actions/workflows/audit.yaml)
|
||||
[](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/esp-rs/espup)
|
||||
[](https://matrix.to/#/#esp-rs:matrix.org)
|
||||
|
||||
> `rustup` for [esp-rs](https://github.com/esp-rs/)
|
||||
|
||||
@ -14,10 +15,12 @@ developing applications in Rust for Espressif SoC's.
|
||||
> This application is still under development and should be considered experimental
|
||||
|
||||
## Requirements
|
||||
|
||||
Before running or installing `espup`, make sure that [`rustup`](https://www.rust-lang.org/tools/install)
|
||||
and the following dependencies are installed.
|
||||
### Windows
|
||||
|
||||
- Python must be installed and the version should be between `3.6` and `3.10`.
|
||||
- [Python](https://www.python.org/downloads/). Version should be between `3.6` and `3.10`.
|
||||
- [git](https://git-scm.com/download/win)
|
||||
- Toolchain. Select one of the following:
|
||||
- [Windows x86_64 GNU](https://github.com/esp-rs/rust-build#windows-x86_64-gnu)
|
||||
- [Windows x86_64 MSVC](https://github.com/esp-rs/rust-build#windows-x86_64-msvc)
|
||||
@ -26,14 +29,18 @@ developing applications in Rust for Espressif SoC's.
|
||||
### Linux
|
||||
- Ubuntu/Debian
|
||||
```sh
|
||||
sudo apt-get install -y git curl gcc clang ninja-build cmake libudev-dev \
|
||||
python3 python3-pip python3-venv libusb-1.0-0 libssl-dev pkg-config
|
||||
apt-get install -y git python3 python3-pip gcc build-essential curl pkg-config libudev-dev libssl-dev
|
||||
```
|
||||
- Fedora
|
||||
```sh
|
||||
dnf -y install git python3 python3-pip gcc openssl1.1 systemd-devel
|
||||
```
|
||||
- openSUSE Thumbleweed
|
||||
```
|
||||
sudo zypper install -y git gcc libudev-devel ninja python3 python38-pip
|
||||
```
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Download the pre-compiled [release binaries](https://github.com/esp-rs/espup/releases) or using [cargo-binstall](https://github.com/cargo-bins/cargo-binstall).
|
||||
|
61
src/config.rs
Normal file
61
src/config.rs
Normal file
@ -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<String>,
|
||||
/// Destination of the generated export file.
|
||||
pub export_file: PathBuf,
|
||||
/// Extra crates to installed.
|
||||
pub extra_crates: HashSet<String>,
|
||||
/// 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<Target>,
|
||||
/// Xtensa Rust toolchain.
|
||||
pub xtensa_toolchain: RustToolchain,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Load the config from config file
|
||||
pub fn load() -> Result<Self> {
|
||||
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()))
|
||||
}
|
||||
}
|
44
src/host_triple.rs
Normal file
44
src/host_triple.rs
Normal file
@ -0,0 +1,44 @@
|
||||
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, Deserialize, Serialize, Default)]
|
||||
pub enum HostTriple {
|
||||
/// 64-bit Linux
|
||||
#[strum(serialize = "x86_64-unknown-linux-gnu")]
|
||||
#[default]
|
||||
X86_64UnknownLinuxGnu,
|
||||
/// ARM64 Linux
|
||||
#[strum(serialize = "aarch64-unknown-linux-gnu")]
|
||||
Aarch64UnknownLinuxGnu,
|
||||
/// 64-bit MSVC
|
||||
#[strum(serialize = "x86_64-pc-windows-msvc")]
|
||||
X86_64PcWindowsMsvc,
|
||||
/// 64-bit MinGW
|
||||
#[strum(serialize = "x86_64-pc-windows-gnu")]
|
||||
X86_64PcWindowsGnu,
|
||||
/// 64-bit macOS
|
||||
#[strum(serialize = "x86_64-apple-darwin")]
|
||||
X86_64AppleDarwin,
|
||||
/// ARM64 macOS
|
||||
#[strum(serialize = "aarch64-apple-darwin")]
|
||||
Aarch64AppleDarwin,
|
||||
}
|
||||
|
||||
/// 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,
|
||||
))
|
||||
} else {
|
||||
HostTriple::from_str(guess_host_triple().unwrap())
|
||||
.context(format!("{} Unable to guess host triple.", emoji::ERROR,))
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
pub mod config;
|
||||
pub mod emoji;
|
||||
pub mod host_triple;
|
||||
pub mod targets;
|
||||
pub mod toolchain;
|
||||
pub mod logging {
|
||||
|
199
src/main.rs
199
src/main.rs
@ -1,36 +1,43 @@
|
||||
#[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,
|
||||
targets::{parse_targets, Target},
|
||||
toolchain::{
|
||||
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"^(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)\.(?P<subpatch>0|[1-9]\d*)?$";
|
||||
/// Latest Xtensa Toolchain version.
|
||||
const LATEST_TOOLCHAIN_VERSION: &str = "1.64.0.0";
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(
|
||||
name = "espup",
|
||||
@ -56,6 +63,9 @@ pub enum SubCommand {
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct InstallOpts {
|
||||
/// Target triple of the host.
|
||||
#[arg(short = 'd', long, required = false)]
|
||||
pub default_host: Option<String>,
|
||||
/// ESP-IDF version to install. If empty, no esp-idf is installed. Version format:
|
||||
///
|
||||
/// - `commit:<hash>`: Uses the commit `<hash>` of the `esp-idf` repository.
|
||||
@ -89,63 +99,63 @@ 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,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct UpdateOpts {
|
||||
/// Target triple of the host.
|
||||
#[arg(short = 'd', long, required = false)]
|
||||
pub default_host: Option<String>,
|
||||
/// Verbosity level of the logs.
|
||||
#[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<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct UninstallOpts {
|
||||
/// ESP-IDF version to uninstall. If empty, no esp-idf is uninstalled. Version format:
|
||||
///
|
||||
/// - `commit:<hash>`: Uses the commit `<hash>` of the `esp-idf` repository.
|
||||
///
|
||||
/// - `tag:<tag>`: Uses the tag `<tag>` of the `esp-idf` repository.
|
||||
///
|
||||
/// - `branch:<branch>`: Uses the branch `<branch>` of the `esp-idf` repository.
|
||||
///
|
||||
/// - `v<major>.<minor>` or `<major>.<minor>`: Uses the tag `v<major>.<minor>` of the `esp-idf` repository.
|
||||
///
|
||||
/// - `<branch>`: Uses the branch `<branch>` of the `esp-idf` repository.
|
||||
#[arg(short = 'e', long, required = false)]
|
||||
pub espidf_version: Option<String>,
|
||||
/// 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<String> {
|
||||
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
|
||||
);
|
||||
}
|
||||
Ok(arg.to_string())
|
||||
}
|
||||
|
||||
/// Installs the Rust for ESP chips environment
|
||||
fn install(args: InstallOpts) -> Result<()> {
|
||||
initialize_logger(&args.log_level);
|
||||
|
||||
info!("{} Installing esp-rs", emoji::DISC);
|
||||
let targets: HashSet<Target> = parse_targets(&args.targets).unwrap();
|
||||
let host_triple = get_host_triple(args.default_host)?;
|
||||
let mut extra_crates: HashSet<RustCrate> =
|
||||
args.extra_crates.split(',').map(RustCrate::new).collect();
|
||||
let mut exports: Vec<String> = Vec::new();
|
||||
let export_file = args.export_file.clone();
|
||||
let rust_toolchain = RustToolchain::new(args.toolchain_version.clone());
|
||||
|
||||
let rust_toolchain = RustToolchain::new(&args.toolchain_version, &host_triple);
|
||||
// Complete LLVM is failing for Windows, aarch64 MacOs, and aarch64 Linux, so we are using always minified.
|
||||
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
|
||||
let llvm = LlvmToolchain::new(args.profile_minimal);
|
||||
let llvm = LlvmToolchain::new(args.profile_minimal, &host_triple);
|
||||
#[cfg(any(not(target_arch = "x86_64"), not(target_os = "linux")))]
|
||||
let llvm = LlvmToolchain::new(true);
|
||||
let llvm = LlvmToolchain::new(true, &host_triple);
|
||||
|
||||
debug!(
|
||||
"{} Arguments:
|
||||
- Host triple: {}
|
||||
- Targets: {:?}
|
||||
- ESP-IDF version: {:?}
|
||||
- Export file: {:?}
|
||||
@ -156,10 +166,11 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
- Profile Minimal: {:?}
|
||||
- Toolchain version: {:?}",
|
||||
emoji::INFO,
|
||||
host_triple,
|
||||
targets,
|
||||
&args.espidf_version,
|
||||
export_file,
|
||||
extra_crates,
|
||||
&extra_crates,
|
||||
llvm,
|
||||
&args.nightly_version,
|
||||
rust_toolchain,
|
||||
@ -181,11 +192,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)?);
|
||||
exports.extend(install_gcc_targets(&targets, &host_triple)?);
|
||||
}
|
||||
|
||||
debug!(
|
||||
@ -193,7 +204,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()?;
|
||||
}
|
||||
|
||||
@ -203,6 +214,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::<HashSet<String>>(),
|
||||
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!",
|
||||
@ -211,61 +240,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:
|
||||
- Toolchain version: {}",
|
||||
- Host triple: {}
|
||||
- Toolchain version: {:#?}
|
||||
- Config: {:#?}",
|
||||
emoji::INFO,
|
||||
&args.toolchain_version,
|
||||
host_triple,
|
||||
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);
|
||||
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(())
|
||||
}
|
||||
@ -280,8 +350,11 @@ fn main() -> Result<()> {
|
||||
|
||||
/// Deletes dist folder.
|
||||
fn clear_dist_folder() -> Result<()> {
|
||||
info!("{} Clearing dist folder", emoji::WRENCH);
|
||||
remove_dir_all(&get_dist_path(""))?;
|
||||
let dist_path = PathBuf::from(get_dist_path(""));
|
||||
if dist_path.exists() {
|
||||
info!("{} Clearing dist folder", emoji::WRENCH);
|
||||
remove_dir_all(&dist_path)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,14 @@
|
||||
//! ESP32 chip variants support.
|
||||
|
||||
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, Hash, PartialEq, 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")]
|
||||
@ -22,20 +24,6 @@ pub enum Target {
|
||||
ESP32C3,
|
||||
}
|
||||
|
||||
impl FromStr for Target {
|
||||
type Err = ();
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"esp32" => Ok(Target::ESP32),
|
||||
"esp32s2" => Ok(Target::ESP32S2),
|
||||
"esp32s3" => Ok(Target::ESP32S3),
|
||||
"esp32c3" => Ok(Target::ESP32C3),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a vector of Chips from a comma or space separated string.
|
||||
pub fn parse_targets(targets_str: &str) -> Result<HashSet<Target>, String> {
|
||||
debug!("{} Parsing targets: {}", emoji::DEBUG, targets_str);
|
||||
@ -54,7 +42,15 @@ pub fn parse_targets(targets_str: &str) -> Result<HashSet<Target>, String> {
|
||||
};
|
||||
|
||||
for target in targets_str {
|
||||
targets.insert(FromStr::from_str(target).unwrap());
|
||||
targets.insert(
|
||||
Target::from_str(target)
|
||||
.context(format!(
|
||||
"{} Target '{}' is not supported",
|
||||
emoji::ERROR,
|
||||
target
|
||||
))
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
debug!("{} Parsed targets: {:?}", emoji::DEBUG, targets);
|
||||
Ok(targets)
|
||||
|
@ -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,10 +163,10 @@ impl EspIdfRepo {
|
||||
}
|
||||
|
||||
/// Create a new instance with the proper arguments.
|
||||
pub fn new(version: &str, minified: bool, targets: HashSet<Target>) -> EspIdfRepo {
|
||||
pub fn new(version: &str, minified: bool, targets: &HashSet<Target>) -> EspIdfRepo {
|
||||
let install_path = PathBuf::from(get_tools_path());
|
||||
debug!(
|
||||
"{} ESP-IDF install path: {}",
|
||||
"{} ESP-IDF install path: '{}'",
|
||||
emoji::DEBUG,
|
||||
install_path.display()
|
||||
);
|
||||
@ -175,7 +175,7 @@ impl EspIdfRepo {
|
||||
version: version.to_string(),
|
||||
minified,
|
||||
install_path,
|
||||
targets,
|
||||
targets: targets.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,28 +2,34 @@
|
||||
|
||||
use crate::{
|
||||
emoji,
|
||||
host_triple::HostTriple,
|
||||
targets::Target,
|
||||
toolchain::{download_file, espidf::get_tool_path},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use embuild::espidf::EspIdfVersion;
|
||||
use log::{debug, info};
|
||||
use std::collections::HashSet;
|
||||
use log::{debug, info, warn};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
const DEFAULT_GCC_REPOSITORY: &str = "https://github.com/espressif/crosstool-NG/releases/download";
|
||||
const DEFAULT_GCC_RELEASE: &str = "esp-2021r2-patch5";
|
||||
const DEFAULT_GCC_VERSION: &str = "8_4_0";
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GccToolchain {
|
||||
/// The repository containing GCC sources.
|
||||
pub repository_url: String,
|
||||
/// Host triple.
|
||||
pub host_triple: HostTriple,
|
||||
/// Repository release version to use.
|
||||
pub release: String,
|
||||
/// GCC Version.
|
||||
pub version: String,
|
||||
/// The repository containing GCC sources.
|
||||
pub repository_url: String,
|
||||
/// GCC Toolchain target.
|
||||
pub toolchain_name: String,
|
||||
/// GCC Version.
|
||||
pub version: String,
|
||||
}
|
||||
|
||||
impl GccToolchain {
|
||||
@ -39,17 +45,23 @@ impl GccToolchain {
|
||||
/// Installs the gcc toolchain.
|
||||
pub fn install(&self) -> Result<()> {
|
||||
let target_dir = format!("{}/{}-{}", self.toolchain_name, self.release, self.version);
|
||||
|
||||
let gcc_path = get_tool_path(&target_dir);
|
||||
let host_triple = guess_host_triple::guess_host_triple().unwrap();
|
||||
let extension = get_artifact_extension(host_triple);
|
||||
let extension = get_artifact_extension(&self.host_triple);
|
||||
debug!("{} GCC path: {}", emoji::DEBUG, gcc_path);
|
||||
if Path::new(&PathBuf::from(&gcc_path)).exists() {
|
||||
warn!(
|
||||
"{} Previous installation of GCC exist in: '{}'. Reusing this installation.",
|
||||
emoji::WARN,
|
||||
&gcc_path
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
let gcc_file = format!(
|
||||
"{}-gcc{}-{}-{}.{}",
|
||||
self.toolchain_name,
|
||||
self.version,
|
||||
self.release,
|
||||
get_arch(host_triple).unwrap(),
|
||||
get_arch(&self.host_triple).unwrap(),
|
||||
extension
|
||||
);
|
||||
let gcc_dist_url = format!("{}/{}/{}", self.repository_url, self.release, gcc_file);
|
||||
@ -63,40 +75,37 @@ impl GccToolchain {
|
||||
}
|
||||
|
||||
/// Create a new instance with default values and proper toolchain name.
|
||||
pub fn new(target: Target) -> Self {
|
||||
pub fn new(target: &Target, host_triple: &HostTriple) -> Self {
|
||||
Self {
|
||||
repository_url: DEFAULT_GCC_REPOSITORY.to_string(),
|
||||
host_triple: host_triple.clone(),
|
||||
release: DEFAULT_GCC_RELEASE.to_string(),
|
||||
version: DEFAULT_GCC_VERSION.to_string(),
|
||||
repository_url: DEFAULT_GCC_REPOSITORY.to_string(),
|
||||
toolchain_name: get_toolchain_name(target),
|
||||
version: DEFAULT_GCC_VERSION.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the name of the GCC arch based on the host triple.
|
||||
fn get_arch(host_triple: &str) -> Result<&str, String> {
|
||||
fn get_arch(host_triple: &HostTriple) -> Result<&str> {
|
||||
match host_triple {
|
||||
"aarch64-apple-darwin" | "x86_64-apple-darwin" => Ok("macos"),
|
||||
"aarch64-unknown-linux-gnu" => Ok("linux-arm64"),
|
||||
"x86_64-unknown-linux-gnu" => Ok("linux-amd64"),
|
||||
"x86_64-pc-windows-msvc" | "x86_64-pc-windows-gnu" => Ok("win64"),
|
||||
_ => Err(format!(
|
||||
"No GCC arch found for the host triple: {}",
|
||||
host_triple
|
||||
)),
|
||||
HostTriple::Aarch64AppleDarwin | HostTriple::X86_64AppleDarwin => Ok("macos"),
|
||||
HostTriple::X86_64UnknownLinuxGnu => Ok("linux-amd64"),
|
||||
HostTriple::Aarch64UnknownLinuxGnu => Ok("linux-arm64"),
|
||||
HostTriple::X86_64PcWindowsMsvc | HostTriple::X86_64PcWindowsGnu => Ok("win64"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the artifact extension based on the host architecture.
|
||||
fn get_artifact_extension(host_triple: &str) -> &str {
|
||||
/// Gets the artifact extension based on the host triple.
|
||||
fn get_artifact_extension(host_triple: &HostTriple) -> &str {
|
||||
match host_triple {
|
||||
"x86_64-pc-windows-msvc" | "x86_64-pc-windows-gnu" => "zip",
|
||||
HostTriple::X86_64PcWindowsMsvc | HostTriple::X86_64PcWindowsGnu => "zip",
|
||||
_ => "tar.gz",
|
||||
}
|
||||
}
|
||||
|
||||
/// 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(),
|
||||
@ -128,11 +137,14 @@ pub fn get_ulp_toolchain_name(target: Target, version: Option<&EspIdfVersion>) -
|
||||
}
|
||||
|
||||
/// Installs GCC toolchain the selected targets.
|
||||
pub fn install_gcc_targets(targets: HashSet<Target>) -> Result<Vec<String>> {
|
||||
pub fn install_gcc_targets(
|
||||
targets: &HashSet<Target>,
|
||||
host_triple: &HostTriple,
|
||||
) -> Result<Vec<String>> {
|
||||
info!("{} Installing gcc for build targets", emoji::WRENCH);
|
||||
let mut exports: Vec<String> = Vec::new();
|
||||
for target in targets {
|
||||
let gcc = GccToolchain::new(target);
|
||||
let gcc = GccToolchain::new(target, host_triple);
|
||||
gcc.install()?;
|
||||
|
||||
#[cfg(windows)]
|
||||
|
@ -2,10 +2,11 @@
|
||||
|
||||
use crate::{
|
||||
emoji,
|
||||
host_triple::HostTriple,
|
||||
toolchain::{download_file, espidf::get_tool_path},
|
||||
};
|
||||
use anyhow::{bail, Ok, Result};
|
||||
use log::info;
|
||||
use log::{info, warn};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
const DEFAULT_LLVM_COMPLETE_REPOSITORY: &str =
|
||||
@ -14,37 +15,39 @@ const DEFAULT_LLVM_MINIFIED_REPOSITORY: &str =
|
||||
"https://github.com/esp-rs/rust-build/releases/download/llvm-project-14.0-minified";
|
||||
const DEFAULT_LLVM_VERSION: &str = "esp-14.0.0-20220415";
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct LlvmToolchain {
|
||||
/// LLVM Toolchain file name.
|
||||
pub file_name: String,
|
||||
/// Host triple.
|
||||
pub host_triple: HostTriple,
|
||||
/// LLVM Toolchain path.
|
||||
pub path: PathBuf,
|
||||
/// The repository containing LVVM sources.
|
||||
pub repository_url: String,
|
||||
/// Repository release version to use.
|
||||
pub version: String,
|
||||
/// LLVM Toolchain file name.
|
||||
pub file_name: String,
|
||||
/// LLVM Toolchain path.
|
||||
pub path: PathBuf,
|
||||
}
|
||||
|
||||
impl LlvmToolchain {
|
||||
/// Gets the name of the LLVM arch based on the host triple.
|
||||
fn get_arch(host_triple: &str) -> Result<String> {
|
||||
fn get_arch(host_triple: &HostTriple) -> Result<&str> {
|
||||
match host_triple {
|
||||
"aarch64-apple-darwin" | "x86_64-apple-darwin" => Ok("macos".to_string()),
|
||||
"x86_64-unknown-linux-gnu" => Ok("linux-amd64".to_string()),
|
||||
"x86_64-pc-windows-msvc" | "x86_64-pc-windows-gnu" => Ok("win64".to_string()),
|
||||
HostTriple::Aarch64AppleDarwin | HostTriple::X86_64AppleDarwin => Ok("macos"),
|
||||
HostTriple::X86_64UnknownLinuxGnu => Ok("linux-amd64"),
|
||||
HostTriple::X86_64PcWindowsMsvc | HostTriple::X86_64PcWindowsGnu => Ok("win64"),
|
||||
_ => bail!(
|
||||
"{} No LLVM arch found for the host triple: {}",
|
||||
"{} No LLVM arch found for the host triple: '{}'",
|
||||
emoji::ERROR,
|
||||
host_triple
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the artifact extension based on the host architecture.
|
||||
fn get_artifact_extension(host_triple: &str) -> &str {
|
||||
/// Gets the artifact extension based on the host triple.
|
||||
fn get_artifact_extension(host_triple: &HostTriple) -> &str {
|
||||
match host_triple {
|
||||
"x86_64-pc-windows-msvc" | "x86_64-pc-windows-gnu" => "zip",
|
||||
HostTriple::X86_64PcWindowsMsvc | HostTriple::X86_64PcWindowsGnu => "zip",
|
||||
_ => "tar.xz",
|
||||
}
|
||||
}
|
||||
@ -63,18 +66,18 @@ impl LlvmToolchain {
|
||||
let mut exports: Vec<String> = Vec::new();
|
||||
|
||||
if Path::new(&self.path).exists() {
|
||||
bail!(
|
||||
"{} Previous installation of LLVM exist in: {}.\n Please, remove the directory before new installation.",
|
||||
emoji::WARN,
|
||||
self.path.to_str().unwrap()
|
||||
);
|
||||
warn!(
|
||||
"{} Previous installation of LLVM exist in: '{}'. Reusing this installation.",
|
||||
emoji::WARN,
|
||||
self.path.to_str().unwrap()
|
||||
);
|
||||
} else {
|
||||
info!("{} Installing Xtensa elf Clang", emoji::WRENCH);
|
||||
download_file(
|
||||
self.repository_url.clone(),
|
||||
&format!(
|
||||
"idf_tool_xtensa_elf_clang.{}",
|
||||
Self::get_artifact_extension(guess_host_triple::guess_host_triple().unwrap())
|
||||
Self::get_artifact_extension(&self.host_triple)
|
||||
),
|
||||
self.path.to_str().unwrap(),
|
||||
true,
|
||||
@ -95,10 +98,9 @@ impl LlvmToolchain {
|
||||
}
|
||||
|
||||
/// Create a new instance with default values and proper toolchain version.
|
||||
pub fn new(minified: bool) -> Self {
|
||||
let host_triple = guess_host_triple::guess_host_triple().unwrap();
|
||||
let version = DEFAULT_LLVM_VERSION.to_string();
|
||||
pub fn new(minified: bool, host_triple: &HostTriple) -> Self {
|
||||
let file_name: String;
|
||||
let version = DEFAULT_LLVM_VERSION.to_string();
|
||||
let repository_url: String;
|
||||
if minified {
|
||||
file_name = format!(
|
||||
@ -130,10 +132,11 @@ impl LlvmToolchain {
|
||||
)
|
||||
.into();
|
||||
Self {
|
||||
file_name,
|
||||
host_triple: host_triple.clone(),
|
||||
path,
|
||||
repository_url,
|
||||
version,
|
||||
file_name,
|
||||
path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,13 +30,17 @@ pub fn download_file(
|
||||
) -> Result<String> {
|
||||
let file_path = format!("{}/{}", output_directory, file_name);
|
||||
if Path::new(&file_path).exists() {
|
||||
info!("{} Using cached file: {}", emoji::INFO, file_path);
|
||||
info!("{} Using cached file: '{}'", emoji::INFO, file_path);
|
||||
return Ok(file_path);
|
||||
} else if !Path::new(&output_directory).exists() {
|
||||
info!("{} Creating directory: {}", emoji::WRENCH, output_directory);
|
||||
info!(
|
||||
"{} Creating directory: '{}'",
|
||||
emoji::WRENCH,
|
||||
output_directory
|
||||
);
|
||||
if let Err(_e) = create_dir_all(output_directory) {
|
||||
bail!(
|
||||
"{} Creating directory {} failed",
|
||||
"{} Creating directory '{}' failed",
|
||||
emoji::ERROR,
|
||||
output_directory
|
||||
);
|
||||
@ -61,7 +65,7 @@ pub fn download_file(
|
||||
}
|
||||
"gz" => {
|
||||
info!(
|
||||
"{} Uncompressing tar.gz file to {}",
|
||||
"{} Uncompressing tar.gz file to '{}'",
|
||||
emoji::WRENCH,
|
||||
output_directory
|
||||
);
|
||||
@ -72,7 +76,7 @@ pub fn download_file(
|
||||
}
|
||||
"xz" => {
|
||||
info!(
|
||||
"{} Uncompressing tar.xz file to {}",
|
||||
"{} Uncompressing tar.xz file to '{}'",
|
||||
emoji::WRENCH,
|
||||
output_directory
|
||||
);
|
||||
@ -82,11 +86,15 @@ pub fn download_file(
|
||||
archive.unpack(output_directory).unwrap();
|
||||
}
|
||||
_ => {
|
||||
bail!("{} Unsuported file extension: {}", emoji::ERROR, extension);
|
||||
bail!(
|
||||
"{} Unsuported file extension: '{}'",
|
||||
emoji::ERROR,
|
||||
extension
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!("{} Creating file: {}", emoji::WRENCH, file_path);
|
||||
info!("{} Creating file: '{}'", emoji::WRENCH, file_path);
|
||||
let mut out = File::create(file_path)?;
|
||||
copy(&mut resp, &mut out)?;
|
||||
}
|
||||
|
@ -1,34 +1,40 @@
|
||||
//! Xtensa Rust Toolchain source and installation tools
|
||||
|
||||
#[cfg(unix)]
|
||||
use super::espidf::get_dist_path;
|
||||
use crate::{
|
||||
emoji,
|
||||
toolchain::{download_file, espidf::get_dist_path, get_home_dir},
|
||||
host_triple::HostTriple,
|
||||
toolchain::{download_file, get_home_dir},
|
||||
};
|
||||
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,
|
||||
/// Xtensa Rust toolchain file.
|
||||
pub dist_file: String,
|
||||
/// Xtensa Rust toolchain URL.
|
||||
pub dist_url: String,
|
||||
/// Host triple.
|
||||
pub host_triple: String,
|
||||
/// Path to the rustup home directory.
|
||||
pub rustup_home: PathBuf,
|
||||
#[cfg(unix)]
|
||||
/// Xtensa Src Rust toolchain file.
|
||||
pub src_dist_file: String,
|
||||
#[cfg(unix)]
|
||||
/// Xtensa Src Rust toolchain URL.
|
||||
pub src_dist_url: String,
|
||||
/// Path to the cargo home directory.
|
||||
pub cargo_home: PathBuf,
|
||||
/// Path to the rustup home directory.
|
||||
pub rustup_home: PathBuf,
|
||||
/// Xtensa Rust toolchain destination path.
|
||||
pub toolchain_destination: PathBuf,
|
||||
/// Xtensa Rust Toolchain version.
|
||||
@ -44,7 +50,7 @@ impl RustToolchain {
|
||||
let toolchain_path = self.toolchain_destination.clone().join("esp");
|
||||
if toolchain_path.exists() {
|
||||
bail!(
|
||||
"{} Previous installation of Rust Toolchain exist in: {}.\n Please, remove the directory before new installation.",
|
||||
"{} Previous installation of Rust Toolchain exist in: '{}'. Please, remove the directory before new installation.",
|
||||
emoji::WARN,
|
||||
self.toolchain_destination.display()
|
||||
);
|
||||
@ -57,7 +63,6 @@ impl RustToolchain {
|
||||
|
||||
#[cfg(unix)]
|
||||
if cfg!(unix) {
|
||||
let host_triple = guess_host_triple::guess_host_triple().unwrap();
|
||||
download_file(
|
||||
self.dist_url.clone(),
|
||||
"rust.tar.xz",
|
||||
@ -69,7 +74,7 @@ impl RustToolchain {
|
||||
let arguments = format!(
|
||||
"{}/rust-nightly-{}/install.sh --destdir={} --prefix='' --without=rust-docs",
|
||||
get_dist_path("rust"),
|
||||
host_triple,
|
||||
&self.host_triple,
|
||||
self.toolchain_destination.display()
|
||||
);
|
||||
cmd!("/bin/bash", "-c", arguments).run()?;
|
||||
@ -104,10 +109,9 @@ impl RustToolchain {
|
||||
}
|
||||
|
||||
/// Create a new instance.
|
||||
pub fn new(toolchain_version: String) -> Self {
|
||||
let host_triple = guess_host_triple::guess_host_triple().unwrap();
|
||||
pub fn new(toolchain_version: &str, host_triple: &HostTriple) -> Self {
|
||||
let artifact_extension = get_artifact_extension(host_triple);
|
||||
let version = toolchain_version;
|
||||
let version = toolchain_version.to_string();
|
||||
let dist = format!("rust-{}-{}", version, host_triple);
|
||||
let dist_file = format!("{}.{}", dist, artifact_extension);
|
||||
let dist_url = format!(
|
||||
@ -130,21 +134,22 @@ impl RustToolchain {
|
||||
#[cfg(windows)]
|
||||
let toolchain_destination = rustup_home.join("toolchains");
|
||||
Self {
|
||||
cargo_home,
|
||||
dist_file,
|
||||
dist_url,
|
||||
host_triple: host_triple.to_string(),
|
||||
rustup_home,
|
||||
#[cfg(unix)]
|
||||
src_dist_file,
|
||||
#[cfg(unix)]
|
||||
src_dist_url,
|
||||
cargo_home,
|
||||
rustup_home,
|
||||
toolchain_destination,
|
||||
version,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Debug)]
|
||||
#[derive(Hash, Eq, PartialEq, Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct RustCrate {
|
||||
/// Crate name.
|
||||
pub name: String,
|
||||
@ -175,9 +180,9 @@ impl RustCrate {
|
||||
}
|
||||
|
||||
/// Gets the artifact extension based on the host architecture.
|
||||
fn get_artifact_extension(host_triple: &str) -> &str {
|
||||
fn get_artifact_extension(host_triple: &HostTriple) -> &str {
|
||||
match host_triple {
|
||||
"x86_64-pc-windows-msvc" | "x86_64-pc-windows-gnu" => "zip",
|
||||
HostTriple::X86_64PcWindowsMsvc | HostTriple::X86_64PcWindowsGnu => "zip",
|
||||
_ => "tar.xz",
|
||||
}
|
||||
}
|
||||
@ -192,97 +197,24 @@ pub fn get_rustup_home() -> PathBuf {
|
||||
PathBuf::from(env::var("RUSTUP_HOME").unwrap_or_else(|_e| get_home_dir() + "/.rustup"))
|
||||
}
|
||||
|
||||
/// Checks if rustup and the proper nightly version are installed. If they are
|
||||
/// not, proceed to install them.
|
||||
/// 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<()> {
|
||||
info!("{} Checking existing Rust installation", emoji::WRENCH);
|
||||
|
||||
match cmd!("rustup", "toolchain", "list")
|
||||
if let Ok(child_output) = cmd!("rustup", "toolchain", "list")
|
||||
.into_inner()
|
||||
.stdout(Stdio::piped())
|
||||
.output()
|
||||
{
|
||||
Ok(child_output) => {
|
||||
let result = String::from_utf8_lossy(&child_output.stdout);
|
||||
if !result.contains("nightly") {
|
||||
warn!("{} Rust nightly toolchain not found", emoji::WARN);
|
||||
install_rust_nightly(nightly_version)?;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if let std::io::ErrorKind::NotFound = e.kind() {
|
||||
warn!("{} rustup was not found.", emoji::WARN);
|
||||
install_rustup(nightly_version)?;
|
||||
} else {
|
||||
bail!("{} Error: {}", emoji::ERROR, e);
|
||||
}
|
||||
let result = String::from_utf8_lossy(&child_output.stdout);
|
||||
if !result.contains("nightly") {
|
||||
warn!("{} Rust nightly toolchain not found", emoji::WARN);
|
||||
install_rust_nightly(nightly_version)?;
|
||||
}
|
||||
} else {
|
||||
bail!("{} rustup was not found. Please, install rustup: https://www.rust-lang.org/tools/install", emoji::ERROR);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Installs rustup
|
||||
fn install_rustup(nightly_version: &str) -> Result<()> {
|
||||
#[cfg(windows)]
|
||||
let rustup_init_path = download_file(
|
||||
"https://win.rustup.rs/x86_64".to_string(),
|
||||
"rustup-init.exe",
|
||||
&get_dist_path("rustup"),
|
||||
false,
|
||||
)?;
|
||||
#[cfg(unix)]
|
||||
let rustup_init_path = download_file(
|
||||
"https://sh.rustup.rs".to_string(),
|
||||
"rustup-init.sh",
|
||||
&get_dist_path("rustup"),
|
||||
false,
|
||||
)?;
|
||||
info!(
|
||||
"{} Installing rustup with {} toolchain",
|
||||
emoji::WRENCH,
|
||||
nightly_version
|
||||
);
|
||||
|
||||
#[cfg(windows)]
|
||||
cmd!(
|
||||
rustup_init_path,
|
||||
"--default-toolchain",
|
||||
nightly_version,
|
||||
"--profile",
|
||||
"minimal",
|
||||
"-y"
|
||||
)
|
||||
.run()?;
|
||||
#[cfg(not(windows))]
|
||||
cmd!(
|
||||
"/bin/bash",
|
||||
rustup_init_path,
|
||||
"--default-toolchain",
|
||||
nightly_version,
|
||||
"--profile",
|
||||
"minimal",
|
||||
"-y"
|
||||
)
|
||||
.run()?;
|
||||
|
||||
#[cfg(windows)]
|
||||
let path = format!(
|
||||
"{};{}",
|
||||
std::env::var("PATH").unwrap(),
|
||||
get_cargo_home().join("bin").display()
|
||||
);
|
||||
#[cfg(unix)]
|
||||
let path = format!(
|
||||
"{}:{}",
|
||||
std::env::var("PATH").unwrap(),
|
||||
get_cargo_home().join("bin").display()
|
||||
);
|
||||
|
||||
std::env::set_var("PATH", path);
|
||||
warn!(
|
||||
"{} Please restart your terminal after the installation for the changes to take effect.",
|
||||
emoji::WARN
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user