Fix single binary mapping by manipulating the PATH variable

main
trivernis 1 year ago
parent 91f5570032
commit 6ede8a3df6
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -24,6 +24,7 @@ clap = { version = "4.1.1", features = ["derive"] }
crossterm = "0.25.0"
dialoguer = "0.10.3"
dirs = "4.0.0"
envmnt = "0.10.4"
futures = "0.3.25"
futures-util = "0.3.25"
indicatif = "0.17.3"

@ -2,6 +2,10 @@ use lazy_static::lazy_static;
use std::path::PathBuf;
pub const NODE_DIST_URL: &str = "https://nodejs.org/dist";
#[cfg(not(windows))]
pub const SEARCH_PATH_SEPARATOR: &str = ":";
#[cfg(windows)]
pub const SEARCH_PATH_SEPARATOR: &str = ";";
lazy_static! {
pub static ref CFG_DIR: PathBuf = dirs::config_dir()

@ -1,4 +1,4 @@
use std::process;
use std::{env, process};
use args::Args;
use clap::Parser;
@ -36,7 +36,7 @@ async fn main() -> Result<()> {
return Ok(());
}
let mut nenv = get_nenv(args.use_version.as_ref()).await?;
let mut nenv = get_nenv(args.use_version.clone()).await?;
match args.command {
args::Command::Install(v) => nenv.install(v.version).await,
@ -63,7 +63,7 @@ fn print_version() {
println!("{} v{}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
}
async fn get_nenv(version_override: Option<&NodeVersion>) -> Result<Nenv> {
async fn get_nenv(version_override: Option<NodeVersion>) -> Result<Nenv> {
Nenv::init(version_override).await
}

@ -1,4 +1,5 @@
use std::{
env,
ffi::OsString,
path::PathBuf,
process::{ExitStatus, Stdio},
@ -8,6 +9,7 @@ use crate::error::CommandNotFoundError;
use miette::{Context, IntoDiagnostic, Result};
use tokio::process::Command;
#[derive(Debug)]
pub struct MappedCommand {
name: String,
path: PathBuf,
@ -19,10 +21,11 @@ impl MappedCommand {
Self { name, path, args }
}
#[tracing::instrument(skip_all, level = "debug")]
#[tracing::instrument(level = "debug")]
pub async fn run(mut self) -> Result<ExitStatus> {
self.adjust_path()?;
let exit_status = Command::new(self.path)
.envs(env::vars_os())
.args(self.args)
.stdin(Stdio::inherit())
.stdout(Stdio::inherit())

@ -40,7 +40,7 @@ impl NodeApp {
.context("Creating executable wrapper script")
}
#[cfg(not(target_os = "windows"))]
#[cfg(not(windows))]
async fn write_wrapper_script(&self, path: &Path) -> Result<(), io::Error> {
fs::write(path, format!("#!/bin/sh\nnenv exec {} \"$@\"", self.name)).await?;
let src_metadata = self.path.metadata()?;
@ -49,7 +49,7 @@ impl NodeApp {
Ok(())
}
#[cfg(target_os = "windows")]
#[cfg(windows)]
async fn write_wrapper_script(&self, path: &Path) -> Result<(), io::Error> {
fs::write(
path.with_extension("bat"),
@ -117,12 +117,12 @@ async fn get_applications(path: &Path) -> Result<Vec<NodeApp>> {
Ok(files)
}
#[cfg(not(target_os = "windows"))]
#[cfg(not(windows))]
fn exclude_path(_path: &Path) -> bool {
false
}
#[cfg(target_os = "windows")]
#[cfg(windows)]
fn exclude_path(path: &Path) -> bool {
let Some(extension) = path.extension() else {
return true;

@ -1,8 +1,12 @@
use std::{ffi::OsString, process::ExitStatus};
use std::{env, ffi::OsString, process::ExitStatus};
use envmnt::ListOptions;
use tokio::fs;
use crate::{consts::BIN_DIR, repository::node_path::NodePath};
use crate::{
consts::{BIN_DIR, SEARCH_PATH_SEPARATOR},
repository::node_path::NodePath,
};
use self::{
mapped_command::MappedCommand,
@ -26,6 +30,7 @@ impl Mapper {
/// Executes a mapped command with the given node environment
#[tracing::instrument(level = "debug", skip(self))]
pub async fn exec(&self, command: String, args: Vec<OsString>) -> Result<ExitStatus> {
self.set_env();
let executable = self.node_path.bin().join(&command);
let exit_status = MappedCommand::new(command, executable, args).run().await?;
self.remap_additive().await?;
@ -60,4 +65,18 @@ impl Mapper {
)
.await
}
fn set_env(&self) {
env::set_var(
"NODE_PATH",
self.node_path.node_modules().to_string_lossy().to_string(),
);
let list_options = ListOptions {
separator: Some(SEARCH_PATH_SEPARATOR.to_string()),
ignore_empty: true,
};
let mut path_env = envmnt::get_list_with_options("PATH", &list_options).unwrap_or_default();
path_env.insert(0, self.node_path.bin().to_string_lossy().to_string());
envmnt::set_list_with_options("PATH", &path_env, &list_options);
}
}

@ -22,13 +22,13 @@ pub struct Nenv {
impl Nenv {
#[tracing::instrument(level = "debug")]
pub async fn init(version_override: Option<&NodeVersion>) -> Result<Self> {
pub async fn init(version_override: Option<NodeVersion>) -> Result<Self> {
let config = ConfigAccess::load().await?;
let repo = Repository::init(config.clone()).await?;
let default_version = { config.get().await.node.default_version.to_owned() };
let active_version = if let Some(version) = version_override {
version.to_owned()
version
} else {
Self::get_active_version().await.unwrap_or(default_version)
};
@ -265,7 +265,8 @@ impl Nenv {
for (bin, cfg) in &self.config.get().await.bins {
let path = self
.repo
.get_version_path(&cfg.node_version)?
.get_version_path(&cfg.node_version)
.await?
.ok_or_else(|| VersionError::not_installed(&cfg.node_version))?;
binaries_with_path.push((bin.to_owned(), path));
}

@ -12,7 +12,15 @@ impl NodePath {
#[cfg(not(target_os = "windows"))]
pub fn bin(&self) -> PathBuf {
self.base.join("bin")
self.base.join("bin").canonicalize().unwrap()
}
pub fn lib(&self) -> PathBuf {
self.base.join("lib").canonicalize().unwrap()
}
pub fn node_modules(&self) -> PathBuf {
self.lib().join("node_modules")
}
#[cfg(target_os = "windows")]

Loading…
Cancel
Save