Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow aliasing to the system version #556

Merged
merged 6 commits into from
Oct 17, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Allow symlinking to the system version
this PR allows `fnm alias system any_alias` and specifically `fnm default system`, for those who are seeking for it.
it also reveals that we need to do some housekeeping and clean the code. it is very complicated and I believe I can make it nicer. but this is for the future.
  • Loading branch information
Schniz committed Oct 14, 2021
commit 19b403e27a0d748a1cf99e1286a54f6ef0c0c1cb
28 changes: 19 additions & 9 deletions src/alias.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::config::FnmConfig;
use crate::fs::{remove_symlink_dir, symlink_dir};
use crate::fs::{remove_symlink_dir, shallow_read_symlink, symlink_dir};
use crate::system_version;
use crate::version::Version;
use std::convert::TryInto;
use std::path::PathBuf;
Expand Down Expand Up @@ -44,7 +45,12 @@ impl std::convert::TryInto<StoredAlias> for &std::path::Path {
type Error = std::io::Error;

fn try_into(self) -> Result<StoredAlias, Self::Error> {
let destination_path = std::fs::canonicalize(&self)?;
let shallow_self = shallow_read_symlink(self)?;
let destination_path = if shallow_self == system_version::path() {
shallow_self
} else {
std::fs::canonicalize(&shallow_self)?
};
Ok(StoredAlias {
alias_path: PathBuf::from(self),
destination_path,
Expand All @@ -54,13 +60,17 @@ impl std::convert::TryInto<StoredAlias> for &std::path::Path {

impl StoredAlias {
pub fn s_ver(&self) -> &str {
self.destination_path
.parent()
.unwrap()
.file_name()
.expect("must have basename")
.to_str()
.unwrap()
if self.destination_path == system_version::path() {
system_version::display_name()
} else {
self.destination_path
.parent()
.unwrap()
.file_name()
.expect("must have basename")
.to_str()
.unwrap()
}
}

pub fn name(&self) -> &str {
Expand Down
5 changes: 4 additions & 1 deletion src/choose_version_for_user_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ pub fn choose_version_for_user_input<'a>(
installed_versions::list(config.installations_dir()).context(VersionListing)?;

let result = if let UserVersion::Full(Version::Bypassed) = requested_version {
info!("Bypassing fnm: using {} node", "system".cyan());
info!(
"Bypassing fnm: using {} node",
system_version::display_name().cyan()
);
Some(ApplicableVersion {
path: system_version::path(),
version: Version::Bypassed,
Expand Down
1 change: 1 addition & 0 deletions src/commands/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ impl Command for Env {
if self.use_on_cd {
println!("{}", shell.use_on_cd(&config));
}
shell.rehash().map(|v| println!("{}", v));
Ok(())
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/commands/ls_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ impl super::command::Command for LsLocal {
.map(|x| x.name())
.collect::<Vec<_>>()
.join(", ");
format!(" {}", version_string.dimmed())
format!(" {}", version_string)
}
};

let version_str = format!("* {}{}", version, version_aliases);
let version_str = format!("* {}{}", version, version_aliases.white().dimmed());

if curr_version == Some(version) {
println!("{}", version_str.cyan());
Expand Down
10 changes: 8 additions & 2 deletions src/commands/use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,15 @@ impl Command for Use {
.context(CantInferVersion)?;

let version_path = if let UserVersion::Full(Version::Bypassed) = requested_version {
outln!(config#Info, "Bypassing fnm: using {} node", "system".cyan());
outln!(config#Info, "Bypassing fnm: using {} node", system_version::display_name().cyan());
system_version::path()
} else if let Some(alias_name) = requested_version.alias_name() {
let alias_path = config.aliases_dir().join(&alias_name);
if alias_path.exists() {
let shallow_path = fs::shallow_read_symlink(&alias_path).context(SymlinkReadFailed)?;
if shallow_path == system_version::path() {
outln!(config#Info, "Bypassing fnm: using {} node", system_version::display_name().cyan());
shallow_path
} else if alias_path.exists() {
outln!(config#Info, "Using Node for alias {}", alias_name.cyan());
alias_path
} else {
Expand Down Expand Up @@ -166,6 +170,8 @@ fn warn_if_multishell_path_not_in_path_env_var(
pub enum Error {
#[snafu(display("Can't create the symlink: {}", source))]
SymlinkingCreationIssue { source: std::io::Error },
#[snafu(display("Can't read the symlink: {}", source))]
SymlinkReadFailed { source: std::io::Error },
#[snafu(display("{}", source))]
InstallError { source: <Install as Command>::Error },
#[snafu(display("Can't get locally installed versions: {}", source))]
Expand Down
10 changes: 10 additions & 0 deletions src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,13 @@ pub fn remove_symlink_dir<P: AsRef<Path>>(path: P) -> std::io::Result<()> {
std::fs::remove_file(path)?;
Ok(())
}

#[cfg(unix)]
pub fn shallow_read_symlink<P: AsRef<Path>>(path: P) -> std::io::Result<std::path::PathBuf> {
std::fs::read_link(path)
}

#[cfg(windows)]
pub fn shallow_read_symlink<P: AsRef<Path>>(path: P) -> std::io::Result<std::path::PathBuf> {
junction::get_target(path)
}
3 changes: 3 additions & 0 deletions src/shell/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ pub trait Shell: Debug {
fn set_env_var(&self, name: &str, value: &str) -> String;
fn use_on_cd(&self, config: &crate::config::FnmConfig) -> String;
fn into_structopt_shell(&self) -> structopt::clap::Shell;
fn rehash(&self) -> Option<String> {
None
}
}

#[cfg(windows)]
Expand Down
4 changes: 4 additions & 0 deletions src/shell/zsh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ impl Shell for Zsh {
format!("export {}={:?}", name, value)
}

fn rehash(&self) -> Option<String> {
Some("rehash".to_string())
}

fn use_on_cd(&self, _config: &crate::config::FnmConfig) -> String {
indoc!(
r#"
Expand Down
4 changes: 4 additions & 0 deletions src/system_version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ pub fn path() -> PathBuf {

PathBuf::from(path_as_string)
}

pub fn display_name() -> &'static str {
"system"
}
7 changes: 4 additions & 3 deletions src/version.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::alias;
use crate::config;
use crate::lts::LtsType;
use crate::system_version;
use std::str::FromStr;

#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone)]
Expand All @@ -18,7 +19,7 @@ fn first_letter_is_number(s: &str) -> bool {
impl Version {
pub fn parse<S: AsRef<str>>(version_str: S) -> Result<Self, semver::Error> {
let lowercased = version_str.as_ref().to_lowercase();
if lowercased == "system" {
if lowercased == system_version::display_name() {
Ok(Self::Bypassed)
} else if lowercased.starts_with("lts-") || lowercased.starts_with("lts/") {
let lts_type = LtsType::from(&lowercased[4..]);
Expand Down Expand Up @@ -57,7 +58,7 @@ impl Version {

pub fn installation_path(&self, config: &config::FnmConfig) -> Option<std::path::PathBuf> {
match self {
Self::Bypassed => None,
Self::Bypassed => Some(system_version::path()),
v @ Self::Lts(_) | v @ Self::Alias(_) => {
Some(config.aliases_dir().join(v.alias_name().unwrap()))
}
Expand Down Expand Up @@ -95,7 +96,7 @@ impl<'de> serde::Deserialize<'de> for Version {
impl std::fmt::Display for Version {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Bypassed => write!(f, "system"),
Self::Bypassed => write!(f, "{}", system_version::display_name()),
Self::Lts(lts) => write!(f, "lts-{}", lts),
Self::Semver(semver) => write!(f, "v{}", semver),
Self::Alias(alias) => write!(f, "{}", alias),
Expand Down