This repository has been archived by the owner on Jul 17, 2024. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
356 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
github: moonrepo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
branches: | ||
- master | ||
pull_request: | ||
|
||
jobs: | ||
format: | ||
name: Format | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
matrix: | ||
os: [ubuntu-latest, windows-latest] | ||
fail-fast: false | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: moonrepo/setup-rust@v1 | ||
with: | ||
components: rustfmt | ||
- run: cargo fmt --all --check | ||
lint: | ||
name: Lint | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
matrix: | ||
os: [ubuntu-latest, windows-latest] | ||
fail-fast: false | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: moonrepo/setup-rust@v1 | ||
with: | ||
components: clippy | ||
- run: cargo clippy --workspace --all-targets | ||
test: | ||
name: Test | ||
runs-on: ${{ matrix.os }} | ||
strategy: | ||
matrix: | ||
os: [ubuntu-latest, macos-latest, windows-latest] | ||
fail-fast: false | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: moonrepo/setup-rust@v1 | ||
with: | ||
bins: cargo-wasi, cargo-nextest | ||
- run: cargo wasi build | ||
- run: cargo nextest run |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[plugins] | ||
schema-test = "source:target/wasm32-wasi/debug/schema_plugin.wasm" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# Changelog | ||
|
||
## 0.0.1 | ||
|
||
#### 🎉 Release | ||
|
||
- Initial release! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
[package] | ||
name = "schema_plugin" | ||
version = "0.0.1" | ||
edition = "2021" | ||
license = "MIT" | ||
publish = false | ||
|
||
[lib] | ||
crate-type = ['cdylib'] | ||
|
||
[dependencies] | ||
extism-pdk = "0.3.3" | ||
proto_pdk = "0.4.2" | ||
proto_schema_plugin = { version = "0.8.1", path = "../../proto/crates/schema-plugin" } | ||
regex = "1.9.3" | ||
serde = "1.0.183" | ||
serde_json = "1.0.104" | ||
starbase_utils = { version = "0.2.17", default-features = false, features = [ | ||
"toml", | ||
] } | ||
|
||
[dev-dependencies] | ||
proto_pdk_test_utils = "0.3.3" | ||
starbase_sandbox = "0.1.8" | ||
tokio = "1.30.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
MIT License | ||
|
||
Copyright (c) 2023 moonrepo, Inc. | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and | ||
associated documentation files (the "Software"), to deal in the Software without restriction, | ||
including without limitation the rights to use, copy, modify, merge, publish, distribute, | ||
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial | ||
portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT | ||
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES | ||
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Schema plugin | ||
|
||
WASM plugin for [proto](https://github.com/moonrepo/proto) that is powered by a schema. Currently supports TOML. | ||
|
||
## Contributing | ||
|
||
Build the plugin: | ||
|
||
```shell | ||
cargo build --target wasm32-wasi | ||
``` | ||
|
||
Test the plugin by running `proto` commands. Requires proto >= v0.12. | ||
|
||
```shell | ||
proto install schema-test | ||
proto list-remote schema-test | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[toolchain] | ||
profile = "default" | ||
channel = "1.71.1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// WASM cannot be executed through the test runner and we need to avoid building | ||
// WASM code for non-WASM targets. We can solve both of these with a cfg flag. | ||
|
||
mod proto; | ||
|
||
pub use proto::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,227 @@ | ||
use extism_pdk::*; | ||
use proto_pdk::*; | ||
use proto_schema_plugin::{PlatformMapper, Schema, SchemaType}; | ||
use serde_json::Value as JsonValue; | ||
use starbase_utils::toml; | ||
use std::path::PathBuf; | ||
|
||
#[host_fn] | ||
extern "ExtismHost" { | ||
fn exec_command(input: Json<ExecCommandInput>) -> Json<ExecCommandOutput>; | ||
} | ||
|
||
fn get_schema() -> Result<Schema, Error> { | ||
let data = config::get("schema").expect("Missing schema!"); | ||
let schema: Schema = toml::from_str(&data)?; | ||
|
||
Ok(schema) | ||
} | ||
|
||
fn get_platform<'schema>( | ||
schema: &'schema Schema, | ||
env: &Environment, | ||
) -> Result<&'schema PlatformMapper, PluginError> { | ||
let os = env.os.to_string(); | ||
let mut platform = schema.platform.get(&os); | ||
|
||
// Fallback to linux for other OSes | ||
if platform.is_none() | ||
&& (env.os == HostOS::FreeBSD || env.os == HostOS::NetBSD || env.os == HostOS::OpenBSD) | ||
{ | ||
platform = schema.platform.get("linux"); | ||
} | ||
|
||
platform.ok_or_else(|| PluginError::UnsupportedOS { | ||
tool: schema.name.clone(), | ||
os, | ||
}) | ||
} | ||
|
||
fn get_bin_path(platform: &PlatformMapper, env: &Environment) -> PathBuf { | ||
platform | ||
.bin_path | ||
.clone() | ||
.unwrap_or_else(|| format_bin_name(&env.id, env.os)) | ||
.into() | ||
} | ||
|
||
#[plugin_fn] | ||
pub fn register_tool(Json(_): Json<ToolMetadataInput>) -> FnResult<Json<ToolMetadataOutput>> { | ||
let schema = get_schema()?; | ||
|
||
Ok(Json(ToolMetadataOutput { | ||
name: schema.name, | ||
type_of: match schema.type_of { | ||
SchemaType::Cli => PluginType::CLI, | ||
SchemaType::DependencyManager => PluginType::DependencyManager, | ||
SchemaType::Language => PluginType::Language, | ||
}, | ||
..ToolMetadataOutput::default() | ||
})) | ||
} | ||
|
||
fn is_musl() -> bool { | ||
if cfg!(macos) { | ||
false | ||
} else { | ||
unsafe { | ||
match exec_command(Json(ExecCommandInput::pipe("ldd", ["--version"]))) { | ||
Ok(res) => res.0.stdout.contains("musl"), | ||
Err(_) => false, | ||
} | ||
} | ||
} | ||
} | ||
|
||
fn interpolate_tokens(value: &str, schema: &Schema, env: &Environment) -> String { | ||
let arch = env.arch.to_rust_arch(); | ||
let os = env.os.to_string(); | ||
|
||
let mut value = value | ||
.replace("{version}", &env.version) | ||
.replace("{arch}", schema.install.arch.get(&arch).unwrap_or(&arch)) | ||
.replace("{os}", &os); | ||
|
||
// Avoid detecting musl unless requested | ||
if value.contains("{libc}") { | ||
value = value.replace("{libc}", if is_musl() { "musl" } else { "gnu" }); | ||
} | ||
|
||
value | ||
} | ||
|
||
#[plugin_fn] | ||
pub fn download_prebuilt( | ||
Json(input): Json<DownloadPrebuiltInput>, | ||
) -> FnResult<Json<DownloadPrebuiltOutput>> { | ||
let schema = get_schema()?; | ||
let platform = get_platform(&schema, &input.env)?; | ||
|
||
let download_file = interpolate_tokens(&platform.download_file, &schema, &input.env); | ||
let download_url = interpolate_tokens(&schema.install.download_url, &schema, &input.env) | ||
.replace("{download_file}", &download_file); | ||
|
||
let checksum_file = interpolate_tokens( | ||
platform | ||
.checksum_file | ||
.as_ref() | ||
.unwrap_or(&"CHECKSUM.txt".to_string()), | ||
&schema, | ||
&input.env, | ||
); | ||
let checksum_url = schema.install.checksum_url.as_ref().map(|url| { | ||
interpolate_tokens(&url, &schema, &input.env).replace("{checksum_file}", &checksum_file) | ||
}); | ||
|
||
Ok(Json(DownloadPrebuiltOutput { | ||
archive_prefix: platform.archive_prefix.clone(), | ||
checksum_url, | ||
checksum_name: Some(checksum_file), | ||
download_url, | ||
download_name: Some(download_file), | ||
})) | ||
} | ||
|
||
#[plugin_fn] | ||
pub fn locate_bins(Json(input): Json<LocateBinsInput>) -> FnResult<Json<LocateBinsOutput>> { | ||
let schema = get_schema()?; | ||
let platform = get_platform(&schema, &input.env)?; | ||
|
||
Ok(Json(LocateBinsOutput { | ||
bin_path: Some(get_bin_path(platform, &input.env)), | ||
fallback_last_globals_dir: true, | ||
globals_lookup_dirs: schema.globals.lookup_dirs, | ||
globals_prefix: schema.globals.package_prefix, | ||
..LocateBinsOutput::default() | ||
})) | ||
} | ||
|
||
pub fn remove_v_prefix(value: &str) -> &str { | ||
if value.starts_with('v') || value.starts_with('V') { | ||
return &value[1..]; | ||
} | ||
|
||
value | ||
} | ||
|
||
#[plugin_fn] | ||
pub fn load_versions(Json(_): Json<LoadVersionsInput>) -> FnResult<Json<LoadVersionsOutput>> { | ||
let schema = get_schema()?; | ||
|
||
if let Some(repository) = schema.resolve.git_url { | ||
let pattern = regex::Regex::new(&schema.resolve.git_tag_pattern)?; | ||
|
||
let tags = load_git_tags(&repository)? | ||
.into_iter() | ||
.filter_map(|t| { | ||
pattern | ||
.captures(&t) | ||
.map(|captures| remove_v_prefix(captures.get(1).unwrap().as_str()).to_string()) | ||
}) | ||
.collect::<Vec<_>>(); | ||
|
||
return Ok(Json(LoadVersionsOutput::from_tags(&tags)?)); | ||
} | ||
|
||
if let Some(endpoint) = schema.resolve.manifest_url { | ||
let response: Vec<JsonValue> = fetch_url_with_cache(endpoint)?; | ||
let version_key = &schema.resolve.manifest_version_key; | ||
let mut versions = vec![]; | ||
|
||
for row in response { | ||
match row { | ||
JsonValue::String(v) => { | ||
versions.push(remove_v_prefix(&v).to_string()); | ||
} | ||
JsonValue::Object(o) => { | ||
if let Some(JsonValue::String(v)) = o.get(version_key) { | ||
versions.push(remove_v_prefix(&v).to_string()); | ||
} | ||
} | ||
_ => {} | ||
} | ||
} | ||
|
||
return Ok(Json(LoadVersionsOutput::from_tags(&versions)?)); | ||
} | ||
|
||
err!( | ||
"Unable to resolve versions for {}. Schema either requires a `git_url` or `manifest_url`." | ||
.into() | ||
) | ||
} | ||
|
||
#[plugin_fn] | ||
pub fn detect_version_files(_: ()) -> FnResult<Json<DetectVersionOutput>> { | ||
let mut output = DetectVersionOutput::default(); | ||
let schema = get_schema()?; | ||
|
||
if let Some(files) = schema.detect.version_files { | ||
output.files = files; | ||
} | ||
|
||
Ok(Json(output)) | ||
} | ||
|
||
#[plugin_fn] | ||
pub fn create_shims(Json(input): Json<CreateShimsInput>) -> FnResult<Json<CreateShimsOutput>> { | ||
let mut output = CreateShimsOutput::default(); | ||
let schema = get_schema()?; | ||
let platform = get_platform(&schema, &input.env)?; | ||
let bin_path = get_bin_path(platform, &input.env); | ||
|
||
output.no_primary_global = !schema.shim.global; | ||
|
||
if schema.shim.local { | ||
output.local_shims.insert( | ||
input.env.id, | ||
if let Some(parent_bin) = schema.shim.parent_bin { | ||
ShimConfig::local_with_parent(bin_path, parent_bin) | ||
} else { | ||
ShimConfig::local(bin_path) | ||
}, | ||
); | ||
} | ||
|
||
Ok(Json(output)) | ||
} |