Skip to content

Commit

Permalink
new: Add builtin-plugins setting. (#553)
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj committed Jul 26, 2024
1 parent 68d1cc9 commit 9789648
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 14 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

#### 🚀 Updates

- Added a new setting to `.prototools`, `settings.builtin-plugins`, that can be used to disable all built-in plugins, or only allow a few select plugins.
- Supports a boolean or list of plugin names.
- All are enabled by default for backwards compatibility.
- Merged `proto use` and `proto install` commands. If no arguments are provided to `proto install`, it will install all configured tools.

## 0.38.4
Expand Down
21 changes: 21 additions & 0 deletions crates/cli/tests/plugins_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use proto_core::{
load_tool_from_locator, Id, PluginLocator, ProtoEnvironment, Tool, UnresolvedVersionSpec,
};
use starbase_sandbox::assert_snapshot;
use starbase_sandbox::predicates::prelude::*;
use std::env;
use std::fs;
use std::future::Future;
Expand Down Expand Up @@ -331,5 +332,25 @@ mod plugins {

// Doesn't create shims
}

#[test]
fn errors_if_disabled() {
let sandbox = create_empty_proto_sandbox();
sandbox.create_file(
".prototools",
r#"
[settings]
builtin-plugins = false
"#,
);

let assert = sandbox
.run_bin(|cmd| {
cmd.arg("install").arg("go");
})
.failure();

assert.stderr(predicate::str::contains("Unable to proceed, go"));
}
}
}
48 changes: 37 additions & 11 deletions crates/core/src/proto_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ use indexmap::IndexMap;
use once_cell::sync::OnceCell;
use rustc_hash::FxHashMap;
use schematic::{
derive_enum, env, merge, Config, ConfigEnum, ConfigError, ConfigLoader, Format, HandlerError,
MergeResult, PartialConfig, ValidateError, ValidateErrorType, ValidatorError,
derive_enum, env, merge, Config, ConfigEnum, ConfigError, ConfigLoader, DefaultValueResult,
Format, HandlerError, MergeResult, PartialConfig, ValidateError, ValidateErrorType,
ValidatorError,
};
use serde::Serialize;
use serde::{Deserialize, Serialize};
use starbase_styles::color;
use starbase_utils::json::JsonValue;
use starbase_utils::toml::TomlValue;
Expand Down Expand Up @@ -102,6 +103,17 @@ impl EnvVar {
}
}

#[derive(Clone, Config, Debug, Deserialize, PartialEq, Serialize)]
#[serde(untagged)]
pub enum BuiltinPlugins {
Enabled(bool),
Allowed(Vec<String>),
}

fn default_builtin_plugins(_context: &()) -> DefaultValueResult<BuiltinPlugins> {
Ok(Some(BuiltinPlugins::Enabled(true)))
}

#[derive(Clone, Config, Debug, Serialize)]
#[config(allow_unknown_fields)]
#[serde(rename_all = "kebab-case")]
Expand Down Expand Up @@ -129,6 +141,9 @@ pub struct ProtoSettingsConfig {
#[setting(env = "PROTO_AUTO_INSTALL", parse_env = env::parse_bool)]
pub auto_install: bool,

#[setting(default = default_builtin_plugins)]
pub builtin_plugins: BuiltinPlugins,

#[setting(env = "PROTO_DETECT_STRATEGY")]
pub detect_strategy: DetectStrategy,

Expand Down Expand Up @@ -170,14 +185,25 @@ pub struct ProtoConfig {
}

impl ProtoConfig {
pub fn builtin_plugins() -> BTreeMap<Id, PluginLocator> {
pub fn builtin_plugins(&self) -> BTreeMap<Id, PluginLocator> {
let mut config = ProtoConfig::default();

// Inherit this setting in case builtins have been disabled
config.settings.builtin_plugins = self.settings.builtin_plugins.clone();

// Then inherit all the available builtins
config.inherit_builtin_plugins();

config.plugins
}

pub fn inherit_builtin_plugins(&mut self) {
if !self.plugins.contains_key("bun") {
let is_allowed = |id: &str| match &self.settings.builtin_plugins {
BuiltinPlugins::Enabled(state) => *state,
BuiltinPlugins::Allowed(list) => list.iter().any(|aid| aid == id),
};

if !self.plugins.contains_key("bun") && is_allowed("bun") {
self.plugins.insert(
Id::raw("bun"),
PluginLocator::Url {
Expand All @@ -186,7 +212,7 @@ impl ProtoConfig {
);
}

if !self.plugins.contains_key("deno") {
if !self.plugins.contains_key("deno") && is_allowed("deno") {
self.plugins.insert(
Id::raw("deno"),
PluginLocator::Url {
Expand All @@ -195,7 +221,7 @@ impl ProtoConfig {
);
}

if !self.plugins.contains_key("go") {
if !self.plugins.contains_key("go") && is_allowed("go") {
self.plugins.insert(
Id::raw("go"),
PluginLocator::Url {
Expand All @@ -204,7 +230,7 @@ impl ProtoConfig {
);
}

if !self.plugins.contains_key("node") {
if !self.plugins.contains_key("node") && is_allowed("node") {
self.plugins.insert(
Id::raw("node"),
PluginLocator::Url {
Expand All @@ -214,7 +240,7 @@ impl ProtoConfig {
}

for depman in ["npm", "pnpm", "yarn"] {
if !self.plugins.contains_key(depman) {
if !self.plugins.contains_key(depman) && is_allowed(depman) {
self.plugins.insert(
Id::raw(depman),
PluginLocator::Url {
Expand All @@ -224,7 +250,7 @@ impl ProtoConfig {
}
}

if !self.plugins.contains_key("python") {
if !self.plugins.contains_key("python") && is_allowed("python") {
self.plugins.insert(
Id::raw("python"),
PluginLocator::Url {
Expand All @@ -233,7 +259,7 @@ impl ProtoConfig {
);
}

if !self.plugins.contains_key("rust") {
if !self.plugins.contains_key("rust") && is_allowed("rust") {
self.plugins.insert(
Id::raw("rust"),
PluginLocator::Url {
Expand Down
4 changes: 2 additions & 2 deletions crates/core/src/tool_loader.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::error::ProtoError;
use crate::proto::ProtoEnvironment;
use crate::proto_config::{ProtoConfig, SCHEMA_PLUGIN_KEY};
use crate::proto_config::SCHEMA_PLUGIN_KEY;
use crate::tool::Tool;
use starbase_utils::{json, toml};
use std::fmt::Debug;
Expand Down Expand Up @@ -50,7 +50,7 @@ pub fn locate_tool(id: &Id, proto: &ProtoEnvironment) -> miette::Result<PluginLo

// And finally the built-in plugins
if locator.is_none() {
let builtin_plugins = ProtoConfig::builtin_plugins();
let builtin_plugins = configs.get_merged_config()?.builtin_plugins();

if let Some(maybe_locator) = builtin_plugins.get(id) {
debug!(
Expand Down
98 changes: 98 additions & 0 deletions crates/core/tests/proto_config_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,104 @@ foo = "file://./test.toml"
);
}

mod builtins {
use super::*;
use proto_core::BuiltinPlugins;
use schematic::Config;

#[test]
fn can_enable() {
let sandbox = create_empty_sandbox();
sandbox.create_file(
".prototools",
r#"
[settings]
builtin-plugins = true
"#,
);

let config =
ProtoConfig::from_partial(ProtoConfig::load_from(sandbox.path(), false).unwrap());

assert_eq!(
config.settings.builtin_plugins,
BuiltinPlugins::Enabled(true)
);

assert_eq!(config.builtin_plugins().len(), 10);
}

#[test]
fn can_enable_with_list() {
let sandbox = create_empty_sandbox();
sandbox.create_file(
".prototools",
r#"
[settings]
builtin-plugins = ["node", "go"]
"#,
);

let config =
ProtoConfig::from_partial(ProtoConfig::load_from(sandbox.path(), false).unwrap());

assert_eq!(
config.settings.builtin_plugins,
BuiltinPlugins::Allowed(vec!["node".into(), "go".into()])
);

assert_eq!(config.builtin_plugins().len(), 3);
assert_eq!(
config.builtin_plugins().keys().collect::<Vec<_>>(),
["go", "internal-schema", "node"]
);
}

#[test]
fn can_disable() {
let sandbox = create_empty_sandbox();
sandbox.create_file(
".prototools",
r#"
[settings]
builtin-plugins = false
"#,
);

let config =
ProtoConfig::from_partial(ProtoConfig::load_from(sandbox.path(), false).unwrap());

assert_eq!(
config.settings.builtin_plugins,
BuiltinPlugins::Enabled(false)
);

assert_eq!(config.builtin_plugins().len(), 1);
}

#[test]
fn can_disable_with_list() {
let sandbox = create_empty_sandbox();
sandbox.create_file(
".prototools",
r#"
[settings]
builtin-plugins = []
"#,
);

let config =
ProtoConfig::from_partial(ProtoConfig::load_from(sandbox.path(), false).unwrap());

assert_eq!(
config.settings.builtin_plugins,
BuiltinPlugins::Allowed(vec![])
);

assert_eq!(config.builtin_plugins().len(), 1);
}
}

mod tool_config {
use super::*;
use rustc_hash::FxHashMap;
Expand Down
5 changes: 4 additions & 1 deletion crates/core/tests/version_detector_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ mod version_detector {
load_tool_from_locator(
Id::raw("node"),
ProtoEnvironment::new().unwrap(),
ProtoConfig::builtin_plugins().get("node").unwrap(),
ProtoConfig::default()
.builtin_plugins()
.get("node")
.unwrap(),
)
.await
.unwrap()
Expand Down

0 comments on commit 9789648

Please sign in to comment.