Skip to content

Commit

Permalink
new: Support pinning proto in .prototools. (#560)
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj authored Jul 24, 2024
1 parent 6342b52 commit 00f5833
Show file tree
Hide file tree
Showing 14 changed files with 201 additions and 38 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
- Added `PROTO_NO_MODIFY_PROFILE` and `PROTO_NO_MODIFY_PATH` environment variables to `proto setup` (for automated workflows).
- Updated `github://` plugin locators to support monorepos. Append the project name (that tags are prefixed with) to the path: `github://moonrepo/tools/node_tool`
- Merged `proto use` and `proto install` commands. If no arguments are provided to `proto install`, it will install all configured tools.
- You can now pin a version of proto itself within `.prototools`, and proto shims will attempt to run proto using that configured version, instead of the global version.
```toml
proto = "0.38.0"
```

## 0.38.4

Expand Down
40 changes: 15 additions & 25 deletions Cargo.lock

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

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ default-members = ["crates/cli"]
[workspace.dependencies]
anyhow = "1.0.86"
async-trait = "0.1.81"
clap = "4.5.9"
clap_complete = "4.5.8"
clap = "4.5.10"
clap_complete = "4.5.9"
dirs = "5.0.1"
extism = "1.0.0" # Lower for consumers
extism-pdk = "1.2.0"
Expand Down Expand Up @@ -50,7 +50,7 @@ starbase_utils = { version = "0.8.3", default-features = false, features = [
"toml",
] }
thiserror = "1.0.63"
tokio = { version = "1.38.1", features = ["full", "tracing"] }
tokio = { version = "1.39.1", features = ["full", "tracing"] }
tracing = "0.1.40"
uuid = { version = "1.10.0", features = ["v4"] }

Expand Down
12 changes: 12 additions & 0 deletions crates/cli/src/commands/bin.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::session::ProtoSession;
use clap::Args;
use proto_core::{detect_version, Id, UnresolvedVersionSpec};
use proto_shim::{get_exe_file_name, locate_proto_exe};
use starbase::AppResult;

#[derive(Args, Clone, Debug)]
Expand All @@ -20,6 +21,17 @@ pub struct BinArgs {

#[tracing::instrument(skip_all)]
pub async fn bin(session: ProtoSession, args: BinArgs) -> AppResult {
if args.id == "proto" {
println!(
"{}",
locate_proto_exe("proto")
.unwrap_or(session.env.store.bin_dir.join(get_exe_file_name("proto")))
.display()
);

return Ok(());
}

let mut tool = session.load_tool(&args.id).await?;
let version = detect_version(&tool, args.spec.clone()).await?;

Expand Down
1 change: 1 addition & 0 deletions crates/cli/src/commands/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ pub async fn install_all(session: &ProtoSession, args: InstallArgs) -> AppResult
.get_merged_config_without_global()?
};
let mut versions = config.versions.to_owned();
versions.remove("proto");

for tool in &tools {
if versions.contains_key(&tool.id) {
Expand Down
4 changes: 4 additions & 0 deletions crates/cli/src/commands/outdated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ pub async fn outdated(session: ProtoSession, args: OutdatedArgs) -> AppResult {

if let Some(file_versions) = &file.config.versions {
for (tool_id, config_version) in file_versions {
if tool_id == "proto" {
continue;
}

configured_tools.insert(
tool_id.to_owned(),
(config_version.to_owned(), file.path.to_owned()),
Expand Down
4 changes: 4 additions & 0 deletions crates/cli/src/commands/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ pub async fn status(session: ProtoSession, args: StatusArgs) -> AppResult {

if let Some(file_versions) = &file.config.versions {
for (tool_id, config_version) in file_versions {
if tool_id == "proto" {
continue;
}

items.insert(
tool_id.to_owned(),
StatusItem {
Expand Down
5 changes: 4 additions & 1 deletion crates/cli/src/main_shim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ pub fn main() -> Result<()> {

debug(|| "Running proto shim".into());

// Set the version variable so child processes utilize it
env::set_var("PROTO_VERSION", env!("CARGO_PKG_VERSION"));

// Extract arguments to pass-through
let args = env::args_os().collect::<Vec<_>>();

Expand Down Expand Up @@ -197,9 +200,9 @@ pub fn main() -> Result<()> {
command.env("PROTO_SHIM_NAME", shim_name);
command.env("PROTO_SHIM_PATH", exe_path);

// Must be the last line!
debug(|| "Executing proto command".into());
debug(|| "This will replace the current process and stop debugging!".into());

// Must be the last line!
Ok(exec_command_and_replace(command)?)
}
3 changes: 3 additions & 0 deletions crates/cli/src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,14 @@ impl AppSession for ProtoSession {
async fn startup(&mut self) -> AppResult {
self.env = Arc::new(detect_proto_env()?);

sync_current_proto_tool(&self.env, &self.cli_version)?;

Ok(())
}

async fn analyze(&mut self) -> AppResult {
load_proto_configs(&self.env)?;
download_versioned_proto_tool(&self.env).await?;

Ok(())
}
Expand Down
78 changes: 76 additions & 2 deletions crates/cli/src/systems.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use crate::helpers::fetch_latest_version;
use miette::IntoDiagnostic;
use proto_core::{is_offline, now, ProtoEnvironment};
use proto_core::{is_offline, now, ProtoEnvironment, UnresolvedVersionSpec, PROTO_CONFIG_NAME};
use proto_installer::{determine_triple, download_release, unpack_release};
use proto_shim::get_exe_file_name;
use semver::Version;
use starbase::AppResult;
use starbase_styles::color;
use starbase_utils::fs;
use std::env;
use std::sync::Arc;
use std::time::Duration;
use tracing::{debug, instrument};
use tracing::{debug, instrument, trace};

// STARTUP

Expand All @@ -17,6 +19,32 @@ pub fn detect_proto_env() -> AppResult<ProtoEnvironment> {
ProtoEnvironment::new()
}

#[instrument(skip_all)]
pub fn sync_current_proto_tool(env: &ProtoEnvironment, version: &str) -> AppResult {
let tool_dir = env.store.inventory_dir.join("proto").join(version);

if tool_dir.exists() {
return Ok(());
}

let Ok(current_exe) = env::current_exe() else {
return Ok(());
};

let exe_dir = current_exe.parent().unwrap_or(&env.store.bin_dir);

for exe_name in [get_exe_file_name("proto"), get_exe_file_name("proto-shim")] {
let src_file = exe_dir.join(&exe_name);
let dst_file = tool_dir.join(&exe_name);

if src_file.exists() && !dst_file.exists() {
fs::copy_file(src_file, dst_file)?;
}
}

Ok(())
}

// ANALYZE

#[instrument(skip_all)]
Expand All @@ -26,6 +54,52 @@ pub fn load_proto_configs(env: &ProtoEnvironment) -> AppResult {
Ok(())
}

#[instrument(skip_all)]
pub async fn download_versioned_proto_tool(env: &ProtoEnvironment) -> AppResult {
if is_offline() {
return Ok(());
}

let config = env
.load_config_manager()?
.get_merged_config_without_global()?;

if let Some(UnresolvedVersionSpec::Semantic(version)) = config.versions.get("proto") {
let version = version.to_string();
let tool_dir = env.store.inventory_dir.join("proto").join(&version);

if tool_dir.exists() {
return Ok(());
}

let triple_target = determine_triple()?;

debug!(
version = &version,
install_dir = ?tool_dir,
"Downloading a versioned proto because it was configured in {}",
PROTO_CONFIG_NAME
);

unpack_release(
download_release(
&triple_target,
&version,
&env.store.temp_dir,
|downloaded_size, total_size| {
trace!("Downloaded {} of {} bytes", downloaded_size, total_size);
},
)
.await?,
&tool_dir,
&tool_dir,
false,
)?;
}

Ok(())
}

// EXECUTE

#[instrument(skip_all)]
Expand Down
38 changes: 38 additions & 0 deletions crates/cli/tests/general_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
mod utils;

use utils::*;

mod systems {
use super::*;

#[test]
fn copies_current_bin_to_store() {
let sandbox = create_empty_proto_sandbox();

sandbox
.run_bin(|cmd| {
cmd.arg("bin").arg("proto");
})
.success();

assert!(sandbox
.path()
.join(".proto/tools/proto")
.join(env!("CARGO_PKG_VERSION"))
.exists());
}

#[test]
fn downloads_versioned_bin_to_store() {
let sandbox = create_empty_proto_sandbox();
sandbox.create_file(".prototools", r#"proto = "0.30.0""#);

sandbox
.run_bin(|cmd| {
cmd.arg("bin").arg("proto");
})
.success();

assert!(sandbox.path().join(".proto/tools/proto/0.30.0").exists());
}
}
Loading

0 comments on commit 00f5833

Please sign in to comment.