Merge branch 'main' into feature/doc-update

This commit is contained in:
Sergio Gasquez Arcos 2022-10-27 10:34:50 +02:00 committed by GitHub
commit f3bdc714b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 477 additions and 273 deletions

103
Cargo.lock generated
View File

@ -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",

View File

@ -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

View File

@ -3,6 +3,7 @@
[![Continuous Integration](https://github.com/esp-rs/espup/actions/workflows/ci.yaml/badge.svg)](https://github.com/esp-rs/espup/actions/workflows/ci.yaml)
[![Security audit](https://github.com/esp-rs/espup/actions/workflows/audit.yaml/badge.svg)](https://github.com/esp-rs/espup/actions/workflows/audit.yaml)
[![Open in Remote - Containers](https://img.shields.io/static/v1?label=Remote%20-%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/esp-rs/espup)
[![Matrix](https://img.shields.io/matrix/esp-rs:matrix.org?label=join%20matrix&color=BEC5C9&labelColor=1C2C2E&logo=matrix&style=flat-square)](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
View 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
View 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,))
}
}

View File

@ -1,4 +1,6 @@
pub mod config;
pub mod emoji;
pub mod host_triple;
pub mod targets;
pub mod toolchain;
pub mod logging {

View File

@ -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(())
}

View File

@ -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)

View File

@ -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(),
}
}
}

View File

@ -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)]

View File

@ -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,
}
}
}

View File

@ -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)?;
}

View File

@ -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(())
}