Skip to content

Commit

Permalink
Support adding to PATH on Unix systems (posix, bash, and zsh) (#16)
Browse files Browse the repository at this point in the history
* Support adding to PATH on Unix systems (posix, bash, and zsh)

* UI tests, plus preserve HOME variable on unix

* Clean up fallback code

* Remove test breakpoint (oops)
  • Loading branch information
LPGhatguy committed Jul 2, 2022
1 parent 6d6e321 commit f97a675
Show file tree
Hide file tree
Showing 19 changed files with 406 additions and 14 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/target
*.snap.new
58 changes: 58 additions & 0 deletions Cargo.lock

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

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ edition = "2021"
repository = "https://github.com/LPGhatguy/aftman"
readme = "README.md"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[workspace]
members = ["test-util"]

[dependencies]
anyhow = "1.0.43"
Expand Down Expand Up @@ -36,5 +37,7 @@ tokio = { version = "1.18.2", features = ["macros", "sync", "process"] }
signal-hook = "0.3.14"

[dev-dependencies]
test-util = { path = "test-util" }
tempfile = "3.3.0"
serde_json = "1.0.66"
insta = "1.15.0"
6 changes: 3 additions & 3 deletions src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl Args {
Subcommand::Add(sub) => sub.run(tools),
Subcommand::Install(sub) => sub.run(tools),
Subcommand::Trust(sub) => sub.run(home),
Subcommand::SelfInstall(sub) => sub.run(tools),
Subcommand::SelfInstall(sub) => sub.run(home, tools),

Subcommand::List(_) => bail!("This command is not yet implemented."),
Subcommand::Update(_) => bail!("This command is not yet implemented."),
Expand Down Expand Up @@ -163,10 +163,10 @@ pub struct SelfUpdateSubcommand {}
pub struct SelfInstallSubcommand {}

impl SelfInstallSubcommand {
pub fn run(self, tools: ToolStorage) -> anyhow::Result<()> {
pub fn run(self, home: &Home, tools: ToolStorage) -> anyhow::Result<()> {
tools.update_links()?;

if crate::system_path::add(&tools.bin_dir)? {
if crate::system_path::add(&home)? {
log::info!(
"Added ~/.aftman/bin to your PATH. Restart your terminal for this to take effect."
);
Expand Down
4 changes: 4 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(unused)]

use std::io::{self, BufWriter, Write};
use std::path::Path;

Expand All @@ -17,6 +19,7 @@ pub fn write_only_new(path: &Path, contents: &str) -> anyhow::Result<()> {
};

file.write_all(contents.as_bytes())?;
file.into_inner()?;

Ok(())
}
Expand All @@ -34,6 +37,7 @@ pub fn write_if_not_exists(path: &Path, contents: &str) -> anyhow::Result<()> {
};

file.write_all(contents.as_bytes())?;
file.into_inner()?;

Ok(())
}
10 changes: 10 additions & 0 deletions src/dirs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use std::env;
use std::path::PathBuf;

pub fn home_dir() -> Option<PathBuf> {
if let Ok(home) = env::var("AFTMAN_HOME") {
return Some(PathBuf::from(home));
}

dirs::home_dir()
}
37 changes: 33 additions & 4 deletions src/home.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::env;
use std::path::{Path, PathBuf};
use std::path::{Path, PathBuf, MAIN_SEPARATOR};
use std::sync::Arc;

use anyhow::format_err;

use crate::dirs::home_dir;

/// Defines the root that everything else in Aftman is stored relative to.
///
/// This type encourages good organization, helps us behave predictably, and
Expand All @@ -19,14 +21,14 @@ pub struct Home {

impl Home {
pub fn from_env() -> anyhow::Result<Self> {
// Users can override the Aftman home directory via the AFTMAN_HOME
// Users can override the Aftman home directory via the AFTMAN_ROOT
// environment variable.
if let Ok(var) = env::var("AFTMAN_HOME") {
if let Ok(var) = env::var("AFTMAN_ROOT") {
return Ok(Self::from_path(var));
}

let mut path =
dirs::home_dir().ok_or_else(|| format_err!("Home directory could not be found."))?;
home_dir().ok_or_else(|| format_err!("Home directory could not be found."))?;

path.push(".aftman");

Expand Down Expand Up @@ -55,4 +57,31 @@ impl Home {
pub fn path(&self) -> &Path {
self.path.as_ref()
}

pub fn path_str(&self) -> String {
rehomeify(&self.path)
}

pub fn bin_dir(&self) -> PathBuf {
self.path.join("bin")
}

pub fn bin_dir_str(&self) -> String {
rehomeify(&self.bin_dir())
}
}

/// Returns a human-friendly version of `path`, re-substituting `$HOME` if
/// it is present in the path.
fn rehomeify(path: &Path) -> String {
if let Ok(home) = env::var("HOME") {
let prefix = Path::new(&home);
if let Ok(stripped) = path.strip_prefix(prefix) {
let rest = stripped.to_str().unwrap();

return format!("$HOME{MAIN_SEPARATOR}{rest}");
}
}

path.to_str().unwrap().to_owned()
}
2 changes: 2 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod cli;
mod config;
mod dirs;
mod home;
mod ident;
mod manifest;
Expand Down Expand Up @@ -62,6 +63,7 @@ fn run() -> anyhow::Result<()> {
}

Manifest::init_global(&home)?;
system_path::init(&home)?;

Args::from_args().run(&home, tool_storage)
}
Expand Down
16 changes: 16 additions & 0 deletions src/system_path/env.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh

# This script adds Aftman to the user's PATH and is run via the user's
# shell-specific profile.
#
# This is adapted from Rustup:
# https://github.com/rust-lang/rustup/blob/feec94b6e0203cb6ad023b1e2c953d058e5c3acd/src/cli/self_update/env.sh

case ":${PATH}:" in
*:"{our_bin_dir}":*)
;;

*)
export PATH="{our_bin_dir}:$PATH"
;;
esac
39 changes: 34 additions & 5 deletions src/system_path/mod.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,40 @@
#[cfg(target_os = "windows")]
use std::env;

use crate::home::Home;

mod unix;

#[cfg(windows)]
mod windows;

#[cfg(target_os = "windows")]
pub use windows::add;
#[allow(unreachable_code)]
pub fn init(home: &Home) -> anyhow::Result<()> {
// Users can define this environment variable to force Aftman to interact
// with the user's PATH like a Unix machine. This is helpful for running
// tests on Windows.
if cfg!(unix) || env::var("AFTMAN_PATH_UNIX").is_ok() {
return unix::init(home);
}

#[cfg(windows)]
{
return windows::init(home);
}

Ok(())
}

#[allow(unreachable_code)]
pub fn add(home: &Home) -> anyhow::Result<bool> {
if cfg!(unix) || env::var("AFTMAN_PATH_UNIX").is_ok() {
return unix::add(home);
}

#[cfg(windows)]
{
return windows::add(home);
}

#[cfg(not(target_os = "windows"))]
pub fn add(_path: &std::path::Path) -> anyhow::Result<bool> {
log::debug!("Not adding value to path because this platform is not supported.");
Ok(false)
}
Loading

0 comments on commit f97a675

Please sign in to comment.