Skip to content

Commit

Permalink
Update Windows env (#389)
Browse files Browse the repository at this point in the history
* feat: Update Windows env

* feat: Remove unused import in env.rs

* feat: Add version file for GCC and LLVM

* feat: Improve get methods

* fix: Fix includes
  • Loading branch information
SergioGasquez authored Nov 7, 2023
1 parent 819b3b4 commit 119ec3a
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 58 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ openssl = { version = "0.10.57", features = ["vendored"] }

[target.'cfg(windows)'.dependencies]
winreg = "0.51.0"
winapi = { version = "0.3.9", features = ["winuser"] }

[dev-dependencies]
assert_cmd = "2.0.12"
Expand Down
101 changes: 88 additions & 13 deletions src/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

use crate::error::Error;
use directories::BaseDirs;
use log::info;
#[cfg(windows)]
use log::warn;
use log::debug;
use std::{
env,
fs::File,
Expand All @@ -24,19 +22,44 @@ const DEFAULT_EXPORT_FILE: &str = "export-esp.sh";

#[cfg(windows)]
/// Sets an environment variable for the current user.
pub fn set_environment_variable(key: &str, value: &str) -> Result<(), Error> {
pub fn set_env_variable(key: &str, value: &str) -> Result<(), Error> {
use std::ptr;
use winapi::shared::minwindef::*;
use winapi::um::winuser::{
SendMessageTimeoutA, HWND_BROADCAST, SMTO_ABORTIFHUNG, WM_SETTINGCHANGE,
};

env::set_var(key, value);

let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let environment_key = hkcu.open_subkey_with_flags("Environment", KEY_WRITE)?;
environment_key.set_value(key, &value)?;

// Tell other processes to update their environment
#[allow(clippy::unnecessary_cast)]
unsafe {
SendMessageTimeoutA(
HWND_BROADCAST,
WM_SETTINGCHANGE,
0 as WPARAM,
"Environment\0".as_ptr() as LPARAM,
SMTO_ABORTIFHUNG,
5000,
ptr::null_mut(),
);
}

Ok(())
}

#[cfg(windows)]
/// Deletes an environment variable for the current user.
pub fn delete_environment_variable(key: &str) -> Result<(), Error> {
if env::var_os(key).is_none() {
pub fn delete_env_variable(key: &str) -> Result<(), Error> {
let root = RegKey::predef(HKEY_CURRENT_USER);
let environment = root.open_subkey_with_flags("Environment", KEY_READ | KEY_WRITE)?;

let reg_value = environment.get_raw_value(key);
if reg_value.is_err() {
return Ok(());
}

Expand Down Expand Up @@ -70,7 +93,7 @@ pub fn get_export_file(export_file: Option<PathBuf>) -> Result<PathBuf, Error> {

/// Creates the export file with the necessary environment variables.
pub fn create_export_file(export_file: &PathBuf, exports: &[String]) -> Result<(), Error> {
info!("Creating export file");
debug!("Creating export file");
let mut file = File::create(export_file)?;
for e in exports.iter() {
#[cfg(windows)]
Expand All @@ -82,16 +105,68 @@ pub fn create_export_file(export_file: &PathBuf, exports: &[String]) -> Result<(
Ok(())
}

#[cfg(windows)]
/// Instructions to export the environment variables.
pub fn set_env() -> Result<(), Error> {
let mut path = env::var("PATH").unwrap_or_default();

if let Ok(xtensa_gcc) = env::var("XTENSA_GCC") {
let xtensa_gcc: &str = &xtensa_gcc;
if !path.contains(xtensa_gcc) {
path = format!("{};{}", xtensa_gcc, path);
}
}

if let Ok(riscv_gcc) = env::var("RISCV_GCC") {
let riscv_gcc: &str = &riscv_gcc;
if !path.contains(riscv_gcc) {
path = format!("{};{}", riscv_gcc, path);
}
}

if let Ok(libclang_path) = env::var("LIBCLANG_PATH") {
set_env_variable("LIBCLANG_PATH", &libclang_path)?;
}

if let Ok(libclang_bin_path) = env::var("LIBCLANG_BIN_PATH") {
let libclang_bin_path: &str = &libclang_bin_path;
if !path.contains(libclang_bin_path) {
path = format!("{};{}", libclang_bin_path, path);
}
}

if let Ok(clang_path) = env::var("CLANG_PATH") {
let clang_path: &str = &clang_path;
if !path.contains(clang_path) {
path = format!("{};{}", clang_path, path);
}
}

set_env_variable("PATH", &path)?;
Ok(())
}

#[cfg(windows)]
/// Clean the environment for Windows.
pub fn clean_env() -> Result<(), Error> {
delete_env_variable("LIBCLANG_PATH")?;
delete_env_variable("CLANG_PATH")?;
if let Some(path) = env::var_os("PATH") {
set_env_variable("PATH", &path.to_string_lossy())?;
};

Ok(())
}

/// Instructions to export the environment variables.
pub fn export_environment(export_file: &Path) -> Result<(), Error> {
pub fn print_post_install_msg(export_file: &Path) -> Result<(), Error> {
#[cfg(windows)]
if cfg!(windows) {
set_environment_variable("PATH", &env::var("PATH").unwrap())?;
warn!(
"Your environments variables have been updated! Shell may need to be restarted for changes to be effective"
println!(
"\n\tYour environments variables have been updated! Shell may need to be restarted for changes to be effective"
);
warn!(
"A file was created at '{}' showing the injected environment variables",
println!(
"\tA file was created at '{}' showing the injected environment variables",
export_file.display()
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::{CommandFactory, Parser};
#[cfg(windows)]
use espup::env::set_environment_variable;
use espup::env::clean_env;
use espup::{
cli::{CompletionsOpts, InstallOpts, UninstallOpts},
logging::initialize_logger,
Expand Down Expand Up @@ -79,7 +79,7 @@ async fn uninstall(args: UninstallOpts) -> Result<()> {
remove_dir(&toolchain_dir).await?;

#[cfg(windows)]
set_environment_variable("PATH", &env::var("PATH").unwrap())?;
clean_env()?;
}

info!("Uninstallation successfully completed!");
Expand Down
37 changes: 29 additions & 8 deletions src/toolchain/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use crate::{
use async_trait::async_trait;
use log::{debug, info, warn};
use miette::Result;
#[cfg(windows)]
use std::env;
use std::path::{Path, PathBuf};
#[cfg(windows)]
use std::{env, fs::File};
use tokio::fs::remove_dir_all;

const DEFAULT_GCC_REPOSITORY: &str = "https://github.com/espressif/crosstool-NG/releases/download";
Expand All @@ -31,14 +31,21 @@ pub struct Gcc {
impl Gcc {
/// Gets the binary path.
pub fn get_bin_path(&self) -> String {
format!("{}/{}/bin", &self.path.to_str().unwrap(), &self.arch)
let bin_path = format!("{}/{}/bin", &self.path.to_str().unwrap(), &self.arch);
match std::cfg!(windows) {
true => bin_path.replace('/', "\\"),
false => bin_path,
}
}

/// Create a new instance with default values and proper toolchain name.
pub fn new(arch: &str, host_triple: &HostTriple, toolchain_path: &Path) -> Self {
#[cfg(unix)]
let path = toolchain_path
.join(arch)
.join(format!("esp-{DEFAULT_GCC_RELEASE}"));
#[cfg(windows)]
let path: PathBuf = toolchain_path.into();

Self {
host_triple: host_triple.clone(),
Expand All @@ -52,8 +59,19 @@ impl Gcc {
impl Installable for Gcc {
async fn install(&self) -> Result<Vec<String>, Error> {
let extension = get_artifact_extension(&self.host_triple);
info!("Installing GCC ({})", self.arch);
debug!("GCC path: {}", self.path.display());
if self.path.exists() {

#[cfg(unix)]
let is_installed = self.path.exists();
#[cfg(windows)]
let is_installed = self
.path
.join(&self.arch)
.join(DEFAULT_GCC_RELEASE)
.exists();

if is_installed {
warn!(
"Previous installation of GCC exists in: '{}'. Reusing this installation",
&self.path.display()
Expand Down Expand Up @@ -83,14 +101,17 @@ impl Installable for Gcc {

#[cfg(windows)]
if cfg!(windows) {
File::create(self.path.join(&self.arch).join(DEFAULT_GCC_RELEASE))?;

exports.push(format!(
"$Env:PATH = \"{};\" + $Env:PATH",
&self.get_bin_path()
));
env::set_var(
"PATH",
self.get_bin_path().replace('/', "\\") + ";" + &env::var("PATH").unwrap(),
);
if self.arch == RISCV_GCC {
env::set_var("RISCV_GCC", self.get_bin_path());
} else {
env::set_var("XTENSA_GCC", self.get_bin_path());
}
}
#[cfg(unix)]
exports.push(format!("export PATH=\"{}:$PATH\"", &self.get_bin_path()));
Expand Down
69 changes: 36 additions & 33 deletions src/toolchain/llvm.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! LLVM Toolchain source and installation tools.

#[cfg(windows)]
use crate::env::{delete_environment_variable, set_environment_variable};
use crate::{
error::Error,
host_triple::HostTriple,
Expand All @@ -13,9 +11,9 @@ use directories::BaseDirs;
use log::{info, warn};
use miette::Result;
use regex::Regex;
#[cfg(windows)]
use std::env;
use std::path::{Path, PathBuf};
#[cfg(windows)]
use std::{env, fs::File};
#[cfg(unix)]
use std::{fs::create_dir_all, os::unix::fs::symlink};
use tokio::fs::remove_dir_all;
Expand Down Expand Up @@ -55,21 +53,19 @@ impl Llvm {

/// Gets the binary path.
fn get_lib_path(&self) -> String {
#[cfg(windows)]
let llvm_path = format!("{}/esp-clang/bin", self.path.to_str().unwrap()).replace('/', "\\");
#[cfg(unix)]
let llvm_path = format!("{}/esp-clang/lib", self.path.to_str().unwrap());
llvm_path
match std::cfg!(windows) {
true => format!("{}/esp-clang/bin", self.path.to_str().unwrap()).replace('/', "\\"),
false => format!("{}/esp-clang/lib", self.path.to_str().unwrap()),
}
}

/// Gets the binary path of clang
fn get_bin_path(&self) -> String {
#[cfg(windows)]
let llvm_path =
format!("{}/esp-clang/bin/clang.exe", self.path.to_str().unwrap()).replace('/', "\\");
#[cfg(unix)]
let llvm_path = format!("{}/esp-clang/bin/clang", self.path.to_str().unwrap());
llvm_path
match std::cfg!(windows) {
true => format!("{}/esp-clang/bin/clang.exe", self.path.to_str().unwrap())
.replace('/', "\\"),
false => format!("{}/esp-clang/bin/clang", self.path.to_str().unwrap()),
}
}

/// Create a new instance with default values and proper toolchain version.
Expand Down Expand Up @@ -108,7 +104,10 @@ impl Llvm {
file_name = format!("libs_{file_name}");
}
let repository_url = format!("{DEFAULT_LLVM_REPOSITORY}/{version}/{file_name}");
#[cfg(unix)]
let path = toolchain_path.join(CLANG_NAME).join(&version);
#[cfg(windows)]
let path = toolchain_path.join(CLANG_NAME);

Ok(Self {
extended,
Expand All @@ -127,8 +126,8 @@ impl Llvm {
if llvm_path.exists() {
#[cfg(windows)]
if cfg!(windows) {
delete_environment_variable("LIBCLANG_PATH")?;
delete_environment_variable("CLANG_PATH")?;
env::remove_var("LIBCLANG_PATH");
env::remove_var("CLANG_PATH");
let mut updated_path = env::var("PATH").unwrap().replace(
&format!(
"{}\\{}\\esp-clang\\bin;",
Expand All @@ -145,7 +144,14 @@ impl Llvm {
),
"",
);
set_environment_variable("PATH", &updated_path)?;
updated_path = updated_path.replace(
&format!(
"{}\\esp-clang\\bin;",
llvm_path.display().to_string().replace('/', "\\"),
),
"",
);
env::set_var("PATH", updated_path);
}
remove_dir_all(&llvm_path)
.await
Expand All @@ -169,8 +175,13 @@ impl Llvm {
impl Installable for Llvm {
async fn install(&self) -> Result<Vec<String>, Error> {
let mut exports: Vec<String> = Vec::new();
println!("LLVM Path: {}", self.path.to_str().unwrap());

if Path::new(&self.path).exists() {
#[cfg(unix)]
let is_installed = Path::new(&self.path).exists();
#[cfg(windows)]
let is_installed = self.path.join(&self.version).exists();
if is_installed {
warn!(
"Previous installation of LLVM exists in: '{}'. Reusing this installation",
self.path.to_str().unwrap()
Expand All @@ -189,23 +200,15 @@ impl Installable for Llvm {
// Set environment variables.
#[cfg(windows)]
if cfg!(windows) {
exports.push(format!(
"$Env:LIBCLANG_PATH = \"{}/libclang.dll\"",
self.get_lib_path()
));
File::create(self.path.join(&self.version))?;
let libclang_dll = format!("{}\\libclang.dll", self.get_lib_path());
exports.push(format!("$Env:LIBCLANG_PATH = \"{}\"", libclang_dll));
exports.push(format!(
"$Env:PATH = \"{};\" + $Env:PATH",
self.get_lib_path()
));
set_environment_variable(
"LIBCLANG_PATH",
&format!("{}\\libclang.dll", self.get_lib_path().replace('/', "\\")),
)?;

env::set_var(
"PATH",
self.get_lib_path().replace('/', "\\") + ";" + &env::var("PATH").unwrap(),
);
env::set_var("LIBCLANG_BIN_PATH", self.get_lib_path());
env::set_var("LIBCLANG_PATH", libclang_dll);
}
#[cfg(unix)]
if cfg!(unix) {
Expand Down Expand Up @@ -234,7 +237,7 @@ impl Installable for Llvm {
#[cfg(windows)]
if cfg!(windows) {
exports.push(format!("$Env:CLANG_PATH = \"{}\"", self.get_bin_path()));
set_environment_variable("CLANG_PATH", &self.get_bin_path().replace('/', "\\"))?;
env::set_var("CLANG_PATH", self.get_bin_path());
}
#[cfg(unix)]
exports.push(format!("export CLANG_PATH=\"{}\"", self.get_bin_path()));
Expand Down
Loading

0 comments on commit 119ec3a

Please sign in to comment.