Skip to content

Commit

Permalink
internal: Final polish before release. (#536)
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj committed Jul 4, 2024
1 parent 36200e2 commit cdff60f
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 48 deletions.
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

#### 🚀 Updates

- Added an experimental command called `proto activate` that can be ran within your shell to "activate the proto environment", by setting necessary environment variables and paths when changing directories.
- Added an experimental command called `proto activate` that can be ran within your shell profile to "activate the proto environment", by setting necessary environment variables and paths when changing directories.
- Globally installed packages will now be available automatically. This wasn't possible through shims alone.
- Binaries that come pre-installed with a tool (and are not shims) will also be available automatically.
- Added support for [murex](https://murex.rocks/) shells.
Expand All @@ -27,8 +27,13 @@

#### 🧩 Plugins

- Updated `rust_plugin` to v0.10.4.
- Updated `node_plugin` and `node_depman_plugin` to v0.11.4.
- Updated `python_plugin` to v0.10.4.
- Updated `rust_plugin` to v0.10.5.
- Respect `CARGO_HOME` during rustup installation.
- Updated `schema_plugin` (TOML) to v0.14.0.
- Added `platform.*.exes_dir`.
- Renamed `platform.*.bin_path` to `exe_path`.

## 0.37.2

Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ starbase_archive = { version = "0.8.0", features = [
] }
starbase_events = { version = "0.6.2" }
starbase_sandbox = { version = "0.6.4" }
starbase_shell = { version = "0.4.0", features = ["miette"] }
starbase_shell = { version = "0.5.0", features = ["miette"] }
starbase_styles = { version = "0.4.1" }
starbase_utils = { version = "0.8.0", default-features = false, features = [
"json",
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ proto is a pluggable next-generation version manager for multiple programming la
- Python
- Rust
- ... [and more via plugins!](https://moonrepo.dev/docs/proto/tools)

## Contributors

Special thanks to the wonderful people who have contributed to this project:

[![Contributors](https://contrib.rocks/image?repo=moonrepo/proto)](https://github.com/moonrepo/proto/graphs/contributors)
3 changes: 2 additions & 1 deletion crates/cli/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ impl App {
pub enum Commands {
#[command(
name = "activate",
about = "Activate proto for the current shell session by prepending tool directories to PATH and setting environment variables."
about = "Activate proto for the current shell session by prepending tool directories to PATH and setting environment variables.",
long_about = "Activate proto for the current shell session by prepending tool directories to PATH and setting environment variables.\n\nThis should be ran within your shell profile.\nLearn more: https://moonrepo.dev/docs/proto/workflows"
)]
Activate(ActivateArgs),

Expand Down
128 changes: 97 additions & 31 deletions crates/cli/src/commands/activate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ use miette::IntoDiagnostic;
use proto_core::{detect_version, Id};
use serde::Serialize;
use starbase::AppResult;
use starbase_shell::{Hook, ShellType};
use starbase_styles::color;
use starbase_shell::{BoxedShell, Hook, ShellType, Statement};
use starbase_utils::json;
use std::path::PathBuf;
use std::env;
use std::path::{Path, PathBuf};
use tokio::task::{self, JoinHandle};
use tracing::warn;

#[derive(Default, Serialize)]
struct ActivateItem {
Expand All @@ -19,6 +18,15 @@ struct ActivateItem {
pub paths: Vec<PathBuf>,
}

impl ActivateItem {
pub fn add_path(&mut self, path: &Path) {
// Only add paths that exist and are normalized
if let Ok(path) = path.canonicalize() {
self.paths.push(path);
}
}
}

#[derive(Default, Serialize)]
struct ActivateInfo {
pub env: IndexMap<String, Option<String>>,
Expand All @@ -38,21 +46,61 @@ impl ActivateInfo {
self.env.extend(item.env.clone());
self.tools.push(item);
}

pub fn export(self, shell: &BoxedShell) -> String {
let mut output = vec![];

for (key, value) in &self.env {
output.push(shell.format_env(key, value.as_deref()));
}

let paths = self
.paths
.iter()
.filter_map(|path| path.to_str().map(|p| p.to_owned()))
.collect::<Vec<_>>();

if !paths.is_empty() {
output.push(shell.format(Statement::PrependPath {
paths: &paths,
key: Some("PATH"),
orig_key: if env::var("__ORIG_PATH").is_ok() {
Some("__ORIG_PATH")
} else {
None
},
}));
}

output.join("\n")
}
}

#[derive(Args, Clone, Debug)]
pub struct ActivateArgs {
#[arg(help = "Shell to activate for")]
shell: Option<ShellType>,

#[arg(long, help = "Print the info in JSON format")]
#[arg(
long,
help = "Print the activate instructions in shell specific-syntax"
)]
export: bool,

#[arg(long, help = "Print the activate instructions in JSON format")]
json: bool,

#[arg(long, help = "Don't include ~/.proto/bin in path lookup")]
no_bin: bool,

#[arg(long, help = "Don't include ~/.proto/shims in path lookup")]
no_shim: bool,
}

#[tracing::instrument(skip_all)]
pub async fn activate(session: ProtoSession, args: ActivateArgs) -> AppResult {
// Detect the shell that we need to activate for
let shell = match args.shell {
let shell_type = match args.shell {
Some(value) => value,
None => ShellType::try_detect()?,
};
Expand All @@ -73,21 +121,25 @@ pub async fn activate(session: ProtoSession, args: ActivateArgs) -> AppResult {
return Ok(item);
};

// This runs the resolve -> locate flow
// Resolve the version and locate executables
if tool.is_setup(&version).await? {
tool.locate_exes_dir().await?;
tool.locate_globals_dirs().await?;

// Higher priority over globals
if let Some(exe_dir) = tool.get_exes_dir() {
item.paths.push(exe_dir.to_owned());
item.add_path(exe_dir);
}

item.paths.extend(tool.get_globals_dirs().to_owned());
for global_dir in tool.get_globals_dirs() {
item.add_path(global_dir);
}
}

item.env
.extend(tool.proto.load_config()?.get_env_vars(Some(&tool.id))?);
// Inherit all environment variables for the config
let config = tool.proto.load_config()?;

item.env.extend(config.get_env_vars(Some(&tool.id))?);
item.id = tool.id;

Ok(item)
Expand All @@ -97,15 +149,27 @@ pub async fn activate(session: ProtoSession, args: ActivateArgs) -> AppResult {
// Aggregate our list of shell exports
let mut info = ActivateInfo::default();

info.paths.extend([
session.env.store.shims_dir.clone(),
session.env.store.bin_dir.clone(),
]);
// Put shims first so that they can detect newer versions
if !args.no_shim {
info.paths.push(session.env.store.shims_dir.clone());
}

for future in futures {
let item = future.await.into_diagnostic()??;
info.collect(future.await.into_diagnostic()??);
}

info.collect(item);
// Put bins last as a last resort lookup
if !args.no_bin {
info.paths.push(session.env.store.bin_dir.clone());
}

// Output/export the information for the chosen shell
let shell = shell_type.build();

if args.export {
println!("{}", info.export(&shell));

return Ok(());
}

if args.json {
Expand All @@ -114,25 +178,27 @@ pub async fn activate(session: ProtoSession, args: ActivateArgs) -> AppResult {
return Ok(());
}

// Output in shell specific syntax
match shell.build().format_hook(Hook::OnChangeDir {
env: info.env.into_iter().collect(),
paths: info
.paths
.into_iter()
.map(|path| path.to_string_lossy().to_string())
.collect(),
match shell.format_hook(Hook::OnChangeDir {
command: match shell_type {
// These operate on JSON
ShellType::Nu => format!("proto activate {} --json", shell_type),
// While these evaluate shell syntax
_ => format!("proto activate {} --export", shell_type),
},
prefix: "proto".into(),
}) {
Ok(output) => {
println!("{output}");
}
Err(error) => {
warn!(
"Failed to run {}. Perhaps remove it for the time being?",
color::shell("proto activate")
);
warn!("Reason: {}", color::muted_light(error.to_string()));
Err(_) => {
// Do nothing? This command is typically wrapped in `eval`,
// so these warnings would actually just trigger a syntax error.

// warn!(
// "Failed to run {}. Perhaps remove it for the time being?",
// color::shell("proto activate")
// );
// warn!("Reason: {}", color::muted_light(error.to_string()));
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
source: crates/cli/tests/activate_test.rs
expression: "get_activate_output(&assert, &sandbox)"
---
export __ORIG_PATH="$PATH"

_proto_hook() {
local previous_exit_status=$?;
trap -- '' SIGINT;

export PATH="/sandbox/.proto/shims:/sandbox/.proto/bin:$PATH";
eval "$(proto activate bash --export)";
trap - SIGINT;
return $previous_exit_status;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
source: crates/cli/tests/activate_test.rs
expression: "get_activate_output(&assert, &sandbox)"
---
set -gx __ORIG_PATH $PATH

function __proto_hook --on-variable PWD;

set -gx PATH "/sandbox/.proto/shims:/sandbox/.proto/bin" $PATH;
proto activate fish --export | source
end;
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
source: crates/cli/tests/activate_test.rs
expression: "get_activate_output(&assert, &sandbox)"
---
export __ORIG_PATH="$PATH"

_proto_hook() {
trap -- '' SIGINT

export PATH="/sandbox/.proto/shims:/sandbox/.proto/bin:$PATH";
eval "$(proto activate zsh --export)";
trap - SIGINT
}
typeset -ag precmd_functions
Expand Down
10 changes: 5 additions & 5 deletions crates/core/src/proto_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ impl ProtoConfig {
self.plugins.insert(
Id::raw("node"),
PluginLocator::Url {
url: "https://github.com/moonrepo/node-plugin/releases/download/v0.11.3/node_plugin.wasm".into()
url: "https://github.com/moonrepo/node-plugin/releases/download/v0.11.4/node_plugin.wasm".into()
}
);
}
Expand All @@ -218,7 +218,7 @@ impl ProtoConfig {
self.plugins.insert(
Id::raw(depman),
PluginLocator::Url {
url: "https://github.com/moonrepo/node-plugin/releases/download/v0.11.3/node_depman_plugin.wasm".into()
url: "https://github.com/moonrepo/node-plugin/releases/download/v0.11.4/node_depman_plugin.wasm".into()
}
);
}
Expand All @@ -228,7 +228,7 @@ impl ProtoConfig {
self.plugins.insert(
Id::raw("python"),
PluginLocator::Url {
url: "https://github.com/moonrepo/python-plugin/releases/download/v0.10.3/python_plugin.wasm".into()
url: "https://github.com/moonrepo/python-plugin/releases/download/v0.10.4/python_plugin.wasm".into()
}
);
}
Expand All @@ -237,7 +237,7 @@ impl ProtoConfig {
self.plugins.insert(
Id::raw("rust"),
PluginLocator::Url {
url: "https://github.com/moonrepo/rust-plugin/releases/download/v0.10.4/rust_plugin.wasm".into()
url: "https://github.com/moonrepo/rust-plugin/releases/download/v0.10.5/rust_plugin.wasm".into()
}
);
}
Expand All @@ -246,7 +246,7 @@ impl ProtoConfig {
self.plugins.insert(
Id::raw(SCHEMA_PLUGIN_KEY),
PluginLocator::Url {
url: "https://github.com/moonrepo/schema-plugin/releases/download/v0.13.1/schema_plugin.wasm".into()
url: "https://github.com/moonrepo/schema-plugin/releases/download/v0.14.0/schema_plugin.wasm".into()
}
);
}
Expand Down

0 comments on commit cdff60f

Please sign in to comment.