refactor: ♻️ Use download_file to download assets

This commit is contained in:
Sergio Gasquez 2022-09-17 10:07:08 +00:00
parent 211d55fa13
commit 23113d1718
3 changed files with 173 additions and 376 deletions

View File

@ -8,9 +8,10 @@ use std::path::{Path, PathBuf};
mod emoji;
mod toolchain;
mod utils;
use anyhow::{bail, Result};
use anyhow::Result;
use clap_verbosity_flag::{InfoLevel, Verbosity};
use log::{debug, info, warn};
use embuild::cmd;
use log::{info, warn};
// General TODOs:
// - Add extra-crates installation support
@ -113,7 +114,7 @@ fn install(args: InstallOpts) -> Result<()> {
let arch = guess_host_triple::guess_host_triple().unwrap();
let targets: Vec<Chip> = parse_targets(&args.build_target).unwrap();
let llvm_version = parse_llvm_version(&args.llvm_version).unwrap();
let artifact_file_extension = get_artifact_file_extension(arch).to_string();
let artifact_file_extension = get_artifact_llvm_extension(arch).to_string();
let llvm_arch = get_llvm_arch(arch).to_string();
let llvm_file = format!(
"xtensa-esp32-elf-llvm{}-{}-{}.{}",
@ -163,79 +164,41 @@ fn install(args: InstallOpts) -> Result<()> {
// script in dist is not available for the plaform. It's sufficient to extract the toolchain
info!("{} Installing Xtensa Rust toolchain", emoji::WRENCH);
if get_rust_installer(arch).to_string().is_empty() {
// TODO: Check idf_env and adjust
// match prepare_package_strip_prefix(&rust_dist_url,
// &rust_dist_file,
// get_tool_path("rust".to_string()),
// "esp") {
// Ok(_) => { info!("Package ready"); },
// Err(_e) => { bail!("Unable to prepare package"); }
// }
download_file(
rust_dist_url,
"rust.zip",
&args.toolchain_destination.display().to_string(),
true,
)?;
} else {
match prepare_package_strip_prefix(
&rust_dist_url,
get_tool_path("rust"),
&format!("rust-nightly-{}", arch),
) {
Ok(_) => {
debug!("{} Package rust ready", emoji::CHECK);
}
Err(_e) => {
bail!("{} Unable to prepare rust", emoji::ERROR);
}
}
info!("{} Installing rust", emoji::WRENCH);
let mut arguments: Vec<String> = [].to_vec();
arguments.push("-c".to_string());
arguments.push(format!(
"{}/install.sh --destdir={} --prefix='' --without=rust-docs",
get_tool_path("rust"),
download_file(rust_dist_url, "rust.tar.xz", &get_dist_path("rust"), true)?;
info!("{} Installing rust esp toolchain", emoji::WRENCH);
let arguments = format!(
"{}/rust-nightly-{}/install.sh --destdir={} --prefix='' --without=rust-docs",
get_dist_path("rust"),
arch,
args.toolchain_destination.display()
));
);
cmd!("/bin/bash", "-c", arguments).run()?;
match run_command("/bin/bash", arguments.clone(), "".to_string()) {
Ok(_) => {
debug!("{} rust/install.sh command succeeded", emoji::CHECK);
}
Err(_e) => {
bail!("{} rust/install.sh command failed", emoji::ERROR);
}
}
match prepare_package_strip_prefix(
&rust_src_dist_url,
get_tool_path("rust-src"),
"rust-src-nightly",
) {
Ok(_) => {
debug!("{} Package rust-src ready", emoji::CHECK);
}
Err(_e) => {
bail!("{} Unable to prepare rust-src", emoji::ERROR);
}
}
info!("{} Installing rust-src", emoji::WRENCH);
let mut arguments: Vec<String> = [].to_vec();
arguments.push("-c".to_string());
arguments.push(format!(
"{}/install.sh --destdir={} --prefix='' --without=rust-docs",
get_tool_path("rust-src"),
download_file(
rust_src_dist_url,
"rust-src.tar.xz",
&get_dist_path("rust-src"),
true,
)?;
info!("{} Installing rust-src for esp toolchain", emoji::WRENCH);
let arguments = format!(
"{}/rust-src-nightly/install.sh --destdir={} --prefix='' --without=rust-docs",
get_dist_path("rust-src"),
args.toolchain_destination.display()
));
match run_command("/bin/bash", arguments, "".to_string()) {
Ok(_) => {
debug!("{} rust-src/install.sh Command succeeded", emoji::CHECK);
}
Err(_e) => {
bail!("{} rust-src/install.sh Command failed", emoji::ERROR);
}
}
);
cmd!("/bin/bash", "-c", arguments).run()?;
}
}
// install_llvm_clang
// TODO: move to function
info!("{} Installing Xtensa elf Clang", emoji::WRENCH);
if Path::new(idf_tool_xtensa_elf_clang.as_str()).exists() {
warn!(
"{} Previous installation of LLVM exist in: {}.\n Please, remove the directory before new installation.",
@ -243,27 +206,20 @@ fn install(args: InstallOpts) -> Result<()> {
idf_tool_xtensa_elf_clang
);
} else {
match prepare_package_strip_prefix(
&llvm_url,
get_tool_path(&format!(
"xtensa-esp32-elf-clang-{}-{}",
llvm_version, llvm_arch
)),
"",
) {
Ok(_) => {
debug!("{} Package xtensa-esp32-elf-clang ready", emoji::CHECK);
}
Err(_e) => {
bail!("{} Unable to prepare xtensa-esp32-elf-clang", emoji::ERROR);
}
}
download_file(
llvm_url,
&format!(
"idf_tool_xtensa_elf_clang.{}",
get_artifact_llvm_extension(arch)
),
&get_tool_path(""),
true,
)?;
}
let libclang_path = format!("{}/lib", get_tool_path("xtensa-esp32-elf-clang"));
exports.push(format!("export LIBCLANG_PATH=\"{}\"", &libclang_path));
if targets.contains(&Chip::Esp32c3) {
info!("{} Installing riscv target", emoji::WRENCH);
install_riscv_target(&args.nightly_version)?;
}
@ -288,7 +244,7 @@ fn install(args: InstallOpts) -> Result<()> {
// TODO: Install ldproxy
install_extra_crate("ldproxy")?;
} else {
info!("{} Installing gcc for targets", emoji::WRENCH);
info!("{} Installing gcc for build targets", emoji::WRENCH);
exports.extend(install_gcc_targets(targets).unwrap().iter().cloned());
}

View File

@ -1,6 +1,7 @@
use crate::emoji;
use crate::utils::*;
use anyhow::{bail, Result};
use embuild::cmd;
use espflash::Chip;
use log::{debug, info, warn};
use std::path::Path;
@ -8,24 +9,22 @@ use std::process::Stdio;
pub fn check_rust_installation(nightly_version: &str) -> Result<()> {
match std::process::Command::new("rustup")
.args(["toolchain", "list"])
.arg("toolchain")
.arg("list")
.stdout(Stdio::piped())
.output()
{
Ok(child_output) => {
info!("{} rustup found", emoji::INFO);
let result = String::from_utf8_lossy(&child_output.stdout);
if !result.contains(nightly_version) {
warn!("{} nightly toolchain not found", emoji::WARN);
if !result.contains("nightly") {
warn!("{} Rust nightly toolchain not found", emoji::WARN);
install_rust_nightly(nightly_version)?;
} else {
info!("{} {} toolchain found", emoji::INFO, nightly_version);
}
}
Err(e) => {
if let std::io::ErrorKind::NotFound = e.kind() {
warn!("{} rustup was not found.", emoji::WARN);
install_rustup()?;
install_rustup(nightly_version)?;
} else {
bail!("{} Error: {}", emoji::ERROR, e);
}
@ -35,134 +34,91 @@ pub fn check_rust_installation(nightly_version: &str) -> Result<()> {
}
pub fn install_riscv_target(version: &str) -> Result<()> {
match std::process::Command::new("rustup")
.arg("component")
.arg("add")
.arg("rust-src")
.arg("--toolchain")
.arg(version)
.stdout(Stdio::piped())
.output()
{
Ok(child_output) => {
let result = String::from_utf8_lossy(&child_output.stdout);
debug!(
"{} Rust-src for RiscV target installed suscesfully: {}",
emoji::CHECK,
result
);
}
Err(e) => {
bail!(
"{} Rust-src for RiscV target installation failed: {}",
emoji::ERROR,
e
);
}
}
match std::process::Command::new("rustup")
.arg("target")
.arg("add")
.arg("--toolchain")
.arg(version)
.arg("riscv32imc-unknown-none-elf")
.stdout(Stdio::piped())
.output()
{
Ok(child_output) => {
let result = String::from_utf8_lossy(&child_output.stdout);
debug!(
"{} RiscV target installed suscesfully: {}",
emoji::CHECK,
result
);
}
Err(e) => {
bail!("{} RiscV target installation failed: {}", emoji::ERROR, e);
}
}
info!("{} Installing Riscv target", emoji::WRENCH);
cmd!(
"rustup",
"component",
"add",
"rust-src",
"--toolchain",
version
)
.run()?;
cmd!(
"rustup",
"target",
"add",
"--toolchain",
version,
"riscv32imac-unknown-none-elf"
)
.run()?;
Ok(())
}
pub fn install_rustup() -> Result<()> {
pub 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,
)
.unwrap();
)?;
#[cfg(unix)]
let rustup_init_path = download_file(
"https://sh.rustup.rs".to_string(),
"rustup-init.sh",
&get_dist_path("rustup"),
false,
)
.unwrap();
info!("{} Installing rustup with nightly toolchain", emoji::WRENCH);
let mut arguments: Vec<String> = [].to_vec();
arguments.push(rustup_init_path);
arguments.push("--default-toolchain".to_string());
arguments.push("nightly".to_string());
arguments.push("--profile".to_string());
arguments.push("minimal".to_string());
arguments.push("-y".to_string());
run_command("/bin/bash", arguments, "".to_string())?;
)?;
info!(
"{} Installing rustup with {} toolchain",
emoji::WRENCH,
nightly_version
);
#[cfg(windows)]
// TO BE TESTED
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()?;
Ok(())
}
pub fn install_rust_nightly(version: &str) -> Result<()> {
info!("{} Installing {} toolchain", emoji::WRENCH, version);
match std::process::Command::new("rustup")
.arg("toolchain")
.arg("install")
.arg(version)
.arg("--profile")
.arg("minimal")
.stdout(Stdio::piped())
.output()
{
Ok(child_output) => {
let result = String::from_utf8_lossy(&child_output.stdout);
debug!("{} Result: {}", emoji::CHECK, result);
}
Err(e) => {
bail!("{} Error: {}", emoji::ERROR, e);
}
}
cmd!(
"rustup",
"toolchain",
"install",
version,
"--profile",
"minimal"
)
.run()?;
Ok(())
}
pub fn install_extra_crate(crate_name: &str) -> Result<()> {
info!("{} Installing {} crate", emoji::WRENCH, crate_name);
match std::process::Command::new("cargo")
.arg("install")
.arg(crate_name)
.stdout(Stdio::piped())
.output()
{
Ok(child_output) => {
let result = String::from_utf8_lossy(&child_output.stdout);
debug!(
"{} Crate {} installed suscesfully: {}",
emoji::CHECK,
crate_name,
result
);
}
Err(e) => {
bail!(
"{} Crate {} installation failed: {}",
emoji::ERROR,
crate_name,
e
);
}
}
cmd!("cargo", "install", crate_name).run()?;
Ok(())
}
@ -208,24 +164,24 @@ pub fn install_gcc_targets(targets: Vec<Chip>) -> Result<Vec<String>> {
pub fn install_gcc(gcc_target: &str) -> Result<()> {
let gcc_path = get_tool_path(gcc_target);
let extension = get_gcc_artifact_extension(guess_host_triple::guess_host_triple().unwrap());
debug!("{} gcc path: {}", emoji::DEBUG, gcc_path);
let gcc_file = format!(
"{}-gcc8_4_0-esp-2021r2-patch3-{}.tar.gz",
"{}-gcc8_4_0-esp-2021r2-patch3-{}.{}",
gcc_target,
get_gcc_arch(guess_host_triple::guess_host_triple().unwrap())
get_gcc_arch(guess_host_triple::guess_host_triple().unwrap()),
extension
);
let gcc_dist_url = format!(
"https://github.com/espressif/crosstool-NG/releases/download/esp-2021r2-patch3/{}",
gcc_file
);
match prepare_package_strip_prefix(&gcc_dist_url, gcc_path, "") {
Ok(_) => {
debug!("{} Package {} ready", emoji::CHECK, gcc_file);
}
Err(_e) => {
bail!("{} Unable to prepare {}", emoji::ERROR, gcc_file);
}
}
download_file(
gcc_dist_url,
&format!("{}.{}", gcc_target, extension),
&get_tool_path(""),
true,
)?;
Ok(())
}
@ -234,46 +190,53 @@ pub fn install_espidf(targets: &str, version: &str) -> Result<()> {
debug!("{} ESP-IDF Path: {}", emoji::DEBUG, espidf_path);
// #[cfg(windows)]
// match prepare_package(
// "https://dl.espressif.com/dl/idf-git/idf-git-2.30.1-win64.zip".to_string(),
// get_dist_path("idf-git-2.30.1-win64.zip").as_str(),
// get_tool_path("idf-git/2.30.1".to_string()),
// ) {
// Ok(_) => {
// debug!("Ok");
// }
// Err(_e) => {
// bail!("Failed");
// }
// }
// println!("{} Downloading Git package", emoji::DOWNLOAD);
// #[cfg(windows)]
// match prepare_package(
// download_file(
// // TODO: Store URL in a constant
// "https://dl.espressif.com/dl/idf-git/idf-git-2.30.1-win64.zip".to_string(),
// "idf-git-2.30.1-win64.zip",
// &get_tool_path("idf-git/2.30.1"),
// true,
// )
// .unwrap();
// #[cfg(windows)]
// let git_path = get_tool_path("idf-git/2.30.1/cmd/git.exe");
// #[cfg(unix)]
// let git_path = "/usr/bin/git".to_string();
// #[cfg(windows)]
// println!("{} Downloading Python package", emoji::DOWNLOAD);
// #[cfg(windows)]
// download_file(
// // TODO: Store the URL in RustToolchain
// "https://dl.espressif.com/dl/idf-python/idf-python-3.8.7-embed-win64.zip".to_string(),
// get_dist_path("idf-python-3.8.7-embed-win64.zip").as_str(),
// get_tool_path("idf-python/3.8.7".to_string()),
// ) {
// Ok(_) => {
// debug!("Ok");
// }
// Err(_e) => {
// bail!("Failed");
// }
// }
// "idf-python-3.8.7-embed-win64.zip",
// &get_tool_path("idf-python/3.8.7"),
// true,
// )
// .unwrap();
#[cfg(windows)]
let git_path = get_tool_path("idf-git/2.30.1/cmd/git.exe".to_string());
#[cfg(unix)]
let git_path = "/usr/bin/git".to_string();
let python_path = get_tool_path("idf-python/3.8.7/python.exe");
#[cfg(target_os = "linux")]
let python_path = "/usr/bin/python".to_string();
#[cfg(target_os = "macos")]
let python_path = "/usr/local/bin/python".to_string();
if !Path::new(&python_path).exists() {
bail!("{} Python not found at {}", emoji::ERROR, python_path);
}
// #[cfg(target_os = "macos")]
// let virtual_env_path = get_python_env_path("4.4", "3.10");
// #[cfg(not(target_os = "macos"))]
// let virtual_env_path = get_python_env_path("4.4", "3.9");
// TODO: See if needed
// update_property("gitPath".to_string(), git_path.clone());
#[cfg(windows)]
let python_path = get_tool_path("idf-python/3.8.7/python.exe".to_string());
#[cfg(unix)]
let python_path = "/usr/bin/python3".to_string();
// TODO: See idf-env to verify installation
// let virtual_env_path = get_python_env_path("4.4", "3.8");
// TODO: Use any git crate?
if !Path::new(&espidf_path).exists() {
let mut arguments: Vec<String> = [].to_vec();
@ -288,15 +251,15 @@ pub fn install_espidf(targets: &str, version: &str) -> Result<()> {
arguments.push("--recursive".to_string());
arguments.push("https://github.com/espressif/esp-idf.git".to_string());
arguments.push(espidf_path.clone());
info!("{} Dowloading esp-idf {}", emoji::DOWNLOAD, version);
match run_command(&git_path, arguments, "".to_string()) {
Ok(_) => {
debug!("{} Cloned esp-idf suscessfuly", emoji::CHECK);
}
Err(_e) => {
bail!("{} Cloned esp-idf failed", emoji::ERROR);
}
}
// info!("{} Dowloading esp-idf {}", emoji::DOWNLOAD, version);
// match run_command(git_path, arguments, "".to_string()) {
// Ok(_) => {
// debug!("{} Cloned esp-idf suscessfuly", emoji::CHECK);
// }
// Err(_e) => {
// bail!("{} Cloned esp-idf failed", emoji::ERROR);
// }
// }
}
info!(
"{} Installing esp-idf for {} with {}/install.sh",

View File

@ -63,7 +63,7 @@ pub fn get_llvm_version_with_underscores(llvm_version: &str) -> String {
llvm_dot_version.replace('.', "_")
}
pub fn get_artifact_file_extension(arch: &str) -> &str {
pub fn get_artifact_llvm_extension(arch: &str) -> &str {
match arch {
"x86_64-pc-windows-msvc" => "zip",
"x86_64-pc-windows-gnu" => "zip",
@ -82,6 +82,14 @@ pub fn get_llvm_arch(arch: &str) -> &str {
}
}
pub fn get_gcc_artifact_extension(arch: &str) -> &str {
match arch {
"x86_64-pc-windows-msvc" => "zip",
"x86_64-pc-windows-gnu" => "zip",
_ => "tar.gz",
}
}
pub fn get_gcc_arch(arch: &str) -> &str {
match arch {
"aarch64-apple-darwin" => "macos",
@ -111,7 +119,7 @@ pub fn get_tools_path() -> String {
}
pub fn get_tool_path(tool_name: &str) -> String {
format!("{}tools/{}", get_tools_path(), tool_name)
format!("{}/tools/{}", get_tools_path(), tool_name)
}
pub fn get_dist_path(tool_name: &str) -> String {
@ -201,62 +209,6 @@ pub fn download_file(
Ok(format!("{}/{}", output_directory, file_name))
}
pub fn prepare_package_strip_prefix(
package_url: &str,
output_directory: String,
strip_prefix: &str,
) -> Result<()> {
info!(
"{} Dowloading and uncompressing {} to {}",
emoji::DOWNLOAD,
&package_url,
&output_directory
);
if Path::new(&output_directory).exists() {
info!(
"{} Using cached directory: {}",
emoji::INFO,
output_directory
);
return Ok(());
}
let tools_path = get_tool_path("");
if !Path::new(&tools_path).exists() {
info!("{} Creating tools directory: {}", emoji::WRENCH, tools_path);
match fs::create_dir_all(&tools_path) {
Ok(_) => {
debug!("{} Directory tools_path created", emoji::CHECK);
}
Err(_e) => {
bail!("{} Directory tools_path creation failed", emoji::ERROR);
}
}
}
let resp = reqwest::blocking::get(package_url).unwrap();
let content_br = BufReader::new(resp);
if package_url.contains(".xz") {
let tarfile = XzDecoder::new(content_br);
let mut archive = Archive::new(tarfile);
archive.unpack(&tools_path).unwrap();
} else {
let tarfile = GzDecoder::new(content_br);
let mut archive = Archive::new(tarfile);
archive.unpack(&tools_path).unwrap();
}
if !strip_prefix.is_empty() {
let extracted_folder = format!("{}{}", &tools_path, strip_prefix);
info!(
"{} Renaming: {} to {}",
emoji::INFO,
&extracted_folder,
&output_directory
);
fs::rename(extracted_folder, output_directory).unwrap();
}
Ok(())
}
#[cfg(windows)]
pub fn run_command(
shell: String,
@ -314,42 +266,6 @@ pub fn run_command(
Ok(output)
}
// pub fn prepare_single_binary(
// package_url: &str,
// binary_name: &str,
// output_directory: &str,
// ) -> Result<String> {
// let tool_path = get_tool_path(output_directory);
// let binary_path = format!("{}/{}", tool_path, binary_name);
// if Path::new(&binary_path).exists() {
// info!("{} Using cached tool: {}", emoji::INFO, binary_path);
// return Ok(binary_path);
// }
// if !Path::new(&tool_path).exists() {
// info!("{} Creating tool directory: {}", emoji::WRENCH, tool_path);
// match fs::create_dir_all(&tool_path) {
// Ok(_) => {
// debug!("{} Succeded", emoji::CHECK);
// }
// Err(_e) => {
// bail!("{} Failed", emoji::ERROR);
// }
// }
// }
// match download_package(package_url.to_string(), binary_path.to_string()) {
// Ok(_) => {
// debug!("{} Succeded", emoji::CHECK);
// }
// Err(_e) => {
// info!("{} Failed", emoji::ERROR);
// }
// }
// Ok(binary_path)
// }
// pub fn get_python_env_path(idf_version: &str, python_version: &str) -> String {
// let tools_path = get_tools_path();
// format!(
@ -358,44 +274,6 @@ pub fn run_command(
// )
// }
// pub fn download_package(package_url: String, package_archive: String) -> Result<(), String> {
// let handle = Handle::current();
// let th = std::thread::spawn(move || {
// handle
// .block_on(fetch_file(
// package_url.to_string(),
// package_archive.to_string(),
// ))
// .unwrap();
// });
// th.join().unwrap();
// Ok(())
// }
// async fn fetch_file(url: String, output: String) -> Result<()> {
// if Path::new(&output).exists() {
// info!("{} Using cached archive: {}", emoji::INFO, output);
// return Ok(());
// }
// info!("{} Downloading {} to {}", emoji::DOWNLOAD, url, output);
// fetch_url(url, output).await
// }
// async fn fetch_url(url: String, output: String) -> Result<()> {
// let response = reqwest::get(&url).await;
// match response {
// Ok(r) => {
// let mut file = std::fs::File::create(output).unwrap();
// let mut content = Cursor::new(r.bytes().await.unwrap());
// std::io::copy(&mut content, &mut file).unwrap();
// return Ok(());
// }
// _ => {
// bail!("{} Download of {} failed", emoji::ERROR, url);
// }
// };
// }
pub fn print_arguments(args: &InstallOpts, arch: &str, targets: &Vec<Chip>, llvm_version: &str) {
debug!(
"{} Arguments: