5.2 KiB
5.2 KiB
Plugin Development
Developing Nushell plugins for performance-critical operations in the Provisioning platform.
Plugin Overview
Nushell plugins provide 10-50x performance improvement over HTTP APIs through native Rust implementations.
Available Plugins
| Plugin | Purpose | Performance Gain | Language |
|---|---|---|---|
| nu_plugin_auth | Authentication and OS keyring | 5x faster | Rust |
| nu_plugin_kms | KMS encryption operations | 10x faster | Rust |
| nu_plugin_orchestrator | Orchestrator queries | 30x faster | Rust |
Plugin Architecture
Plugins communicate with Nushell via MessagePack protocol:
Nushell ←→ MessagePack ←→ Plugin Process
↓ ↓
Script Native Rust
Creating a Plugin
Plugin Template
Generate plugin scaffold:
# Create new plugin
cargo new --lib nu_plugin_myfeature
cd nu_plugin_myfeature
Add dependencies to Cargo.toml:
[package]
name = "nu_plugin_myfeature"
version = "0.1.0"
edition = "2021"
[dependencies]
nu-plugin = "0.109.0"
nu-protocol = "0.109.0"
serde = {version = "1.0", features = ["derive"]}
Plugin Implementation
Implement plugin interface:
// src/lib.rs
use nu_plugin::{EvaluatedCall, LabeledError, Plugin};
use nu_protocol::{Category, PluginSignature, SyntaxShape, Type, Value};
pub struct MyFeaturePlugin;
impl Plugin for MyFeaturePlugin {
fn signature(&self) -> Vec<PluginSignature> {
vec![
PluginSignature::build("my-feature")
.usage("Perform my feature operation")
.required("input", SyntaxShape::String, "input value")
.input_output_type(Type::String, Type::String)
.category(Category::Custom("provisioning".into())),
]
}
fn run(
&mut self,
name: &str,
call: &EvaluatedCall,
input: &Value,
) -> Result<Value, LabeledError> {
match name {
"my-feature" => self.my_feature(call, input),
_ => Err(LabeledError {
label: "Unknown command".into(),
msg: format!("Unknown command: {}", name),
span: None,
}),
}
}
}
impl MyFeaturePlugin {
fn my_feature(&self, call: &EvaluatedCall, _input: &Value) -> Result<Value, LabeledError> {
let input: String = call.req(0)?;
// Perform operation
let result = perform_operation(&input);
Ok(Value::string(result, call.head))
}
}
fn perform_operation(input: &str) -> String {
// Your implementation here
format!("Processed: {}", input)
}
// Plugin entry point
fn main() {
nu_plugin::serve_plugin(&mut MyFeaturePlugin, nu_plugin::MsgPackSerializer {})
}
Building Plugin
# Build release version
cargo build --release
# Install plugin
nu -c 'plugin add target/release/nu_plugin_myfeature'
nu -c 'plugin use myfeature'
# Test plugin
nu -c 'my-feature "test input"'
Plugin Performance Optimization
Benchmarking
use std::time::Instant;
pub fn benchmark_operation() {
let start = Instant::now();
// Operation to benchmark
perform_expensive_operation();
let duration = start.elapsed();
eprintln!("Operation took: {:?}", duration);
}
Caching
Implement caching for expensive operations:
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
pub struct CachedPlugin {
cache: Arc<Mutex<HashMap<String, String>>>,
}
impl CachedPlugin {
fn get_or_compute(&self, key: &str) -> String {
let mut cache = self.cache.lock().unwrap();
if let Some(value) = cache.get(key) {
return value.clone();
}
let value = expensive_computation(key);
cache.insert(key.to_string(), value.clone());
value
}
}
Testing Plugins
Unit Tests
#[cfg(test)]
mod tests {
use super::*;
use nu_protocol::{Span, Value};
#[test]
fn test_my_feature() {
let plugin = MyFeaturePlugin;
let input = Value::string("test", Span::test_data());
let result = plugin.my_feature(&mock_call(), &input).unwrap();
assert_eq!(result.as_string().unwrap(), "Processed: test");
}
fn mock_call() -> EvaluatedCall {
// Mock EvaluatedCall for testing
todo!()
}
}
Integration Tests
# tests/test_plugin.nu
use std assert
def test_plugin_functionality [] {
let result = my-feature "test input"
assert equal $result "Processed: test input"
}
def main [] {
test_plugin_functionality
print "Plugin tests passed"
}
Plugin Best Practices
- Keep plugin logic focused and single-purpose
- Minimize dependencies to reduce binary size
- Use async operations for I/O-bound tasks
- Implement proper error handling
- Document all plugin commands
- Version plugins with semantic versioning
- Provide fallback to HTTP API if plugin unavailable
- Cache expensive computations
- Profile and benchmark performance improvements
Related Documentation
- Build System - Building Rust plugins
- Extension Development - Extension basics
- Testing - Testing strategies