mirror of
https://github.com/esp-rs/espup.git
synced 2025-09-28 21:30:47 +00:00
Code cleanup
This commit is contained in:
parent
84c6d64729
commit
582df61e2c
281
src/config.rs
281
src/config.rs
@ -1,281 +0,0 @@
|
||||
extern crate json;
|
||||
|
||||
use clap::Arg;
|
||||
use clap_nested::{Command, Commander, MultiCommand};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use md5;
|
||||
use std::env;
|
||||
use dirs::home_dir;
|
||||
use json::JsonValue;
|
||||
use crate::shell::run_command;
|
||||
|
||||
pub fn get_espressif_base_path() -> String {
|
||||
env::var("IDF_TOOLS_PATH").unwrap_or_else(|_e|
|
||||
home_dir().unwrap().display().to_string() + "/.espressif"
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Use &str like get_dist_path
|
||||
pub fn get_tool_path(tool_name:String) -> String {
|
||||
let tools_path = get_espressif_base_path();
|
||||
format!("{}/tools/{}", tools_path, tool_name)
|
||||
}
|
||||
|
||||
pub fn get_dist_path(tool_name:&str) -> String {
|
||||
let tools_path = get_espressif_base_path();
|
||||
format!("{}/dist/{}", tools_path, tool_name)
|
||||
}
|
||||
|
||||
pub fn get_python_env_path(idf_version: String, python_version: String) -> String {
|
||||
let tools_path = get_espressif_base_path();
|
||||
format!("{}/python_env/idf{}_py{}_env", tools_path, idf_version, python_version)
|
||||
}
|
||||
|
||||
pub fn get_selected_idf_path() -> String {
|
||||
let selected_idf_id = get_property("idfSelectedId".to_string());
|
||||
get_property_with_idf_id("path".to_string(), selected_idf_id)
|
||||
}
|
||||
|
||||
fn get_json_path() -> String {
|
||||
let idf_json_path = format!("{}/esp_idf.json", get_espressif_base_path());
|
||||
return idf_json_path;
|
||||
}
|
||||
|
||||
pub fn get_idf_id(idf_path: &str) -> String {
|
||||
let idf_path_with_slash = format!("{}", idf_path.replace("\\", "/"));
|
||||
let digest = md5::compute(idf_path_with_slash);
|
||||
return format!("esp-idf-{:x}", digest);
|
||||
}
|
||||
|
||||
fn bootstrap_json(_json_path: String, tools_path: String) {
|
||||
let template = json::object!{
|
||||
"$schema": "http://json-schema.org/schema#",
|
||||
"$id": "http://dl.espressif.com/dl/schemas/esp_idf",
|
||||
"_comment": "Configuration file for ESP-IDF Eclipse plugin.",
|
||||
"_warning": "Use / or \\ when specifying path. Single backslash is not allowed by JSON format.",
|
||||
"gitPath": "",
|
||||
"idfToolsPath": tools_path,
|
||||
"idfSelectedId": "",
|
||||
"idfInstalled": json::JsonValue::new_object()
|
||||
};
|
||||
fs::write(get_json_path(), template.to_string()).unwrap();
|
||||
}
|
||||
|
||||
fn load_json() -> json::JsonValue {
|
||||
let json_path = get_json_path();
|
||||
if !Path::new(&json_path).exists() {
|
||||
println!("Configuration file not found, creating new one: {}", json_path);
|
||||
bootstrap_json(json_path.clone(), get_espressif_base_path());
|
||||
}
|
||||
|
||||
let content = fs::read_to_string(json_path)
|
||||
.expect("Failure");
|
||||
return json::parse(&content.to_string()).unwrap();
|
||||
}
|
||||
|
||||
pub fn get_property(property_name: String) -> String {
|
||||
let parsed_json = load_json();
|
||||
return parsed_json[property_name].to_string();
|
||||
}
|
||||
|
||||
fn print_property(property_name: String) {
|
||||
print!("{}", &get_property(property_name));
|
||||
}
|
||||
|
||||
pub fn get_git_path() -> String {
|
||||
get_property("gitPath".to_string())
|
||||
}
|
||||
|
||||
pub fn get_property_with_idf_id(property_name: String, idf_id: String) -> String {
|
||||
let parsed_json = load_json();
|
||||
return parsed_json["idfInstalled"][idf_id][property_name].to_string();
|
||||
}
|
||||
|
||||
|
||||
pub fn get_property_with_path(property_name: String, idf_path: String) -> String {
|
||||
let parsed_json = load_json();
|
||||
let idf_id = get_idf_id(&idf_path);
|
||||
return parsed_json["idfInstalled"][idf_id][property_name].to_string();
|
||||
}
|
||||
|
||||
fn print_property_with_path(property_name: String, idf_path: String) {
|
||||
print!("{}", get_property_with_path(property_name, idf_path));
|
||||
}
|
||||
|
||||
fn print_property_with_id(property_name: String, idf_id: String) {
|
||||
print!("{}", get_property_with_idf_id(property_name, idf_id));
|
||||
}
|
||||
|
||||
pub fn update_property(property_name: String, property_value: String) {
|
||||
let mut parsed_json = load_json();
|
||||
parsed_json[property_name] = JsonValue::String(property_value);
|
||||
fs::write(get_json_path(), format!("{:#}", parsed_json)).unwrap();
|
||||
}
|
||||
|
||||
// pub fn add_idf_config(idf_path: String, version: String, python_path: String) {
|
||||
// let idf_id = get_idf_id(&idf_path);
|
||||
// let _data = json::object! {
|
||||
// version: version,
|
||||
// python: python_path,
|
||||
// path: idf_path
|
||||
// };
|
||||
|
||||
// let mut parsed_json = load_json();
|
||||
// parsed_json["idfInstalled"].insert(&idf_id, _data).unwrap();
|
||||
// parsed_json["idfSelectedId"] = JsonValue::String(idf_id);
|
||||
|
||||
// fs::write(get_json_path(), format!("{:#}", parsed_json)).unwrap();
|
||||
// }
|
||||
|
||||
// pub fn get_cmd<'a>() -> Command<'a, str> {
|
||||
// Command::new("get")
|
||||
// .description("Retrieve configuration")
|
||||
// .options(|app| {
|
||||
// app.arg(
|
||||
// Arg::with_name("property")
|
||||
// .short("p")
|
||||
// .long("property")
|
||||
// .help("Filter result for property name")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("idf-path")
|
||||
// .short("i")
|
||||
// .long("idf-path")
|
||||
// .help("Path to ESP-IDF")
|
||||
// .takes_value(true),
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("idf-id")
|
||||
// .short("j")
|
||||
// .long("idf-id")
|
||||
// .help("ESP-IDF installation ID")
|
||||
// .takes_value(true),
|
||||
// )
|
||||
// })
|
||||
// .runner(|_args, matches| {
|
||||
// if matches.is_present("property") {
|
||||
// let property_name = matches.value_of("property").unwrap().to_string();
|
||||
|
||||
// if matches.is_present("idf-id") {
|
||||
// let idf_id = matches.value_of("idf-id").unwrap().to_string();
|
||||
// print_property_with_id(property_name, idf_id);
|
||||
// } else if matches.is_present("idf-path") {
|
||||
// let idf_path = matches.value_of("idf-path").unwrap().to_string();
|
||||
// print_property_with_path(property_name, idf_path);
|
||||
// } else {
|
||||
// print_property(property_name);
|
||||
// }
|
||||
// } else {
|
||||
// let content = load_json();
|
||||
// println!("{:#}", &content);
|
||||
// }
|
||||
// Ok(())
|
||||
// })
|
||||
// }
|
||||
|
||||
fn open_idf_config() {
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push(get_json_path());
|
||||
match run_command("notepad".to_string(), arguments, "".to_string()) {
|
||||
Ok(_) => { println!("Ok"); },
|
||||
Err(_e) => { println!("Failed");}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_edit_cmd<'a>() -> Command<'a, str> {
|
||||
Command::new("edit")
|
||||
.description("Open configuration file in editor")
|
||||
.runner(|_args, _matches| {
|
||||
open_idf_config();
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
// pub fn get_add_cmd<'a>() -> Command<'a, str> {
|
||||
// Command::new("add")
|
||||
// .description("Add configuration")
|
||||
// .options(|app| {
|
||||
// app.arg(
|
||||
// Arg::with_name("python")
|
||||
// .short("p")
|
||||
// .long("python")
|
||||
// .help("Full path to Python binary")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("idf-path")
|
||||
// .short("i")
|
||||
// .long("idf-path")
|
||||
// .help("Path to ESP-IDF")
|
||||
// .takes_value(true),
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("idf-version")
|
||||
// .short("x")
|
||||
// .long("idf-version")
|
||||
// .help("ESP-IDF version")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("git")
|
||||
// .short("g")
|
||||
// .long("git")
|
||||
// .help("Full path to Git binary")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("name")
|
||||
// .short("n")
|
||||
// .long("name")
|
||||
// .help("Custom name of ESP-IDF installation")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// })
|
||||
// .runner(|_args, matches| {
|
||||
// let python_path = matches.value_of("python").unwrap().to_string();
|
||||
// let version = matches.value_of("idf-version").unwrap().to_string();
|
||||
// let idf_path = matches.value_of("idf-path").unwrap().to_string();
|
||||
// add_idf_config(idf_path, version, python_path);
|
||||
// Ok(())
|
||||
// })
|
||||
// }
|
||||
|
||||
fn get_set_runner(_args: &str, matches: &clap::ArgMatches) -> std::result::Result<(), clap::Error> {
|
||||
let git_path = matches.value_of("git").unwrap().to_string();
|
||||
update_property("gitPath".to_string(), git_path);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// pub fn get_set_cmd<'a>() -> Command<'a, str> {
|
||||
// Command::new("set")
|
||||
// .description("set configuration")
|
||||
// .options(|app| {
|
||||
// app.arg(
|
||||
// Arg::with_name("git")
|
||||
// .short("g")
|
||||
// .long("git")
|
||||
// .help("Full path to Git binary")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// })
|
||||
// .runner(|_args, matches|
|
||||
// get_set_runner(_args, matches)
|
||||
// )
|
||||
// }
|
||||
|
||||
|
||||
// pub fn get_multi_cmd<'a>() -> MultiCommand<'a, str, str> {
|
||||
// let multi_cmd: MultiCommand<str, str> = Commander::new()
|
||||
// .add_cmd(get_cmd())
|
||||
// .add_cmd(get_edit_cmd())
|
||||
// .add_cmd(get_add_cmd())
|
||||
// .add_cmd(get_set_cmd())
|
||||
// .into_cmd("config")
|
||||
|
||||
// // Optionally specify a description
|
||||
// .description("Maintain configuration of ESP-IDF installations.");
|
||||
|
||||
// return multi_cmd;
|
||||
// }
|
805
src/idf.rs
805
src/idf.rs
@ -1,805 +0,0 @@
|
||||
use clap::Arg;
|
||||
use clap_nested::{Command, Commander, MultiCommand};
|
||||
use git2::Repository;
|
||||
use std::path::Path;
|
||||
use tokio::runtime::Handle;
|
||||
|
||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
||||
use std::env;
|
||||
|
||||
use std::io::Read;
|
||||
use std::process::Stdio;
|
||||
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::config::get_selected_idf_path;
|
||||
use crate::config::get_espressif_base_path;
|
||||
use crate::config::{
|
||||
get_dist_path, get_git_path, get_python_env_path, get_tool_path, update_property,
|
||||
};
|
||||
use crate::package::prepare_package;
|
||||
use crate::shell::run_command;
|
||||
use dirs::home_dir;
|
||||
async fn excecute_async(command: String, arguments: Vec<String>) {
|
||||
let _child_process = tokio::process::Command::new(command)
|
||||
.args(arguments)
|
||||
.status()
|
||||
.await;
|
||||
}
|
||||
|
||||
fn execute_command(command: String, arguments: Vec<String>) -> Result<()> {
|
||||
let argument_string = arguments
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|i| format!("{} ", i.to_string()))
|
||||
.collect::<String>();
|
||||
println!("Executing: {} {}", command, argument_string);
|
||||
let handle = Handle::current().clone();
|
||||
let th = std::thread::spawn(move || handle.block_on(excecute_async(command, arguments)));
|
||||
th.join().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reset_repository(repository_path: String) -> Result<()> {
|
||||
let idf_path = Path::new(&repository_path);
|
||||
assert!(env::set_current_dir(&idf_path).is_ok());
|
||||
println!("Working directory: {}", idf_path.display());
|
||||
|
||||
let git_path = get_git_path();
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push("reset".to_string());
|
||||
arguments.push("--hard".to_string());
|
||||
assert!(execute_command(git_path, arguments).is_ok());
|
||||
|
||||
let mut arguments_submodule: Vec<String> = [].to_vec();
|
||||
arguments_submodule.push("submodule".to_string());
|
||||
arguments_submodule.push("foreach".to_string());
|
||||
arguments_submodule.push("git".to_string());
|
||||
arguments_submodule.push("reset".to_string());
|
||||
arguments_submodule.push("--hard".to_string());
|
||||
assert!(execute_command(get_git_path(), arguments_submodule).is_ok());
|
||||
|
||||
let mut arguments_clean: Vec<String> = [].to_vec();
|
||||
arguments_clean.push("clean".to_string());
|
||||
arguments_clean.push("force".to_string());
|
||||
arguments_clean.push("-d".to_string());
|
||||
assert!(execute_command(get_git_path(), arguments_clean).is_ok());
|
||||
|
||||
let mut arguments_status: Vec<String> = [].to_vec();
|
||||
arguments_status.push("status".to_string());
|
||||
assert!(execute_command(get_git_path(), arguments_status).is_ok());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_submodule(
|
||||
idf_path: String,
|
||||
submodule: String,
|
||||
depth: String,
|
||||
progress: bool,
|
||||
) -> Result<()> {
|
||||
let mut arguments_submodule: Vec<String> = [].to_vec();
|
||||
arguments_submodule.push("-C".to_string());
|
||||
arguments_submodule.push(idf_path);
|
||||
arguments_submodule.push("submodule".to_string());
|
||||
arguments_submodule.push("update".to_string());
|
||||
arguments_submodule.push("--depth".to_string());
|
||||
arguments_submodule.push(depth);
|
||||
if progress {
|
||||
arguments_submodule.push("--progress".to_string());
|
||||
}
|
||||
arguments_submodule.push("--recommend-shallow".to_string());
|
||||
arguments_submodule.push("--recursive".to_string());
|
||||
arguments_submodule.push(submodule);
|
||||
assert!(execute_command(get_git_path(), arguments_submodule).is_ok());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// fn get_reset_cmd<'a>() -> Command<'a, str> {
|
||||
// Command::new("reset")
|
||||
// .description("Reset ESP-IDF git repository to initial state and wipe out modified data")
|
||||
// .options(|app| {
|
||||
// app.arg(
|
||||
// Arg::with_name("idf-path")
|
||||
// .short("d")
|
||||
// .long("idf-path")
|
||||
// .help("Path to existing ESP-IDF")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// })
|
||||
// .runner(|_args, matches| {
|
||||
// if matches.value_of("idf-path").is_some() {
|
||||
// let dir = matches.value_of("idf-path").unwrap();
|
||||
// assert!(reset_repository(dir.to_string()).is_ok());
|
||||
// }
|
||||
// Ok(())
|
||||
// })
|
||||
// }
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_idf_base_directory() -> String {
|
||||
home_dir().unwrap().display().to_string() + "/.espressif"
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn get_esp_idf_directory(idf_name: String) -> String {
|
||||
format!("{}/{}", get_idf_base_directory(), idf_name).replace("/", "\\")
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_esp_idf_directory(idf_name: String) -> String {
|
||||
format!("{}/{}", get_idf_base_directory(), idf_name)
|
||||
}
|
||||
|
||||
fn get_install_runner(
|
||||
_args: &str,
|
||||
_matches: &clap::ArgMatches,
|
||||
) -> std::result::Result<(), clap::Error> {
|
||||
let esp_idf = get_esp_idf_directory("esp-idf-master/".to_string());
|
||||
println!("ESP-IDF Path: {}", esp_idf);
|
||||
|
||||
#[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(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
match prepare_package(
|
||||
"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(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
|
||||
#[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();
|
||||
|
||||
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/python".to_string();
|
||||
|
||||
let virtual_env_path = get_python_env_path("4.4".to_string(), "3.8".to_string());
|
||||
|
||||
if !Path::new(&esp_idf).exists() {
|
||||
// let clone_command = format!("git clone --shallow-since=2020-01-01 --jobs 8 --recursive git@github.com:espressif/esp-idf.git ");
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push("clone".to_string());
|
||||
arguments.push("--shallow-since=2020-01-01".to_string());
|
||||
arguments.push("--jobs".to_string());
|
||||
arguments.push("8".to_string());
|
||||
arguments.push("--recursive".to_string());
|
||||
arguments.push("https://github.com/espressif/esp-idf.git".to_string());
|
||||
// arguments.push("git@github.com:espressif/esp-idf.git".to_string());
|
||||
arguments.push(esp_idf.clone());
|
||||
println!("Cloning: {} {:?}", git_path, arguments);
|
||||
match run_command(git_path, arguments, "".to_string()) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !Path::new(&virtual_env_path).exists() {
|
||||
println!("Creating virtual environment: {}", virtual_env_path);
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push("-m".to_string());
|
||||
arguments.push("virtualenv".to_string());
|
||||
arguments.push(virtual_env_path.clone());
|
||||
match run_command(python_path, arguments, "".to_string()) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
let python_path = format!("{}/Scripts/python.exe", virtual_env_path);
|
||||
#[cfg(unix)]
|
||||
let python_path = format!("{}/bin/python", virtual_env_path);
|
||||
|
||||
let idf_tools = format!("{}/tools/idf_tools.py", esp_idf);
|
||||
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push(idf_tools.clone());
|
||||
arguments.push("install".to_string());
|
||||
match run_command(python_path.clone(), arguments, "".to_string()) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push(idf_tools);
|
||||
arguments.push("install-python-env".to_string());
|
||||
match run_command(python_path.clone(), arguments, "".to_string()) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
|
||||
// add_idf_config(esp_idf, "4.4".to_string(), python_path);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn install_espidf(targets: &str, version: String) -> Result<()> {
|
||||
let espidf_path = get_esp_idf_directory("frameworks/esp-idf".to_string());
|
||||
println!("ESP-IDF Path: {}", 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(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
match prepare_package(
|
||||
"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(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
|
||||
#[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();
|
||||
|
||||
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();
|
||||
|
||||
let virtual_env_path = get_python_env_path("4.4".to_string(), "3.8".to_string());
|
||||
// TODO: Use any git crate?
|
||||
if !Path::new(&espidf_path).exists() {
|
||||
// let clone_command = format!("git clone --shallow-since=2020-01-01 --jobs 8 --recursive git@github.com:espressif/esp-idf.git ");
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push("clone".to_string());
|
||||
arguments.push("--jobs".to_string());
|
||||
arguments.push("8".to_string());
|
||||
arguments.push("--branch".to_string());
|
||||
arguments.push(version);
|
||||
arguments.push("--depth".to_string());
|
||||
arguments.push("1".to_string());
|
||||
arguments.push("--shallow-submodules".to_string());
|
||||
arguments.push("--recursive".to_string());
|
||||
arguments.push("https://github.com/espressif/esp-idf.git".to_string());
|
||||
// arguments.push("git@github.com:espressif/esp-idf.git".to_string());
|
||||
arguments.push(espidf_path.clone());
|
||||
println!("Cloning: {} {:?}", git_path, arguments);
|
||||
match run_command(git_path, arguments, "".to_string()) {
|
||||
Ok(_) => {
|
||||
println!("Cloned esp-idf suscessfuly");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Cloned esp-idf failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("Installing esp-idf for {} with {}/install.sh", targets, espidf_path);
|
||||
let install_script_path = format!("{}/install.sh", espidf_path);
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push(targets.to_string());
|
||||
match run_command(install_script_path, arguments, "".to_string()) {
|
||||
Ok(_) => {
|
||||
println!("ESP-IDF installation succeeded");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("ESP-IDF installation failed");
|
||||
}
|
||||
}
|
||||
// match std::process::Command::new(install_script_path)
|
||||
// .arg("esp32 esp32s2")
|
||||
// .stdout(Stdio::piped())
|
||||
// .output()
|
||||
// {
|
||||
// Ok(child_output) => {
|
||||
// let result = String::from_utf8_lossy(&child_output.stdout);
|
||||
// println!("ESP-IDF installation succeeded: {}", result);
|
||||
// }
|
||||
// Err(e) => {
|
||||
// println!("ESP-IDF installation failed: {}", e);
|
||||
// }
|
||||
// }
|
||||
|
||||
println!("Installing CMake");
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
let mut idf_tools_scritp_path = format!("{}/tools/idf_tools.py", espidf_path);
|
||||
arguments.push(idf_tools_scritp_path);
|
||||
arguments.push("install".to_string());
|
||||
arguments.push("cmake".to_string());
|
||||
match run_command(python_path, arguments, "".to_string()) {
|
||||
Ok(_) => {
|
||||
println!("CMake installation succeeded");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("CMake installation failed");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// pub fn get_install_cmd<'a>() -> Command<'a, str> {
|
||||
// Command::new("install")
|
||||
// .description("Install new instance of IDF")
|
||||
// .options(|app| {
|
||||
// app.arg(
|
||||
// Arg::with_name("installer")
|
||||
// .short("e")
|
||||
// .long("installer")
|
||||
// .help("Path to installer binary"),
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("interactive")
|
||||
// .short("i")
|
||||
// .long("interactive")
|
||||
// .help("Run installation in interactive mode"),
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("upgrade")
|
||||
// .short("u")
|
||||
// .long("upgrade")
|
||||
// .takes_value(false)
|
||||
// .help("Upgrade existing installation"))
|
||||
// .arg(
|
||||
// Arg::with_name("idf-version")
|
||||
// .short("x")
|
||||
// .long("idf-version")
|
||||
// .takes_value(true)
|
||||
// .help("ESP-IDF version"))
|
||||
// .arg(
|
||||
// Arg::with_name("idf-path")
|
||||
// .short("d")
|
||||
// .long("idf-path")
|
||||
// .takes_value(true)
|
||||
// .help("ESP-IDF installation directory"))
|
||||
// .arg(
|
||||
// Arg::with_name("verbose")
|
||||
// .short("w")
|
||||
// .long("verbose")
|
||||
// .takes_value(false)
|
||||
// .help("display diagnostic log after installation"))
|
||||
// })
|
||||
// .runner(|_args, matches|
|
||||
// get_install_runner(_args, matches)
|
||||
// )
|
||||
// }
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_shell() -> String {
|
||||
"/bin/bash".to_string()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_initializer() -> String {
|
||||
format!("{}/export.sh", get_selected_idf_path())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn get_initializer_arguments() -> Vec<String> {
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push("-c".to_string());
|
||||
arguments.push(
|
||||
". ./export.sh;cd examples/get-started/blink;idf.py fullclean; idf.py build".to_string(),
|
||||
);
|
||||
arguments
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn get_shell() -> String {
|
||||
"powershell".to_string()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn get_initializer() -> String {
|
||||
format!("{}/Initialize-Idf.ps1", get_espressif_base_path())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn get_initializer_arguments() -> Vec<String> {
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push("-ExecutionPolicy".to_string());
|
||||
arguments.push("Bypass".to_string());
|
||||
arguments.push("-NoExit".to_string());
|
||||
arguments.push("-File".to_string());
|
||||
arguments.push(get_initializer());
|
||||
arguments
|
||||
}
|
||||
|
||||
fn get_shell_runner(
|
||||
_args: &str,
|
||||
_matches: &clap::ArgMatches,
|
||||
) -> std::result::Result<(), clap::Error> {
|
||||
println!("Starting process");
|
||||
// let root = Path::new("C:\\esp");
|
||||
// assert!(env::set_current_dir(&root).is_ok());
|
||||
// println!("Successfully changed working directory to {}!", root.display());
|
||||
|
||||
let process = std::process::Command::new(get_shell())
|
||||
.args(get_initializer_arguments())
|
||||
.stdin(Stdio::inherit())
|
||||
.stdout(Stdio::inherit())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
let mut s = String::new();
|
||||
match process.stdout.unwrap().read_to_string(&mut s) {
|
||||
Err(why) => panic!("couldn't read stdout: {}", why),
|
||||
Ok(_) => print!("{}", s),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// pub fn get_shell_cmd<'a>() -> Command<'a, str> {
|
||||
// Command::new("shell")
|
||||
// .description("Start the companion")
|
||||
// .options(|app| {
|
||||
// app.arg(
|
||||
// Arg::with_name("port")
|
||||
// .short("p")
|
||||
// .long("port")
|
||||
// .help("Name of communication port")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// })
|
||||
// .runner(|_args, matches| get_shell_runner(_args, matches) )
|
||||
// }
|
||||
|
||||
#[cfg(unix)]
|
||||
fn run_build(
|
||||
idf_path: &String,
|
||||
shell_initializer: &String,
|
||||
) -> std::result::Result<(), clap::Error> {
|
||||
// println!("Starting process");
|
||||
let root = Path::new(&idf_path);
|
||||
assert!(env::set_current_dir(&root).is_ok());
|
||||
|
||||
run_idf_command("cd examples/get-started/blink; idf.py fullclean; idf.py build".to_string());
|
||||
|
||||
//println!("output = {:?}", output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn run_idf_command(command: String) {
|
||||
match run_command(get_shell(), get_initializer_arguments(), command) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn run_build(
|
||||
idf_path: &String,
|
||||
_shell_initializer: &String,
|
||||
) -> std::result::Result<(), clap::Error> {
|
||||
// println!("Starting process");
|
||||
let root = Path::new(&idf_path);
|
||||
assert!(env::set_current_dir(&root).is_ok());
|
||||
|
||||
run_idf_command("cd examples/get-started/blink; idf.py fullclean; idf.py build\n".to_string());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_build_runner(
|
||||
_args: &str,
|
||||
matches: &clap::ArgMatches,
|
||||
) -> std::result::Result<(), clap::Error> {
|
||||
let build_repetitions: i32 = matches
|
||||
.value_of("repeat")
|
||||
.unwrap()
|
||||
.to_string()
|
||||
.parse()
|
||||
.unwrap();
|
||||
let idf_path = matches
|
||||
.value_of("idf-path")
|
||||
.unwrap_or(&*get_selected_idf_path())
|
||||
.to_string();
|
||||
|
||||
let initializer = get_initializer();
|
||||
println!("Number of CPU cores: {}", num_cpus::get());
|
||||
println!("ESP-IDF Shell Initializer: {}", initializer);
|
||||
println!("ESP-IDF Path: {}", idf_path);
|
||||
for _build_number in 0..build_repetitions {
|
||||
let start = Instant::now();
|
||||
match run_build(&idf_path, &initializer) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
let duration = start.elapsed();
|
||||
println!("Time elapsed in build: {:?}", duration);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn change_submodules_mirror(mut repo: Repository, submodule_url: String) {
|
||||
let mut change_set: Vec<(String, String)> = Vec::new();
|
||||
for submodule in repo.submodules().unwrap() {
|
||||
let repo_name = submodule.name().unwrap().to_string();
|
||||
let original_url = submodule.url().unwrap();
|
||||
|
||||
if !(original_url.starts_with("../../") || original_url.starts_with("https://github.com")) {
|
||||
println!("Submodule: {}, URL: {} - skip", repo_name, original_url);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut old_repo = original_url.split('/').last().unwrap();
|
||||
|
||||
// Correction of some names
|
||||
if old_repo.starts_with("unity") {
|
||||
old_repo = "Unity"
|
||||
} else if old_repo.starts_with("cexception") {
|
||||
old_repo = "CException"
|
||||
}
|
||||
|
||||
let new_url = format!("{}{}", submodule_url, old_repo);
|
||||
|
||||
change_set.push((repo_name, new_url));
|
||||
}
|
||||
|
||||
for submodule in change_set {
|
||||
println!("Submodule: {}, new URL: {}", submodule.0, submodule.1);
|
||||
match repo.submodule_set_url(&*submodule.0, &*submodule.1) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_mirror_switch_runner(
|
||||
_args: &str,
|
||||
matches: &clap::ArgMatches,
|
||||
) -> std::result::Result<(), clap::Error> {
|
||||
let idf_path = matches
|
||||
.value_of("idf-path")
|
||||
.unwrap_or(&*get_selected_idf_path())
|
||||
.to_string();
|
||||
let url = matches.value_of("url").unwrap().to_string();
|
||||
let submodule_url = matches.value_of("submodule-url").unwrap().to_string();
|
||||
|
||||
println!("Processing main repository...");
|
||||
match Repository::open(idf_path.clone()) {
|
||||
Ok(repo) => {
|
||||
//repo.find_remote("origin")?.url()
|
||||
if matches.is_present("url") {
|
||||
match repo.remote_set_url("origin", url.as_str()) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
change_submodules_mirror(repo, submodule_url.clone());
|
||||
}
|
||||
Err(e) => {
|
||||
println!("failed to open: {}", e.to_string());
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
println!("Processing submodules...");
|
||||
match Repository::open(idf_path.clone()) {
|
||||
Ok(repo) => {
|
||||
//repo.find_remote("origin")?.url()
|
||||
if matches.is_present("url") {
|
||||
match repo.remote_set_url("origin", url.as_str()) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for mut submodule_repo_reference in repo.submodules().unwrap() {
|
||||
match submodule_repo_reference.init(false) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
let progress = matches.is_present("progress");
|
||||
if matches.is_present("depth") {
|
||||
// git2 crate does not support depth for submodules, we need to call git instead
|
||||
let depth = matches.value_of("depth").unwrap().to_string();
|
||||
match update_submodule(
|
||||
idf_path.clone(),
|
||||
submodule_repo_reference.name().unwrap().to_string(),
|
||||
depth,
|
||||
progress,
|
||||
) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
match submodule_repo_reference.update(true, None) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
match submodule_repo_reference.open() {
|
||||
Ok(sub_repo) => {
|
||||
println!("Processing submodule: {:?}", sub_repo.workdir().unwrap());
|
||||
change_submodules_mirror(sub_repo, submodule_url.clone());
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Unable to update submodule");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("failed to open: {}", e.to_string());
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// pub fn get_build_cmd<'a>() -> Command<'a, str> {
|
||||
// Command::new("build")
|
||||
// .description("Start build process")
|
||||
// .options(|app| {
|
||||
// app.arg(
|
||||
// Arg::with_name("repeat")
|
||||
// .short("r")
|
||||
// .long("repeat")
|
||||
// .help("Number of repetitions of the same command")
|
||||
// .takes_value(true)
|
||||
// .default_value("1")
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("idf-path")
|
||||
// .short("p")
|
||||
// .long("idf-path")
|
||||
// .help("Path to ESP IDF source code repository")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("tools-path")
|
||||
// .short("t")
|
||||
// .long("tools-path")
|
||||
// .help("Path to Tools directory")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// })
|
||||
// .runner(|_args, matches|
|
||||
// get_build_runner(_args, matches)
|
||||
// )
|
||||
// }
|
||||
|
||||
// pub fn get_mirror_cmd<'a>() -> Command<'a, str> {
|
||||
// Command::new("mirror")
|
||||
// .description("Switch the URL of repository mirror")
|
||||
// .options(|app| {
|
||||
// app.arg(
|
||||
// Arg::with_name("url")
|
||||
// .short("u")
|
||||
// .long("url")
|
||||
// .help("Base URL of the main repo")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("idf-path")
|
||||
// .short("p")
|
||||
// .long("idf-path")
|
||||
// .help("Path to ESP IDF source code repository")
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("submodule-url")
|
||||
// .short("s")
|
||||
// .long("submodule-url")
|
||||
// .help("Base URL for submodule mirror")
|
||||
// .required(true)
|
||||
// .takes_value(true)
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("depth")
|
||||
// .short("d")
|
||||
// .long("depth")
|
||||
// .help("Create shallow clone of the repo and submodules")
|
||||
// .takes_value(true)
|
||||
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("progress")
|
||||
// .short("r")
|
||||
// .long("progress")
|
||||
// .help("Display progress status of git operation")
|
||||
// )
|
||||
// })
|
||||
// .runner(|_args, matches|
|
||||
// get_mirror_switch_runner(_args, matches)
|
||||
// )
|
||||
// }
|
||||
|
||||
// pub fn get_multi_cmd<'a>() -> MultiCommand<'a, str, str> {
|
||||
// let multi_cmd: MultiCommand<str, str> = Commander::new()
|
||||
// .add_cmd(get_build_cmd())
|
||||
// .add_cmd(get_install_cmd())
|
||||
// .add_cmd(get_mirror_cmd())
|
||||
// .add_cmd(get_reset_cmd())
|
||||
// .add_cmd(get_shell_cmd())
|
||||
// .into_cmd("idf")
|
||||
|
||||
// // Optionally specify a description
|
||||
// .description("Maintain configuration of ESP-IDF installations.");
|
||||
|
||||
// return multi_cmd;
|
||||
// }
|
324
src/main.rs
324
src/main.rs
@ -1,25 +1,29 @@
|
||||
extern crate clap;
|
||||
extern crate json;
|
||||
use clap::Parser;
|
||||
use clap_nested::Commander;
|
||||
use dirs::home_dir;
|
||||
// use clap_nested::Commander;
|
||||
// use dirs::home_dir;
|
||||
// use std::error::Error;
|
||||
use std::path::{Path, PathBuf};
|
||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
use crate::config::get_tool_path;
|
||||
use crate::idf::install_espidf;
|
||||
use crate::package::{prepare_package_strip_prefix, prepare_single_binary};
|
||||
use crate::shell::{run_command, update_env_path};
|
||||
// use crate::config::get_tool_path;
|
||||
// use crate::idf::install_espidf;
|
||||
// use crate::package::{prepare_package_strip_prefix, prepare_single_binary};
|
||||
// use crate::shell::{run_command, update_env_path};
|
||||
use crate::utils::*;
|
||||
use crate::toolchain::*;
|
||||
use espflash::Chip;
|
||||
use std::env;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::process::Stdio;
|
||||
use std::str::FromStr;
|
||||
mod config;
|
||||
mod idf;
|
||||
mod package;
|
||||
mod shell;
|
||||
use std::fs;
|
||||
// use std::env;
|
||||
// use std::io::{Error, ErrorKind};
|
||||
// use std::process::Stdio;
|
||||
// use std::str::FromStr;
|
||||
// mod config;
|
||||
// mod idf;
|
||||
// mod package;
|
||||
// mod shell;
|
||||
mod utils;
|
||||
mod toolchain;
|
||||
// use std::fs;
|
||||
|
||||
// General TODOs:
|
||||
// - Prettify prints (add emojis)
|
||||
@ -31,6 +35,7 @@ use std::fs;
|
||||
// - Add tests
|
||||
// - Clean unused code
|
||||
// - Add progress bar
|
||||
// - Shall we delete <espressif>/tools/rust and <espressif>/tools/rust-src?
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Opts {
|
||||
@ -146,7 +151,7 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
);
|
||||
let idf_tool_xtensa_elf_clang = format!(
|
||||
"{}/{}-{}",
|
||||
get_tool_path("xtensa-esp32-elf-clang".to_string()),
|
||||
get_tool_path("xtensa-esp32-elf-clang"),
|
||||
&llvm_version,
|
||||
arch
|
||||
);
|
||||
@ -178,7 +183,7 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
} else {
|
||||
match prepare_package_strip_prefix(
|
||||
&rust_dist_url,
|
||||
get_tool_path("rust".to_string()),
|
||||
get_tool_path("rust"),
|
||||
&format!("rust-nightly-{}", arch),
|
||||
) {
|
||||
Ok(_) => {
|
||||
@ -192,13 +197,13 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
println!(
|
||||
"{}/install.sh --destdir={} --prefix='' --without=rust-docs",
|
||||
get_tool_path("rust".to_string()),
|
||||
get_tool_path("rust"),
|
||||
args.toolchain_destination.display()
|
||||
);
|
||||
arguments.push("-c".to_string());
|
||||
arguments.push(format!(
|
||||
"{}/install.sh --destdir={} --prefix='' --without=rust-docs",
|
||||
get_tool_path("rust".to_string()),
|
||||
get_tool_path("rust"),
|
||||
args.toolchain_destination.display()
|
||||
));
|
||||
|
||||
@ -213,7 +218,7 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
|
||||
match prepare_package_strip_prefix(
|
||||
&rust_src_dist_url,
|
||||
get_tool_path("rust-src".to_string()),
|
||||
get_tool_path("rust-src"),
|
||||
"rust-src-nightly",
|
||||
) {
|
||||
Ok(_) => {
|
||||
@ -227,13 +232,13 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
println!(
|
||||
"{}/install.sh --destdir={} --prefix='' --without=rust-docs",
|
||||
get_tool_path("rust-src".to_string()),
|
||||
get_tool_path("rust-src"),
|
||||
args.toolchain_destination.display()
|
||||
);
|
||||
arguments.push("-c".to_string());
|
||||
arguments.push(format!(
|
||||
"{}/install.sh --destdir={} --prefix='' --without=rust-docs",
|
||||
get_tool_path("rust-src".to_string()),
|
||||
get_tool_path("rust-src"),
|
||||
args.toolchain_destination.display()
|
||||
));
|
||||
match run_command("/bin/bash".to_string(), arguments, "".to_string()) {
|
||||
@ -259,7 +264,7 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
match prepare_package_strip_prefix(
|
||||
&llvm_url,
|
||||
get_tool_path(
|
||||
format!("xtensa-esp32-elf-clang-{}-{}", &llvm_version, llvm_arch).to_string(),
|
||||
&format!("xtensa-esp32-elf-clang-{}-{}", llvm_version, llvm_arch),
|
||||
),
|
||||
"",
|
||||
) {
|
||||
@ -273,7 +278,7 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
}
|
||||
let libclang_path = format!(
|
||||
"{}/lib",
|
||||
get_tool_path("xtensa-esp32-elf-clang".to_string())
|
||||
get_tool_path("xtensa-esp32-elf-clang")
|
||||
);
|
||||
println!("export LIBCLANG_PATH=\"{}\"", &libclang_path);
|
||||
exports.push(format!("export LIBCLANG_PATH=\"{}\"", &libclang_path));
|
||||
@ -287,10 +292,10 @@ fn install(args: InstallOpts) -> Result<()> {
|
||||
|
||||
|
||||
if args.espidf_version.is_some() {
|
||||
idf::install_espidf(&args.build_target, args.espidf_version.unwrap())?;
|
||||
install_espidf(&args.build_target, args.espidf_version.unwrap())?;
|
||||
exports.push(format!(
|
||||
"export IDF_TOOLS_PATH=\"{}\"",
|
||||
config::get_espressif_base_path()
|
||||
get_espressif_base_path()
|
||||
));
|
||||
exports.push(format!(". ./{}/export.sh\"", "TODO:UPDATE"));
|
||||
} else {
|
||||
@ -361,274 +366,7 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_rust_installer(arch: &str) -> &str {
|
||||
match arch {
|
||||
"x86_64-pc-windows-msvc" => "",
|
||||
"x86_64-pc-windows-gnu" => "",
|
||||
_ => "./install.sh",
|
||||
}
|
||||
}
|
||||
|
||||
fn install_rust_nightly(version: &str) {
|
||||
println!("installing nightly toolchain");
|
||||
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);
|
||||
println!("Result: {}", result);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn install_riscv_target(version: &str){
|
||||
|
||||
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);
|
||||
println!("Rust-src for RiscV target installed suscesfully: {}", result);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Rust-src for RiscV target installation failed: {}", 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);
|
||||
println!("RiscV target installed suscesfully: {}", result);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("RiscV target installation failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn install_rustup() {
|
||||
#[cfg(windows)]
|
||||
let rustup_init_path =
|
||||
prepare_single_binary("https://win.rustup.rs/x86_64", "rustup-init.exe", "rustup");
|
||||
#[cfg(unix)]
|
||||
let rustup_init_path = prepare_single_binary("https://sh.rustup.rs/", "rustup-init", "rustup");
|
||||
println!("rustup stable");
|
||||
match std::process::Command::new(rustup_init_path)
|
||||
.arg("--default-toolchain")
|
||||
.arg("none")
|
||||
.arg("--profile")
|
||||
.arg("minimal")
|
||||
.arg("-y")
|
||||
.stdout(Stdio::piped())
|
||||
.output()
|
||||
{
|
||||
Ok(child_output) => {
|
||||
let result = String::from_utf8_lossy(&child_output.stdout);
|
||||
println!("{}", result);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_llvm_version_with_underscores(llvm_version: &str) -> String {
|
||||
let version: Vec<&str> = llvm_version.split("-").collect();
|
||||
let llvm_dot_version = version[1];
|
||||
llvm_dot_version.replace(".", "_")
|
||||
}
|
||||
|
||||
fn get_artifact_file_extension(arch: &str) -> &str {
|
||||
match arch {
|
||||
"x86_64-pc-windows-msvc" => "zip",
|
||||
"x86_64-pc-windows-gnu" => "zip",
|
||||
_ => "tar.xz",
|
||||
}
|
||||
}
|
||||
|
||||
fn get_llvm_arch(arch: &str) -> &str {
|
||||
match arch {
|
||||
"aarch64-apple-darwin" => "macos",
|
||||
"x86_64-apple-darwin" => "macos",
|
||||
"x86_64-unknown-linux-gnu" => "linux-amd64",
|
||||
"x86_64-pc-windows-msvc" => "win64",
|
||||
"x86_64-pc-windows-gnu" => "win64",
|
||||
_ => arch,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_gcc_arch(arch: &str) -> &str {
|
||||
match arch {
|
||||
"aarch64-apple-darwin" => "macos",
|
||||
"aarch64-unknown-linux-gnu" => "linux-arm64",
|
||||
"x86_64-apple-darwin" => "macos",
|
||||
"x86_64-unknown-linux-gnu" => "linux-amd64",
|
||||
"x86_64-pc-windows-msvc" => "win64",
|
||||
"x86_64-pc-windows-gnu" => "win64",
|
||||
_ => arch,
|
||||
}
|
||||
}
|
||||
|
||||
fn install_gcc_targets(targets: Vec<Chip>) -> Result<Vec<String>> {
|
||||
let mut exports: Vec<String> = Vec::new();
|
||||
for target in targets {
|
||||
match target {
|
||||
Chip::Esp32 => {
|
||||
install_gcc("xtensa-esp32-elf");
|
||||
exports.push(format!(
|
||||
"export PATH={}:$PATH",
|
||||
get_tool_path("xtensa-esp32-elf/bin".to_string())
|
||||
));
|
||||
}
|
||||
Chip::Esp32s2 => {
|
||||
install_gcc("xtensa-esp32s2-elf");
|
||||
exports.push(format!(
|
||||
"export PATH={}:$PATH",
|
||||
get_tool_path("xtensa-esp32s2-elf/bin".to_string())
|
||||
));
|
||||
}
|
||||
Chip::Esp32s3 => {
|
||||
install_gcc("xtensa-esp32s3-elf");
|
||||
exports.push(format!(
|
||||
"export PATH={}:$PATH",
|
||||
get_tool_path("xtensa-esp32s3-elf/bin".to_string())
|
||||
));
|
||||
}
|
||||
Chip::Esp32c3 => {
|
||||
install_gcc("riscv32-esp-elf");
|
||||
exports.push(format!(
|
||||
"export PATH={}:$PATH",
|
||||
get_tool_path("riscv32-esp-elf/bin".to_string())
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
println!("Unknown target")
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
fn install_gcc(gcc_target: &str) {
|
||||
let gcc_path = get_tool_path(gcc_target.to_string());
|
||||
println!("gcc path: {}", gcc_path);
|
||||
// if Path::new(&gcc_path).exists() {
|
||||
// println!("Previous installation of GCC for target: {}", gcc_path);
|
||||
// // return Ok(());
|
||||
// } else {
|
||||
// fs::create_dir_all(&gcc_path).unwrap();
|
||||
let gcc_file = format!(
|
||||
"{}-gcc8_4_0-esp-2021r2-patch3-{}.tar.gz",
|
||||
gcc_target,
|
||||
get_gcc_arch(guess_host_triple::guess_host_triple().unwrap())
|
||||
);
|
||||
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(_) => {
|
||||
println!("Package {} ready", gcc_file);
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Unable to prepare {}", gcc_file);
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
// TODO: Create test for this function
|
||||
fn parse_targets(build_target: &str) -> Result<Vec<Chip>> {
|
||||
println!("Parsing targets: {}", build_target);
|
||||
let mut chips: Vec<Chip> = Vec::new();
|
||||
if build_target.contains("all") {
|
||||
chips.push(Chip::Esp32);
|
||||
chips.push(Chip::Esp32s2);
|
||||
chips.push(Chip::Esp32s3);
|
||||
chips.push(Chip::Esp32c3);
|
||||
return Ok(chips);
|
||||
}
|
||||
let mut targets: Vec<&str>;
|
||||
if build_target.contains(' ') || build_target.contains(',') {
|
||||
targets = build_target.split([',', ' ']).collect();
|
||||
} else {
|
||||
targets = vec![build_target];
|
||||
}
|
||||
for target in targets {
|
||||
match target {
|
||||
"esp32" => chips.push(Chip::Esp32),
|
||||
"esp32s2" => chips.push(Chip::Esp32s2),
|
||||
"esp32s3" => chips.push(Chip::Esp32s3),
|
||||
"esp32c3" => chips.push(Chip::Esp32c3),
|
||||
_ => {
|
||||
return Err(Box::new(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Unknown target: {}", target),
|
||||
)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(chips)
|
||||
}
|
||||
|
||||
fn parse_llvm_version(llvm_version: &str) -> Result<String> {
|
||||
let parsed_version = match llvm_version {
|
||||
"13" => "esp-13.0.0-20211203",
|
||||
"14" => "esp-14.0.0-20220415",
|
||||
"15" => "", // TODO: Fill when released
|
||||
_ => {
|
||||
return Err(Box::new(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("Unknown LLVM Version: {}", llvm_version),
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
Ok(parsed_version.to_string())
|
||||
}
|
||||
|
||||
fn check_rust_installation(nightly_version: &str) {
|
||||
match std::process::Command::new("rustup")
|
||||
.args(["toolchain", "list"])
|
||||
.stdout(Stdio::piped())
|
||||
.output()
|
||||
{
|
||||
Ok(child_output) => {
|
||||
println!("rustup found.");
|
||||
let result = String::from_utf8_lossy(&child_output.stdout);
|
||||
if !result.contains(nightly_version) {
|
||||
println!("nightly toolchain not found");
|
||||
install_rust_nightly(nightly_version);
|
||||
} else {
|
||||
println!("nightly toolchain found.");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error: {}", e);
|
||||
install_rustup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
317
src/package.rs
317
src/package.rs
@ -1,317 +0,0 @@
|
||||
use anyhow::Context;
|
||||
use std::fs::File;
|
||||
use std::io::Cursor;
|
||||
use std::{path::{Component::Normal, Path, PathBuf}};
|
||||
use std::{fs, io};
|
||||
use tar::Archive;
|
||||
use xz2::read::XzDecoder;
|
||||
use crate::config::{get_dist_path, get_tool_path};
|
||||
use flate2::bufread::GzDecoder;
|
||||
use std::io::BufReader;
|
||||
use tokio::runtime::Handle;
|
||||
|
||||
type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
|
||||
|
||||
pub fn unzip(file_path: String, output_directory: String) -> Result<()> {
|
||||
let file_name = std::path::Path::new(&file_path);
|
||||
let file = fs::File::open(&file_name).unwrap();
|
||||
|
||||
let mut archive = zip::ZipArchive::new(file).unwrap();
|
||||
|
||||
for i in 0..archive.len() {
|
||||
let mut file = archive.by_index(i).unwrap();
|
||||
let file_outpath = match file.enclosed_name() {
|
||||
Some(path) => path.to_owned(),
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// Add path prefix to extract the file
|
||||
let mut outpath = std::path::PathBuf::new();
|
||||
outpath.push(&output_directory);
|
||||
outpath.push(file_outpath);
|
||||
|
||||
{
|
||||
let comment = file.comment();
|
||||
if !comment.is_empty() {
|
||||
println!("File {} comment: {}", i, comment);
|
||||
}
|
||||
}
|
||||
|
||||
if (&*file.name()).ends_with('/') {
|
||||
println!("* extracted: \"{}\"", outpath.display());
|
||||
fs::create_dir_all(&outpath).unwrap();
|
||||
} else {
|
||||
println!(
|
||||
"* extracted: \"{}\" ({} bytes)",
|
||||
outpath.display(),
|
||||
file.size()
|
||||
);
|
||||
if let Some(p) = outpath.parent() {
|
||||
if !p.exists() {
|
||||
fs::create_dir_all(&p).unwrap();
|
||||
}
|
||||
}
|
||||
let mut outfile = fs::File::create(&outpath).unwrap();
|
||||
io::copy(&mut file, &mut outfile).unwrap();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unzip_strip_prefix(
|
||||
file_path: String,
|
||||
output_directory: String,
|
||||
strip_prefix: &str,
|
||||
) -> Result<()> {
|
||||
let file_name = std::path::Path::new(&file_path);
|
||||
let file = fs::File::open(&file_name).unwrap();
|
||||
|
||||
let mut archive = zip::ZipArchive::new(file).unwrap();
|
||||
|
||||
for i in 0..archive.len() {
|
||||
let mut file = archive.by_index(i).unwrap();
|
||||
let file_outpath = match file.enclosed_name() {
|
||||
Some(path) => path.to_owned(),
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// Add path prefix to extract the file
|
||||
let mut outpath = std::path::PathBuf::new();
|
||||
outpath.push(&output_directory);
|
||||
|
||||
// Skip files in top level directories which are not under directory with prefix
|
||||
if !file_outpath.starts_with(strip_prefix) {
|
||||
println!("* skipped: \"{}\"", file_outpath.display());
|
||||
continue;
|
||||
}
|
||||
|
||||
let stripped_file_outpath = file_outpath.strip_prefix(strip_prefix).unwrap();
|
||||
outpath.push(stripped_file_outpath);
|
||||
|
||||
{
|
||||
let comment = file.comment();
|
||||
if !comment.is_empty() {
|
||||
println!("File {} comment: {}", i, comment);
|
||||
}
|
||||
}
|
||||
|
||||
if (&*file.name()).ends_with('/') {
|
||||
if !Path::new(file.name()).exists() {
|
||||
println!("* created: \"{}\"", outpath.display());
|
||||
fs::create_dir_all(&outpath).unwrap();
|
||||
}
|
||||
} else {
|
||||
println!(
|
||||
"* extracted: \"{}\" ({} bytes)",
|
||||
outpath.display(),
|
||||
file.size()
|
||||
);
|
||||
if let Some(p) = outpath.parent() {
|
||||
if !p.exists() {
|
||||
fs::create_dir_all(&p).unwrap();
|
||||
}
|
||||
}
|
||||
let mut outfile = fs::File::create(&outpath).unwrap();
|
||||
io::copy(&mut file, &mut outfile).unwrap();
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn untar_strip_prefix(
|
||||
file_path: String,
|
||||
output_directory: String,
|
||||
strip_prefix: &str,
|
||||
) -> Result<()> {
|
||||
println!(
|
||||
"Untar: file {} output_dir {} strip_prefix {}",
|
||||
file_path, output_directory, strip_prefix
|
||||
);
|
||||
let tar_xz = File::open(file_path)?;
|
||||
let tar = XzDecoder::new(tar_xz);
|
||||
let mut archive = Archive::new(tar);
|
||||
archive
|
||||
.entries()?
|
||||
.filter_map(|e| e.ok())
|
||||
.map(|mut entry| -> Result<PathBuf> {
|
||||
let path = entry.path()?.strip_prefix(strip_prefix)?.to_owned();
|
||||
let full_path = format!("{}/{}", output_directory, path.display().to_string());
|
||||
entry.unpack(&full_path)?;
|
||||
Ok(full_path.parse().unwrap())
|
||||
})
|
||||
.filter_map(|e| e.ok())
|
||||
.for_each(|x| println!("> {}", x.display()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
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)?;
|
||||
let mut content = Cursor::new(r.bytes().await?);
|
||||
std::io::copy(&mut content, &mut file)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
_ => {
|
||||
println!("Download of {} failed", url);
|
||||
// Exit code is 0, there is temporal issue with Windows Installer which does not recover from error exit code
|
||||
#[cfg(windows)]
|
||||
std::process::exit(0);
|
||||
#[cfg(unix)]
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async fn download_file(url: String, output: String) -> Result<()> {
|
||||
if Path::new(&output).exists() {
|
||||
println!("Using cached archive: {}", output);
|
||||
return Ok(());
|
||||
}
|
||||
println!("Downloading {} to {}", url, output);
|
||||
fetch_url(url, output).await
|
||||
}
|
||||
|
||||
pub fn download_package(package_url: String, package_archive: String) -> Result<()> {
|
||||
let handle = Handle::current().clone();
|
||||
let th = std::thread::spawn(move || {
|
||||
handle
|
||||
.block_on(download_file(package_url, package_archive))
|
||||
.unwrap();
|
||||
});
|
||||
Ok(th.join().unwrap())
|
||||
}
|
||||
|
||||
pub fn prepare_package(
|
||||
package_url: String,
|
||||
package_archive: &str,
|
||||
output_directory: String,
|
||||
) -> Result<()> {
|
||||
if Path::new(&output_directory).exists() {
|
||||
println!("Using cached directory: {}", output_directory);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let dist_path = get_dist_path("");
|
||||
if !Path::new(&dist_path).exists() {
|
||||
println!("Creating dist directory: {}", dist_path);
|
||||
match fs::create_dir_all(&dist_path) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let package_archive = get_dist_path(package_archive);
|
||||
|
||||
match download_package(package_url, package_archive.clone()) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
unzip(package_archive, output_directory).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn prepare_single_binary(
|
||||
package_url: &str,
|
||||
binary_name: &str,
|
||||
output_directory: &str,
|
||||
) -> String {
|
||||
let tool_path = get_tool_path(output_directory.to_string());
|
||||
let binary_path = format!("{}/{}", tool_path, binary_name);
|
||||
|
||||
if Path::new(&binary_path).exists() {
|
||||
println!("Using cached tool: {}", binary_path);
|
||||
return binary_path;
|
||||
}
|
||||
|
||||
if !Path::new(&tool_path).exists() {
|
||||
println!("Creating tool directory: {}", tool_path);
|
||||
match fs::create_dir_all(&tool_path) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match download_package(package_url.to_string(), binary_path.to_string()) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
return binary_path;
|
||||
}
|
||||
|
||||
pub fn prepare_package_strip_prefix(
|
||||
package_url: &str,
|
||||
output_directory: String,
|
||||
strip_prefix: &str,
|
||||
) -> Result<()> {
|
||||
println!("prepare_package_strip_prefix:
|
||||
-pacakge_url: {}
|
||||
-output dir: {}
|
||||
-strip_prefix: {}", &package_url, &output_directory, &strip_prefix);
|
||||
|
||||
if Path::new(&output_directory).exists() {
|
||||
println!("Using cached directory: {}", output_directory);
|
||||
return Ok(());
|
||||
}
|
||||
let tools_path = get_tool_path("".to_string());
|
||||
if !Path::new(&tools_path).exists() {
|
||||
println!("Creating tools directory: {}", tools_path);
|
||||
match fs::create_dir_all(&tools_path) {
|
||||
Ok(_) => {
|
||||
println!("tools_path created");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("tools_path creating failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
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)?;
|
||||
} else {
|
||||
let tarfile = GzDecoder::new(content_br);
|
||||
let mut archive = Archive::new(tarfile);
|
||||
archive.unpack(&tools_path)?;
|
||||
}
|
||||
if !strip_prefix.is_empty(){
|
||||
let extracted_folder = format!("{}{}", &tools_path, strip_prefix);
|
||||
println!("Renaming: {} to {}", &extracted_folder, &output_directory);
|
||||
fs::rename(extracted_folder, output_directory)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub fn remove_package(package_archive: &str, output_directory: &str) -> Result<()> {
|
||||
if Path::new(package_archive).exists() {
|
||||
fs::remove_file(package_archive)
|
||||
.with_context(|| format!("Unable to delete `{}`", package_archive))?;
|
||||
}
|
||||
if Path::new(output_directory).exists() {
|
||||
fs::remove_dir_all(output_directory)
|
||||
.with_context(|| format!("Unable to delete `{}`", output_directory))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
179
src/shell.rs
179
src/shell.rs
@ -1,179 +0,0 @@
|
||||
use std::process::Stdio;
|
||||
use std::io::{Write};
|
||||
use std::env;
|
||||
use clap::Arg;
|
||||
use clap_nested::{Command, Commander, MultiCommand};
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn run_command(shell: String, arguments: Vec<String>, command: String) -> std::result::Result<(), clap::Error> {
|
||||
// println!("arguments = {:?}", arguments);
|
||||
let mut child_process = std::process::Command::new(shell)
|
||||
.args(arguments)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()?;
|
||||
{
|
||||
let child_stdin = child_process.stdin.as_mut().unwrap();
|
||||
child_stdin.write_all(&*command.into_bytes())?;
|
||||
// Close stdin to finish and avoid indefinite blocking
|
||||
drop(child_stdin);
|
||||
|
||||
}
|
||||
let _output = child_process.wait_with_output()?;
|
||||
|
||||
// println!("output = {:?}", output);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn run_command(shell: String, arguments: Vec<String>, command: String) -> std::result::Result<(), clap::Error> {
|
||||
// Unix - pass command as parameter for initializer
|
||||
let mut arguments = arguments.clone();
|
||||
if !command.is_empty() {
|
||||
arguments.push(command);
|
||||
}
|
||||
|
||||
//println!("arguments = {:?}", arguments);
|
||||
let mut child_process = std::process::Command::new(shell)
|
||||
.args(arguments)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()?;
|
||||
{
|
||||
|
||||
}
|
||||
let output = child_process.wait_with_output()?;
|
||||
//println!("output = {:?}", output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn wide_null(s: &str) -> Vec<u16> {
|
||||
s.encode_utf16().chain(Some(0)).collect()
|
||||
}
|
||||
#[cfg(windows)]
|
||||
pub fn set_env_variable(key:&str, value:String) {
|
||||
use winreg::{enums::HKEY_CURRENT_USER, RegKey};
|
||||
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
||||
let (env, _) = hkcu.create_subkey("Environment").unwrap(); // create_subkey opens with write permissions
|
||||
env.set_value(key, &value).unwrap();
|
||||
// It's necessary to notify applications about update of the environment
|
||||
// https://stackoverflow.com/questions/19705401/how-to-set-system-environment-variable-in-c/19705691#19705691
|
||||
let param = wide_null("Environment").as_ptr() as winapi::shared::minwindef::LPARAM;
|
||||
unsafe {
|
||||
winapi::um::winuser::SendNotifyMessageW(
|
||||
winapi::um::winuser::HWND_BROADCAST,
|
||||
winapi::um::winuser::WM_SETTINGCHANGE,
|
||||
0,
|
||||
param
|
||||
);
|
||||
}
|
||||
}
|
||||
#[cfg(unix)]
|
||||
pub fn set_env_variable(key:&str, value:&str) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn append_path(original_path: &str, new_path: &str) -> String {
|
||||
if original_path.len() == 0 {
|
||||
return new_path.to_string();
|
||||
}
|
||||
|
||||
if original_path.contains(new_path) {
|
||||
return original_path.to_string();
|
||||
}
|
||||
|
||||
if original_path.chars().last().unwrap() != ';' {
|
||||
return format!("{};{};", original_path, new_path);
|
||||
}
|
||||
|
||||
format!("{}{};", original_path, new_path)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::shell::append_path;
|
||||
|
||||
#[test]
|
||||
fn test_append_path() {
|
||||
assert_eq!(append_path("",""), "");
|
||||
assert_eq!(append_path("a",""), "a");
|
||||
assert_eq!(append_path("a","b"), "a;b;");
|
||||
assert_eq!(append_path("","b"), "b");
|
||||
assert_eq!(append_path("a;b;","b"), "a;b;");
|
||||
assert_eq!(append_path("a;c;","b"), "a;c;b;");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn update_env_variable(variable_name: &str, value: &str) {
|
||||
use winreg::{enums::HKEY_CURRENT_USER, RegKey};
|
||||
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
||||
let env = hkcu.open_subkey("Environment").unwrap();
|
||||
let env_path:String = env.get_value(variable_name).unwrap();
|
||||
let updated_env_path = append_path(env_path.as_str(), value);
|
||||
set_env_variable(variable_name, updated_env_path);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn update_env_path(value: &str) {
|
||||
update_env_variable("PATH", value);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn update_env_variable(variable_name: &str, value: &str) {
|
||||
env::set_var(variable_name, value);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn update_env_path(value: &str) {
|
||||
let env_path:String = env::var("PATH").unwrap();
|
||||
let updated_env_path = append_path(env_path.as_str(), value);
|
||||
env::set_var("PATH", updated_env_path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// pub fn get_cmd<'a>() -> Command<'a, str> {
|
||||
// Command::new("append")
|
||||
// .description("Append path to environment variable")
|
||||
// .options(|app| {
|
||||
// app.arg(
|
||||
// Arg::with_name("variable")
|
||||
// .short("v")
|
||||
// .long("variable")
|
||||
// .help("Name of environment variable")
|
||||
// .takes_value(true),
|
||||
// )
|
||||
// .arg(
|
||||
// Arg::with_name("path")
|
||||
// .short("p")
|
||||
// .long("path")
|
||||
// .help("Path which should be added to the variable")
|
||||
// .takes_value(true),
|
||||
// )
|
||||
// })
|
||||
// .runner(|_args, matches| {
|
||||
// let variable_name = matches.value_of("variable").unwrap().to_string();
|
||||
// let path_value = matches.value_of("path").unwrap().to_string();
|
||||
// update_env_variable(variable_name.as_str(), path_value.as_str());
|
||||
// Ok(())
|
||||
// })
|
||||
// }
|
||||
|
||||
// pub fn get_multi_cmd<'a>() -> MultiCommand<'a, str, str> {
|
||||
// let multi_cmd: MultiCommand<str, str> = Commander::new()
|
||||
// .add_cmd(get_cmd())
|
||||
// .into_cmd("shell")
|
||||
|
||||
// // Optionally specify a description
|
||||
// .description("Detection of Antivirus and handling exception registration.");
|
||||
|
||||
// return multi_cmd;
|
||||
// }
|
297
src/toolchain.rs
Normal file
297
src/toolchain.rs
Normal file
@ -0,0 +1,297 @@
|
||||
use std::process::Stdio;
|
||||
use espflash::Chip;
|
||||
use crate::utils::*;
|
||||
use std::path::Path;
|
||||
pub fn check_rust_installation(nightly_version: &str) {
|
||||
match std::process::Command::new("rustup")
|
||||
.args(["toolchain", "list"])
|
||||
.stdout(Stdio::piped())
|
||||
.output()
|
||||
{
|
||||
Ok(child_output) => {
|
||||
println!("rustup found.");
|
||||
let result = String::from_utf8_lossy(&child_output.stdout);
|
||||
if !result.contains(nightly_version) {
|
||||
println!("nightly toolchain not found");
|
||||
install_rust_nightly(nightly_version);
|
||||
} else {
|
||||
println!("nightly toolchain found.");
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error: {}", e);
|
||||
install_rustup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn install_riscv_target(version: &str){
|
||||
|
||||
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);
|
||||
println!("Rust-src for RiscV target installed suscesfully: {}", result);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Rust-src for RiscV target installation failed: {}", 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);
|
||||
println!("RiscV target installed suscesfully: {}", result);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("RiscV target installation failed: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn install_rustup() {
|
||||
#[cfg(windows)]
|
||||
let rustup_init_path =
|
||||
prepare_single_binary("https://win.rustup.rs/x86_64", "rustup-init.exe", "rustup");
|
||||
#[cfg(unix)]
|
||||
let rustup_init_path = prepare_single_binary("https://sh.rustup.rs/", "rustup-init", "rustup");
|
||||
println!("rustup stable");
|
||||
match std::process::Command::new(rustup_init_path)
|
||||
.arg("--default-toolchain")
|
||||
.arg("none")
|
||||
.arg("--profile")
|
||||
.arg("minimal")
|
||||
.arg("-y")
|
||||
.stdout(Stdio::piped())
|
||||
.output()
|
||||
{
|
||||
Ok(child_output) => {
|
||||
let result = String::from_utf8_lossy(&child_output.stdout);
|
||||
println!("{}", result);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn install_rust_nightly(version: &str) {
|
||||
println!("installing nightly toolchain");
|
||||
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);
|
||||
println!("Result: {}", result);
|
||||
}
|
||||
Err(e) => {
|
||||
println!("Error: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn install_gcc_targets(targets: Vec<Chip>) -> Result<Vec<String>, String> {
|
||||
let mut exports: Vec<String> = Vec::new();
|
||||
for target in targets {
|
||||
match target {
|
||||
Chip::Esp32 => {
|
||||
install_gcc("xtensa-esp32-elf");
|
||||
exports.push(format!(
|
||||
"export PATH={}:$PATH",
|
||||
get_tool_path("xtensa-esp32-elf/bin")
|
||||
));
|
||||
}
|
||||
Chip::Esp32s2 => {
|
||||
install_gcc("xtensa-esp32s2-elf");
|
||||
exports.push(format!(
|
||||
"export PATH={}:$PATH",
|
||||
get_tool_path("xtensa-esp32s2-elf/bin")
|
||||
));
|
||||
}
|
||||
Chip::Esp32s3 => {
|
||||
install_gcc("xtensa-esp32s3-elf");
|
||||
exports.push(format!(
|
||||
"export PATH={}:$PATH",
|
||||
get_tool_path("xtensa-esp32s3-elf/bin")
|
||||
));
|
||||
}
|
||||
Chip::Esp32c3 => {
|
||||
install_gcc("riscv32-esp-elf");
|
||||
exports.push(format!(
|
||||
"export PATH={}:$PATH",
|
||||
get_tool_path("riscv32-esp-elf/bin")
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
println!("Unknown target")
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(exports)
|
||||
}
|
||||
|
||||
pub fn install_gcc(gcc_target: &str) {
|
||||
let gcc_path = get_tool_path(gcc_target);
|
||||
println!("gcc path: {}", gcc_path);
|
||||
// if Path::new(&gcc_path).exists() {
|
||||
// println!("Previous installation of GCC for target: {}", gcc_path);
|
||||
// // return Ok(());
|
||||
// } else {
|
||||
// fs::create_dir_all(&gcc_path).unwrap();
|
||||
let gcc_file = format!(
|
||||
"{}-gcc8_4_0-esp-2021r2-patch3-{}.tar.gz",
|
||||
gcc_target,
|
||||
get_gcc_arch(guess_host_triple::guess_host_triple().unwrap())
|
||||
);
|
||||
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(_) => {
|
||||
println!("Package {} ready", gcc_file);
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Unable to prepare {}", gcc_file);
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
pub fn install_espidf(targets: &str, version: String) -> Result<(), String> {
|
||||
let espidf_path = format!("{}/frameworks/esp-idf", get_espressif_base_path());
|
||||
println!("ESP-IDF Path: {}", 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(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
match prepare_package(
|
||||
"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(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
|
||||
#[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();
|
||||
|
||||
// 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();
|
||||
|
||||
let virtual_env_path = get_python_env_path("4.4", "3.8");
|
||||
// TODO: Use any git crate?
|
||||
if !Path::new(&espidf_path).exists() {
|
||||
// let clone_command = format!("git clone --shallow-since=2020-01-01 --jobs 8 --recursive git@github.com:espressif/esp-idf.git ");
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push("clone".to_string());
|
||||
arguments.push("--jobs".to_string());
|
||||
arguments.push("8".to_string());
|
||||
arguments.push("--branch".to_string());
|
||||
arguments.push(version);
|
||||
arguments.push("--depth".to_string());
|
||||
arguments.push("1".to_string());
|
||||
arguments.push("--shallow-submodules".to_string());
|
||||
arguments.push("--recursive".to_string());
|
||||
arguments.push("https://github.com/espressif/esp-idf.git".to_string());
|
||||
// arguments.push("git@github.com:espressif/esp-idf.git".to_string());
|
||||
arguments.push(espidf_path.clone());
|
||||
println!("Cloning: {} {:?}", git_path, arguments);
|
||||
match run_command(git_path, arguments, "".to_string()) {
|
||||
Ok(_) => {
|
||||
println!("Cloned esp-idf suscessfuly");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Cloned esp-idf failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
println!("Installing esp-idf for {} with {}/install.sh", targets, espidf_path);
|
||||
let install_script_path = format!("{}/install.sh", espidf_path);
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
arguments.push(targets.to_string());
|
||||
match run_command(install_script_path, arguments, "".to_string()) {
|
||||
Ok(_) => {
|
||||
println!("ESP-IDF installation succeeded");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("ESP-IDF installation failed");
|
||||
}
|
||||
}
|
||||
// match std::process::Command::new(install_script_path)
|
||||
// .arg("esp32 esp32s2")
|
||||
// .stdout(Stdio::piped())
|
||||
// .output()
|
||||
// {
|
||||
// Ok(child_output) => {
|
||||
// let result = String::from_utf8_lossy(&child_output.stdout);
|
||||
// println!("ESP-IDF installation succeeded: {}", result);
|
||||
// }
|
||||
// Err(e) => {
|
||||
// println!("ESP-IDF installation failed: {}", e);
|
||||
// }
|
||||
// }
|
||||
|
||||
println!("Installing CMake");
|
||||
let mut arguments: Vec<String> = [].to_vec();
|
||||
let mut idf_tools_scritp_path = format!("{}/tools/idf_tools.py", espidf_path);
|
||||
arguments.push(idf_tools_scritp_path);
|
||||
arguments.push("install".to_string());
|
||||
arguments.push("cmake".to_string());
|
||||
match run_command(python_path, arguments, "".to_string()) {
|
||||
Ok(_) => {
|
||||
println!("CMake installation succeeded");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("CMake installation failed");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
296
src/utils.rs
Normal file
296
src/utils.rs
Normal file
@ -0,0 +1,296 @@
|
||||
|
||||
|
||||
use espflash::Chip;
|
||||
use std::path::Path;
|
||||
use dirs::home_dir;
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use tar::Archive;
|
||||
use flate2::bufread::GzDecoder;
|
||||
use xz2::read::XzDecoder;
|
||||
use std::io::BufReader;
|
||||
use std::process::Stdio;
|
||||
use tokio::runtime::Handle;
|
||||
use std::io::Cursor;
|
||||
|
||||
|
||||
// TODO: Create test for this function
|
||||
pub fn parse_targets(build_target: &str) -> Result<Vec<Chip>, String> {
|
||||
println!("Parsing targets: {}", build_target);
|
||||
let mut chips: Vec<Chip> = Vec::new();
|
||||
if build_target.contains("all") {
|
||||
chips.push(Chip::Esp32);
|
||||
chips.push(Chip::Esp32s2);
|
||||
chips.push(Chip::Esp32s3);
|
||||
chips.push(Chip::Esp32c3);
|
||||
return Ok(chips);
|
||||
}
|
||||
let mut targets: Vec<&str>;
|
||||
if build_target.contains(' ') || build_target.contains(',') {
|
||||
targets = build_target.split([',', ' ']).collect();
|
||||
} else {
|
||||
targets = vec![build_target];
|
||||
}
|
||||
for target in targets {
|
||||
match target {
|
||||
"esp32" => chips.push(Chip::Esp32),
|
||||
"esp32s2" => chips.push(Chip::Esp32s2),
|
||||
"esp32s3" => chips.push(Chip::Esp32s3),
|
||||
"esp32c3" => chips.push(Chip::Esp32c3),
|
||||
_ => {
|
||||
return Err(
|
||||
format!("Unknown target: {}", target),
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(chips)
|
||||
}
|
||||
|
||||
pub fn parse_llvm_version(llvm_version: &str) -> Result<String, String> {
|
||||
let parsed_version = match llvm_version {
|
||||
"13" => "esp-13.0.0-20211203",
|
||||
"14" => "esp-14.0.0-20220415",
|
||||
"15" => "", // TODO: Fill when released
|
||||
_ => {
|
||||
return Err(
|
||||
format!("Unknown LLVM Version: {}", llvm_version),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(parsed_version.to_string())
|
||||
}
|
||||
|
||||
|
||||
pub fn get_llvm_version_with_underscores(llvm_version: &str) -> String {
|
||||
let version: Vec<&str> = llvm_version.split("-").collect();
|
||||
let llvm_dot_version = version[1];
|
||||
llvm_dot_version.replace(".", "_")
|
||||
}
|
||||
|
||||
pub fn get_artifact_file_extension(arch: &str) -> &str {
|
||||
match arch {
|
||||
"x86_64-pc-windows-msvc" => "zip",
|
||||
"x86_64-pc-windows-gnu" => "zip",
|
||||
_ => "tar.xz",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_llvm_arch(arch: &str) -> &str {
|
||||
match arch {
|
||||
"aarch64-apple-darwin" => "macos",
|
||||
"x86_64-apple-darwin" => "macos",
|
||||
"x86_64-unknown-linux-gnu" => "linux-amd64",
|
||||
"x86_64-pc-windows-msvc" => "win64",
|
||||
"x86_64-pc-windows-gnu" => "win64",
|
||||
_ => arch,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_gcc_arch(arch: &str) -> &str {
|
||||
match arch {
|
||||
"aarch64-apple-darwin" => "macos",
|
||||
"aarch64-unknown-linux-gnu" => "linux-arm64",
|
||||
"x86_64-apple-darwin" => "macos",
|
||||
"x86_64-unknown-linux-gnu" => "linux-amd64",
|
||||
"x86_64-pc-windows-msvc" => "win64",
|
||||
"x86_64-pc-windows-gnu" => "win64",
|
||||
_ => arch,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_rust_installer(arch: &str) -> &str {
|
||||
match arch {
|
||||
"x86_64-pc-windows-msvc" => "",
|
||||
"x86_64-pc-windows-gnu" => "",
|
||||
_ => "./install.sh",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn get_espressif_base_path() -> String {
|
||||
env::var("IDF_TOOLS_PATH").unwrap_or_else(|_e|
|
||||
home_dir().unwrap().display().to_string() + "/.espressif/"
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_tool_path(tool_name: &str) -> String {
|
||||
format!("{}/tools/{}", get_espressif_base_path(), tool_name)
|
||||
}
|
||||
|
||||
|
||||
pub fn prepare_package_strip_prefix(
|
||||
package_url: &str,
|
||||
output_directory: String,
|
||||
strip_prefix: &str,
|
||||
) -> Result<(), String> {
|
||||
println!("prepare_package_strip_prefix:
|
||||
-pacakge_url: {}
|
||||
-output dir: {}
|
||||
-strip_prefix: {}", &package_url, &output_directory, &strip_prefix);
|
||||
|
||||
if Path::new(&output_directory).exists() {
|
||||
println!("Using cached directory: {}", output_directory);
|
||||
return Ok(());
|
||||
}
|
||||
let tools_path = get_tool_path("");
|
||||
if !Path::new(&tools_path).exists() {
|
||||
println!("Creating tools directory: {}", tools_path);
|
||||
match fs::create_dir_all(&tools_path) {
|
||||
Ok(_) => {
|
||||
println!("tools_path created");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("tools_path creating failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
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);
|
||||
println!("Renaming: {} to {}", &extracted_folder, &output_directory);
|
||||
fs::rename(extracted_folder, output_directory).unwrap();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn run_command(shell: String, arguments: Vec<String>, command: String) -> std::result::Result<(), clap::Error> {
|
||||
// println!("arguments = {:?}", arguments);
|
||||
let mut child_process = std::process::Command::new(shell)
|
||||
.args(arguments)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()?;
|
||||
{
|
||||
let child_stdin = child_process.stdin.as_mut().unwrap();
|
||||
child_stdin.write_all(&*command.into_bytes())?;
|
||||
// Close stdin to finish and avoid indefinite blocking
|
||||
drop(child_stdin);
|
||||
|
||||
}
|
||||
let _output = child_process.wait_with_output()?;
|
||||
|
||||
// println!("output = {:?}", output);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn run_command(shell: String, arguments: Vec<String>, command: String) -> std::result::Result<(), clap::Error> {
|
||||
// Unix - pass command as parameter for initializer
|
||||
let mut arguments = arguments.clone();
|
||||
if !command.is_empty() {
|
||||
arguments.push(command);
|
||||
}
|
||||
|
||||
//println!("arguments = {:?}", arguments);
|
||||
let mut child_process = std::process::Command::new(shell)
|
||||
.args(arguments)
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()?;
|
||||
{
|
||||
|
||||
}
|
||||
let output = child_process.wait_with_output()?;
|
||||
//println!("output = {:?}", output);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn prepare_single_binary(
|
||||
package_url: &str,
|
||||
binary_name: &str,
|
||||
output_directory: &str,
|
||||
) -> String {
|
||||
let tool_path = get_tool_path(output_directory);
|
||||
let binary_path = format!("{}/{}", tool_path, binary_name);
|
||||
|
||||
if Path::new(&binary_path).exists() {
|
||||
println!("Using cached tool: {}", binary_path);
|
||||
return binary_path;
|
||||
}
|
||||
|
||||
if !Path::new(&tool_path).exists() {
|
||||
println!("Creating tool directory: {}", tool_path);
|
||||
match fs::create_dir_all(&tool_path) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match download_package(package_url.to_string(), binary_path.to_string()) {
|
||||
Ok(_) => {
|
||||
println!("Ok");
|
||||
}
|
||||
Err(_e) => {
|
||||
println!("Failed");
|
||||
}
|
||||
}
|
||||
return binary_path;
|
||||
}
|
||||
|
||||
pub fn get_python_env_path(idf_version: &str, python_version: &str) -> String {
|
||||
let tools_path = get_espressif_base_path();
|
||||
format!("{}/python_env/idf{}_py{}_env", tools_path, idf_version, python_version)
|
||||
}
|
||||
|
||||
|
||||
pub fn download_package(package_url: String, package_archive: String) -> Result<(), String> {
|
||||
let handle = Handle::current().clone();
|
||||
let th = std::thread::spawn(move || {
|
||||
handle
|
||||
.block_on(download_file(package_url.to_string(), package_archive.to_string()))
|
||||
.unwrap();
|
||||
});
|
||||
Ok(th.join().unwrap())
|
||||
}
|
||||
|
||||
async fn download_file(url: String, output: String) -> Result<(), String> {
|
||||
if Path::new(&output).exists() {
|
||||
println!("Using cached archive: {}", output);
|
||||
return Ok(());
|
||||
}
|
||||
println!("Downloading {} to {}", url, output);
|
||||
fetch_url(url, output).await
|
||||
}
|
||||
|
||||
async fn fetch_url(url: String, output: String) -> Result<(), String> {
|
||||
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(());
|
||||
}
|
||||
_ => {
|
||||
println!("Download of {} failed", url);
|
||||
// Exit code is 0, there is temporal issue with Windows Installer which does not recover from error exit code
|
||||
#[cfg(windows)]
|
||||
std::process::exit(0);
|
||||
#[cfg(unix)]
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user