Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion .cursor/rules/conventional_commits.mdc
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
alwaysApply: false
description: how to write commit and PR titles
---

## Conventional Commits (REQUIRED)

All commit messages and PR titles MUST follow conventional commit format:
Expand Down Expand Up @@ -29,4 +34,35 @@ chore(deps): update Rust dependencies
```

### Common Scopes
`registry`, `aqua`, `cli`, `config`, `backend`, `tool`, `env`, `task`, `api`, `ui`, `core`, `deps`, `schema`, `doctor`, `shim`, `security`
`registry`, `aqua`, `cli`, `config`, `backend`, `tool`, `env`, `task`, `api`, `ui`, `core`, `deps`, `schema`, `doctor`, `shim`, `security`## Conventional Commits (REQUIRED)

All commit messages and PR titles MUST follow conventional commit format:

### Format
```
<type>(<scope>): <description>
```

### Types
- `feat:` - New features
- `fix:` - Bug fixes
- `refactor:` - Code refactoring
- `doc:` - Documentation
- `style:` - Code style/formatting
- `perf:` - Performance improvements
- `test:` - Testing changes
- `chore:` - Maintenance tasks
- `chore(deps):` - Dependency updates

### Examples
```
feat(cli): add new command for tool management
fix(config): resolve parsing issue with nested tables
refactor(backend): simplify plugin loading logic
doc(api): update configuration examples
test(e2e): add tests for tool installation
chore(deps): update Rust dependencies
```

### Common Scopes
`registry`, `aqua`, `cli`, `config`, `backend`, `tool`, `env`, `task`, `api`, `ui`, `core`, `deps`, `schema`, `doctor`, `shim`, `security`
16 changes: 16 additions & 0 deletions .cursor/rules/testing.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
description: how to test the mise codebase
alwaysApply: false
---

Testing and linting commands should be run via `mise run`.

- `mise run e2e [test_filename]` executes an e2e test
- `mise run test:unit` executes the unit tests
- `mise run lint` runs the linting commands
- `mise run lint-fix` runs the linting commands and fixes the issues
- `mise --cd crates/vfox run test` executes the tests for the vfox crate
- `mise --cd crates/vfox run lint` runs the linting commands for the vfox crate
- `mise --cd crates/vfox run lint-fix` runs the linting commands and fixes the issues for the vfox crate

other tasks can be found by running `mise task ls`
4 changes: 2 additions & 2 deletions crates/vfox/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ edition = "2021"
license = "MIT"
description = "Interface to vfox plugins"
documentation = "https://docs.rs/vfox"
homepage = "https://github.com/jdx/vfox.rs"
repository = "https://github.com/jdx/vfox.rs"
homepage = "https://github.com/jdx/mise"
repository = "https://github.com/jdx/mise"
include = ["src", "lua", "Cargo.toml", "Cargo.lock", "README.md", "LICENSE"]

[lib]
Expand Down
46 changes: 46 additions & 0 deletions crates/vfox/src/hooks/backend_exec_env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use mlua::{FromLua, IntoLua, Lua, Value, prelude::LuaError};
use std::path::PathBuf;

use crate::hooks::env_keys::EnvKey;

#[derive(Debug, Clone)]
pub struct BackendExecEnvContext {
pub args: Vec<String>,
pub tool: String,
pub version: String,
pub install_path: PathBuf,
}

#[derive(Debug, Clone)]
pub struct BackendExecEnvResponse {
pub env_vars: Vec<EnvKey>,
}

impl IntoLua for BackendExecEnvContext {
fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<Value> {
let table = lua.create_table()?;
table.set("args", self.args)?;
table.set("tool", self.tool)?;
table.set("version", self.version)?;
table.set(
"install_path",
self.install_path.to_string_lossy().to_string(),
)?;
Ok(Value::Table(table))
}
}

impl FromLua for BackendExecEnvResponse {
fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {
match value {
Value::Table(table) => Ok(BackendExecEnvResponse {
env_vars: table.get::<Vec<crate::hooks::env_keys::EnvKey>>("env_vars")?,
}),
_ => Err(LuaError::FromLuaConversionError {
from: value.type_name(),
to: "BackendExecEnvResponse".to_string(),
message: Some("Expected table".to_string()),
}),
}
}
}
41 changes: 41 additions & 0 deletions crates/vfox/src/hooks/backend_install.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use mlua::{FromLua, IntoLua, Lua, Value, prelude::LuaError};
use std::path::PathBuf;

#[derive(Debug, Clone)]
pub struct BackendInstallContext {
pub args: Vec<String>,
pub tool: String,
pub version: String,
pub install_path: PathBuf,
}

#[derive(Debug, Clone)]
pub struct BackendInstallResponse {
}

impl IntoLua for BackendInstallContext {
fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<Value> {
let table = lua.create_table()?;
table.set("args", self.args)?;
table.set("tool", self.tool)?;
table.set("version", self.version)?;
table.set(
"install_path",
self.install_path.to_string_lossy().to_string(),
)?;
Ok(Value::Table(table))
}
}

impl FromLua for BackendInstallResponse {
fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {
match value {
Value::Table(_) => Ok(BackendInstallResponse {}),
_ => Err(LuaError::FromLuaConversionError {
from: value.type_name(),
to: "BackendInstallResponse".to_string(),
message: Some("Expected table".to_string()),
}),
}
}
}
36 changes: 36 additions & 0 deletions crates/vfox/src/hooks/backend_list_versions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use mlua::{FromLua, IntoLua, Lua, Value, prelude::LuaError};

#[derive(Debug, Clone)]
pub struct BackendListVersionsContext {
pub args: Vec<String>,
pub tool: String,
}

#[derive(Debug, Clone)]
pub struct BackendListVersionsResponse {
pub versions: Vec<String>,
}

impl IntoLua for BackendListVersionsContext {
fn into_lua(self, lua: &mlua::Lua) -> mlua::Result<Value> {
let table = lua.create_table()?;
table.set("args", self.args)?;
table.set("tool", self.tool)?;
Ok(Value::Table(table))
}
}

impl FromLua for BackendListVersionsResponse {
fn from_lua(value: Value, _: &Lua) -> std::result::Result<Self, LuaError> {
match value {
Value::Table(table) => Ok(BackendListVersionsResponse {
versions: table.get::<Vec<String>>("versions")?,
}),
_ => Err(LuaError::FromLuaConversionError {
from: value.type_name(),
to: "BackendListVersionsResponse".to_string(),
message: Some("Expected table".to_string()),
}),
}
}
}
2 changes: 1 addition & 1 deletion crates/vfox/src/hooks/env_keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::error::Result;
use crate::sdk_info::SdkInfo;
use crate::Plugin;

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct EnvKey {
pub key: String,
pub value: String,
Expand Down
3 changes: 3 additions & 0 deletions crates/vfox/src/hooks/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
pub mod available;
pub mod backend_exec_env;
pub mod backend_install;
pub mod backend_list_versions;
pub mod env_keys;
pub mod mise_env;
pub mod mise_path;
Expand Down
7 changes: 7 additions & 0 deletions crates/vfox/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ pub use error::VfoxError;
pub use plugin::Plugin;
pub use vfox::Vfox;

// Backend hooks
pub mod backend_hooks {
pub use crate::hooks::backend_exec_env::{BackendExecEnvContext, BackendExecEnvResponse};
pub use crate::hooks::backend_install::{BackendInstallContext, BackendInstallResponse};
pub use crate::hooks::backend_list_versions::{BackendListVersionsContext, BackendListVersionsResponse};
}

mod config;
mod context;
mod error;
Expand Down
52 changes: 52 additions & 0 deletions crates/vfox/src/lua_mod/cmd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use mlua::prelude::*;
use mlua::Table;

pub fn mod_cmd(lua: &Lua) -> LuaResult<()> {
let package: Table = lua.globals().get("package")?;
let loaded: Table = package.get("loaded")?;
let cmd = lua.create_table_from(vec![("exec", lua.create_function(exec)?)])?;
loaded.set("cmd", cmd.clone())?;
loaded.set("vfox.cmd", cmd)?;
Ok(())
}

fn exec(_lua: &Lua, (command,): (String,)) -> LuaResult<String> {
use std::process::Command;

let output = Command::new("sh")
.arg("-c")
.arg(&command)
.output()
.map_err(|e| mlua::Error::RuntimeError(format!("Failed to execute command: {}", e)))?;

let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);

if output.status.success() {
Ok(stdout.to_string())
} else {
Err(mlua::Error::RuntimeError(format!(
"Command failed with status {}: {}",
output.status,
stderr
)))
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_cmd() {
let lua = Lua::new();
mod_cmd(&lua).unwrap();
lua.load(mlua::chunk! {
local cmd = require("cmd")
local result = cmd.exec("echo hello world")
assert(result == "hello world\n")
})
.exec()
.unwrap();
}
}
2 changes: 2 additions & 0 deletions crates/vfox/src/lua_mod/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod archiver;
mod cmd;
mod env;
mod file;
mod hooks;
Expand All @@ -8,6 +9,7 @@ mod json;
mod strings;

pub use archiver::mod_archiver as archiver;
pub use cmd::mod_cmd as cmd;
pub use env::mod_env as env;
pub use file::mod_file as file;
pub use hooks::mod_hooks as hooks;
Expand Down
60 changes: 60 additions & 0 deletions crates/vfox/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,65 @@ impl Plugin {
Ok(result)
}

// Backend plugin methods
pub async fn backend_list_versions(
&self,
ctx: crate::hooks::backend_list_versions::BackendListVersionsContext,
) -> Result<crate::hooks::backend_list_versions::BackendListVersionsResponse> {
debug!("[vfox:{}] backend_list_versions", &self.name);
self.load()?;
// Set the context as a global variable with a unique name
self.set_global("BACKEND_CTX", ctx)?;
let response = self
.eval_async(chunk! {
if PLUGIN.BackendListVersions then
return PLUGIN:BackendListVersions(BACKEND_CTX)
else
return {versions = {}}
end
})
.await?;
Ok(response)
}

pub async fn backend_install(
&self,
ctx: crate::hooks::backend_install::BackendInstallContext,
) -> Result<crate::hooks::backend_install::BackendInstallResponse> {
debug!("[vfox:{}] backend_install", &self.name);
self.load()?;
self.set_global("BACKEND_CTX", ctx)?;
let response = self
.eval_async(chunk! {
if PLUGIN.BackendInstall then
return PLUGIN:BackendInstall(BACKEND_CTX)
else
return {success = false, message = "Backend install not implemented"}
end
})
.await?;
Ok(response)
}

pub async fn backend_exec_env(
&self,
ctx: crate::hooks::backend_exec_env::BackendExecEnvContext,
) -> Result<crate::hooks::backend_exec_env::BackendExecEnvResponse> {
debug!("[vfox:{}] backend_exec_env", &self.name);
self.load()?;
self.set_global("BACKEND_CTX", ctx)?;
let response = self
.eval_async(chunk! {
if PLUGIN.BackendExecEnv then
return PLUGIN:BackendExecEnv(BACKEND_CTX)
else
return {env_vars = {}}
end
})
.await?;
Ok(response)
}

fn load(&self) -> Result<&Metadata> {
self.metadata.get_or_try_init(|| {
debug!("Getting metadata for {self}");
Expand All @@ -116,6 +175,7 @@ impl Plugin {
)?;

lua_mod::archiver(&self.lua)?;
lua_mod::cmd(&self.lua)?;
lua_mod::file(&self.lua)?;
lua_mod::html(&self.lua)?;
lua_mod::http(&self.lua)?;
Expand Down
Loading
Loading