Browse Source

Try to allow using shims

I am still not sure this will fix the graphic IDE issue,
but it will most certainly fix the rehashing issues.

Still need to consider how to tackle the IDE issue.
Hmm.
Maybe I have the strangest idea.
I will try.
remotes/origin/add-with-shims
Gal Schlezinger 3 years ago
parent
commit
6700c32910
No known key found for this signature in database
GPG Key ID: 68CF3D15D272E5E1
  1. 16
      src/commands/env.rs
  2. 25
      src/commands/exec.rs
  3. 1
      src/main.rs
  4. 62
      src/shims/mod.rs
  5. 3
      src/shims/unix.sh
  6. 5
      src/shims/windows.cmd
  7. 10
      tests/feature_tests/mod.rs
  8. 15
      tests/feature_tests/snapshots/e2e__feature_tests__basic_with_shims__Bash.snap
  9. 12
      tests/feature_tests/snapshots/e2e__feature_tests__basic_with_shims__Fish.snap
  10. 13
      tests/feature_tests/snapshots/e2e__feature_tests__basic_with_shims__PowerShell.snap
  11. 13
      tests/feature_tests/snapshots/e2e__feature_tests__basic_with_shims__WinCmd.snap
  12. 13
      tests/feature_tests/snapshots/e2e__feature_tests__basic_with_shims__Zsh.snap
  13. 8
      tests/shellcode/eval_fnm_env.rs

16
src/commands/env.rs

@ -1,11 +1,11 @@ @@ -1,11 +1,11 @@
use super::command::Command;
use crate::config::FnmConfig;
use crate::fs::symlink_dir;
use crate::outln;
use crate::path_ext::PathExt;
use crate::shell::{infer_shell, Shell, AVAILABLE_SHELLS};
use crate::{outln, shims};
use colored::Colorize;
use snafu::{OptionExt, Snafu};
use snafu::{OptionExt, ResultExt, Snafu};
use std::fmt::Debug;
use structopt::StructOpt;
@ -21,6 +21,12 @@ pub struct Env { @@ -21,6 +21,12 @@ pub struct Env {
/// Print the script to change Node versions every directory change
#[structopt(long)]
use_on_cd: bool,
/// Adds `node` shims to your PATH environment variable
/// to allow you to use `node` commands in your shell
/// without rehashing.
#[structopt(long)]
with_shims: bool,
}
fn generate_symlink_path() -> String {
@ -61,7 +67,9 @@ impl Command for Env { @@ -61,7 +67,9 @@ impl Command for Env {
let shell: Box<dyn Shell> = self.shell.or_else(&infer_shell).context(CantInferShell)?;
let multishell_path = make_symlink(config);
let binary_path = if cfg!(windows) {
let binary_path = if self.with_shims {
shims::store_shim(config).context(CantCreateShims)?
} else if cfg!(windows) {
multishell_path.clone()
} else {
multishell_path.join("bin")
@ -107,6 +115,8 @@ pub enum Error { @@ -107,6 +115,8 @@ pub enum Error {
shells_as_string()
))]
CantInferShell,
#[snafu(display("Can't create Node.js shims: {}", source))]
CantCreateShims { source: std::io::Error },
}
fn shells_as_string() -> String {

25
src/commands/exec.rs

@ -3,10 +3,12 @@ use crate::choose_version_for_user_input::{ @@ -3,10 +3,12 @@ use crate::choose_version_for_user_input::{
choose_version_for_user_input, Error as UserInputError,
};
use crate::config::FnmConfig;
use crate::current_version::{self, current_version};
use crate::outln;
use crate::user_version::UserVersion;
use crate::user_version_reader::UserVersionReader;
use colored::Colorize;
use log::debug;
use snafu::{OptionExt, ResultExt, Snafu};
use std::process::{Command, Stdio};
use structopt::StructOpt;
@ -20,6 +22,8 @@ pub struct Exec { @@ -20,6 +22,8 @@ pub struct Exec {
/// Deprecated. This is the default now.
#[structopt(long = "using-file", hidden = true)]
using_file: bool,
#[structopt(long = "using-current", hidden = true, conflicts_with = "using")]
using_current: bool,
/// The command to run
arguments: Vec<String>,
}
@ -40,14 +44,21 @@ impl Cmd for Exec { @@ -40,14 +44,21 @@ impl Cmd for Exec {
let (binary, arguments) = self.arguments.split_first().context(NoBinaryProvided)?;
let version = self
.version
let version = if self.using_current {
let version = current_version(config)
.context(CantGetCurrentVersion)?
.context(NoCurrentVersion)?;
UserVersion::Full(version)
} else {
self.version
.unwrap_or_else(|| {
debug!("no version provided, falling back to current directory");
let current_dir = std::env::current_dir().unwrap();
UserVersionReader::Path(current_dir)
})
.into_user_version()
.context(CantInferVersion)?;
.context(CantInferVersion)?
};
let applicable_version = choose_version_for_user_input(&version, config)
.context(ApplicableVersionError)?
@ -59,6 +70,8 @@ impl Cmd for Exec { @@ -59,6 +70,8 @@ impl Cmd for Exec {
#[cfg(unix)]
let bin_path = applicable_version.path().join("bin");
debug!("Using Node.js from {}", bin_path.display());
let path_env = {
let paths_env = std::env::var_os("PATH").context(CantReadPathVariable)?;
let mut paths: Vec<_> = std::env::split_paths(&paths_env).collect();
@ -105,6 +118,12 @@ pub enum Error { @@ -105,6 +118,12 @@ pub enum Error {
"Can't read exit code from process.\nMaybe the process was killed using a signal?"
))]
CantReadProcessExitCode,
#[snafu(display("{}", source))]
CantGetCurrentVersion {
source: current_version::Error,
},
#[snafu(display("No current version. Please run `fnm use <version>` and retry."))]
NoCurrentVersion,
#[snafu(display("command not provided. Please provide a command to run as an argument, like {} or {}.\n{} {}", "node".italic(), "bash".italic(), "example:".yellow().bold(), "fnm exec --using=12 node --version".italic().yellow()))]
NoBinaryProvided,
}

1
src/main.rs

@ -23,6 +23,7 @@ mod lts; @@ -23,6 +23,7 @@ mod lts;
mod path_ext;
mod remote_node_index;
mod shell;
mod shims;
mod system_info;
mod system_version;
mod user_version;

62
src/shims/mod.rs

@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
use crate::config::FnmConfig;
use log::info;
use std::io::Write;
use std::path::PathBuf;
#[cfg(not(windows))]
const SHIM_CONTENT: &[u8] = include_bytes!("./unix.sh");
#[cfg(windows)]
const SHIM_CONTENT: &[u8] = include_bytes!("./windows.cmd");
pub type Error = std::io::Error;
/// Creates shims for a path and returns the shim directory
pub fn store_shim(config: &FnmConfig) -> Result<PathBuf, Error> {
let dir = shims_dir(config)?;
let executable_path = dir.join(if cfg!(not(windows)) {
"node"
} else {
"node.cmd"
});
if executable_path.exists() {
return Ok(dir);
}
info!("Creating a shim at {}", executable_path.display());
let mut file = std::fs::File::create(&executable_path)?;
#[cfg(not(windows))]
{
use std::os::unix::prelude::PermissionsExt;
info!("Setting file permissions to 777");
let mut perm = file.metadata()?.permissions();
perm.set_mode(0o777);
file.set_permissions(perm)?;
};
file.write_all(SHIM_CONTENT)?;
Ok(dir)
}
fn shims_dir(config: &FnmConfig) -> Result<PathBuf, std::io::Error> {
let path = config.base_dir_with_default().join("shims");
std::fs::create_dir_all(&path)?;
Ok(path)
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
#[test]
fn test_shim() {
let base_dir = tempdir().unwrap();
let config = FnmConfig::default().with_base_dir(Some(base_dir.into_path()));
let dir = shims_dir(&config).unwrap();
assert!(dir.exists());
}
}

3
src/shims/unix.sh

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
#!/usr/bin/env sh
fnm exec --using-current -- node "$@"

5
src/shims/windows.cmd

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
@echo off
fnm exec --using-current -- node %*
@echo on

10
tests/feature_tests/mod.rs

@ -13,6 +13,16 @@ mod basic { @@ -13,6 +13,16 @@ mod basic {
});
}
mod basic_with_shims {
test_shell!(Zsh, Bash, Fish, PowerShell, WinCmd; {
EvalFnmEnv::default()
.with_shims(true)
.then(Call::new("fnm", vec!["install", "v8.11.3"]))
.then(Call::new("fnm", vec!["use", "v8.11.3"]))
.then(test_node_version("v8.11.3"))
});
}
mod nvmrc {
test_shell!(Zsh, Bash, Fish, PowerShell, WinCmd; {
EvalFnmEnv::default()

15
tests/feature_tests/snapshots/e2e__feature_tests__basic_with_shims__Bash.snap

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
---
source: tests/feature_tests/mod.rs
expression: "&source.trim()"
---
set -e
shopt -s expand_aliases
eval "$(fnm env --with-shims)"
fnm install v8.11.3
fnm use v8.11.3
if [ "$(node -v)" != "v8.11.3" ]; then
echo 'Expected Node version to be "v8.11.3", Got: '"$(node -v)"
exit 1
fi

12
tests/feature_tests/snapshots/e2e__feature_tests__basic_with_shims__Fish.snap

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
---
source: tests/feature_tests/mod.rs
expression: "&source.trim()"
---
fnm env --with-shims | source
fnm install v8.11.3
fnm use v8.11.3
if test (node -v) != "v8.11.3"
echo 'Expected Node version to be "v8.11.3", Got: '(node -v)
exit 1
end

13
tests/feature_tests/snapshots/e2e__feature_tests__basic_with_shims__PowerShell.snap

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
---
source: tests/feature_tests/mod.rs
expression: "&source.trim()"
---
$ErrorActionPreference = "Stop"
fnm env --with-shims | Out-String | Invoke-Expression
fnm install v8.11.3
fnm use v8.11.3
If ("$(node -v)" -ne "v8.11.3") {
Write-Output ('Expected Node version to be "v8.11.3", Got: ' + $(node -v))
exit 1
}

13
tests/feature_tests/snapshots/e2e__feature_tests__basic_with_shims__WinCmd.snap

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
---
source: tests/feature_tests/mod.rs
expression: "&source.trim()"
---
FOR /f "tokens=*" %i IN ('fnm env --with-shims') DO CALL %i
fnm install v8.11.3
fnm use v8.11.3
node -v | findstr v8.11.3
if %errorlevel% neq 0 (
echo Node version does not match "v8.11.3"
exit 1
)

13
tests/feature_tests/snapshots/e2e__feature_tests__basic_with_shims__Zsh.snap

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
---
source: tests/feature_tests/mod.rs
expression: "&source.trim()"
---
set -e
eval "$(fnm env --with-shims)"
fnm install v8.11.3
fnm use v8.11.3
if [ "$(node -v)" != "v8.11.3" ]; then
echo 'Expected Node version to be "v8.11.3", Got: '"$(node -v)"
exit 1
fi

8
tests/shellcode/eval_fnm_env.rs

@ -6,6 +6,7 @@ use std::fmt::Write; @@ -6,6 +6,7 @@ use std::fmt::Write;
pub(crate) struct EvalFnmEnv {
use_on_cd: bool,
log_level: Option<&'static str>,
with_shims: bool,
}
impl EvalFnmEnv {
@ -16,6 +17,10 @@ impl EvalFnmEnv { @@ -16,6 +17,10 @@ impl EvalFnmEnv {
pub(crate) fn log_level(self, log_level: Option<&'static str>) -> Self {
Self { log_level, ..self }
}
pub(crate) fn with_shims(self, with_shims: bool) -> Self {
Self { with_shims, ..self }
}
}
impl std::fmt::Display for EvalFnmEnv {
@ -28,6 +33,9 @@ impl std::fmt::Display for EvalFnmEnv { @@ -28,6 +33,9 @@ impl std::fmt::Display for EvalFnmEnv {
if self.use_on_cd {
write!(f, " --use-on-cd")?;
}
if self.with_shims {
write!(f, " --with-shims")?;
}
Ok(())
}
}

Loading…
Cancel
Save