Add nu_plugin_once base and cross-rs config
This commit is contained in:
parent
07e7c8c81f
commit
bb85b2054c
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -3503,6 +3503,16 @@ dependencies = [
|
|||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_once"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"nu-cmd-lang",
|
||||
"nu-plugin",
|
||||
"nu-plugin-test-support",
|
||||
"nu-protocol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu_plugin_polars"
|
||||
version = "0.96.2"
|
||||
|
|
|
@ -51,6 +51,7 @@ members = [
|
|||
"crates/nu_plugin_query",
|
||||
"crates/nu_plugin_custom_values",
|
||||
"crates/nu_plugin_formats",
|
||||
"crates/nu_plugin_once",
|
||||
"crates/nu_plugin_polars",
|
||||
"crates/nu_plugin_stress_internals",
|
||||
"crates/nu-std",
|
||||
|
|
18
Cross.toml
18
Cross.toml
|
@ -1,18 +1,10 @@
|
|||
# Configuration for cross-rs: https://github.com/cross-rs/cross
|
||||
# Run cross-rs like this:
|
||||
# cross build --target aarch64-unknown-linux-gnu --release
|
||||
# or
|
||||
# cross build --target aarch64-unknown-linux-musl --release --features=static-link-openssl
|
||||
|
||||
[target.aarch64-unknown-linux-gnu]
|
||||
pre-build = [
|
||||
"dpkg --add-architecture $CROSS_DEB_ARCH",
|
||||
"apt-get update && apt-get install --assume-yes libssl-dev:$CROSS_DEB_ARCH clang"
|
||||
]
|
||||
# cross build --target i686-unknown-linux-musl --release --features=static-link-openssl
|
||||
|
||||
# NOTE: for musl you will need to build with --features=static-link-openssl
|
||||
[target.aarch64-unknown-linux-musl]
|
||||
[target.i686-unknown-linux-musl]
|
||||
pre-build = [
|
||||
"dpkg --add-architecture $CROSS_DEB_ARCH",
|
||||
"apt-get update && apt-get install --assume-yes clang"
|
||||
]
|
||||
"dpkg --add-architecture i386",
|
||||
"apt-get update && apt-get install --assume-yes libssl-dev:i386 clang"
|
||||
]
|
23
crates/nu_plugin_once/Cargo.toml
Normal file
23
crates/nu_plugin_once/Cargo.toml
Normal file
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
authors = ["Chris Daßler"]
|
||||
description = "A object oriented shell plugin for Nushell"
|
||||
repository = "https://github.com/nushell/nushell/tree/main/crates/nu_plugin_example"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
name = "nu_plugin_once"
|
||||
version = "0.1.0"
|
||||
|
||||
[[bin]]
|
||||
name = "nu_plugin_once"
|
||||
bench = false
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
nu-plugin = { path = "../nu-plugin", version = "0.96.1" }
|
||||
nu-protocol = { path = "../nu-protocol", version = "0.96.1", features = ["plugin"] }
|
||||
|
||||
[dev-dependencies]
|
||||
nu-plugin-test-support = { path = "../nu-plugin-test-support", version = "0.96.1" }
|
||||
nu-cmd-lang = { path = "../nu-cmd-lang", version = "0.96.1" }
|
36
crates/nu_plugin_once/README.md
Normal file
36
crates/nu_plugin_once/README.md
Normal file
|
@ -0,0 +1,36 @@
|
|||
# Plugin Once
|
||||
|
||||
Crate with a simple example of the Plugin trait that needs to be implemented
|
||||
in order to create a binary that can be registered into nushell declaration list
|
||||
|
||||
## `once config`
|
||||
|
||||
This subcommand demonstrates sending configuration from the nushell `$env.config` to a plugin.
|
||||
|
||||
To make use of the plugin after building `nushell` run:
|
||||
|
||||
```nushell
|
||||
plugin add target/debug/nu_plugin_once
|
||||
# or then either restart your current nushell session or run:
|
||||
plugin use target/debug/nu_plugin_once
|
||||
```
|
||||
|
||||
The configuration for the plugin lives in `$env.config.plugins.once`:
|
||||
|
||||
```nushell
|
||||
$env.config = {
|
||||
plugins: {
|
||||
once: [
|
||||
some
|
||||
values
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
To list plugin values run:
|
||||
|
||||
```nushell
|
||||
once config
|
||||
```
|
||||
|
47
crates/nu_plugin_once/src/commands/main.rs
Normal file
47
crates/nu_plugin_once/src/commands/main.rs
Normal file
|
@ -0,0 +1,47 @@
|
|||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||
use nu_protocol::{Category, LabeledError, Signature, Value};
|
||||
|
||||
use crate::OncePlugin;
|
||||
|
||||
pub struct Main;
|
||||
|
||||
impl SimplePluginCommand for Main {
|
||||
type Plugin = OncePlugin;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"once"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"once commands for Nushell plugins"
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
r#"
|
||||
The `once` plugin demonstrates usage of the Nushell plugin API.
|
||||
|
||||
Several commands provided to test and demonstrate different capabilities of
|
||||
plugins exposed through the API. None of these commands are intended to be
|
||||
particularly useful.
|
||||
"#
|
||||
.trim()
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name()).category(Category::Experimental)
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec!["once"]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_plugin: &Self::Plugin,
|
||||
engine: &EngineInterface,
|
||||
call: &EvaluatedCall,
|
||||
_input: &Value,
|
||||
) -> Result<Value, LabeledError> {
|
||||
Ok(Value::string(engine.get_help()?, call.head))
|
||||
}
|
||||
}
|
10
crates/nu_plugin_once/src/commands/mod.rs
Normal file
10
crates/nu_plugin_once/src/commands/mod.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
// `once` command - just suggests to call --help
|
||||
mod main;
|
||||
|
||||
pub use main::Main;
|
||||
|
||||
mod scenario;
|
||||
pub use scenario::Scenario;
|
||||
|
||||
mod scenario_deploy;
|
||||
pub use scenario_deploy::ScenarioDeploy;
|
76
crates/nu_plugin_once/src/commands/scenario.rs
Normal file
76
crates/nu_plugin_once/src/commands/scenario.rs
Normal file
|
@ -0,0 +1,76 @@
|
|||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||
use nu_protocol::{record, Category, Example, LabeledError, Signature, Type, Value};
|
||||
|
||||
use crate::OncePlugin;
|
||||
|
||||
pub struct Scenario;
|
||||
|
||||
impl SimplePluginCommand for Scenario {
|
||||
type Plugin = OncePlugin;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"once scenario"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Manage once scenarios on local or remote servers."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
"Extra usage for once scenario"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
Signature::build(self.name())
|
||||
.category(Category::Experimental)
|
||||
.input_output_type(Type::Nothing, Type::table())
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec!["once", "scenario"]
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
example: "once scenario",
|
||||
description: "List all scenarios",
|
||||
result: Some(Value::test_list(vec![Value::test_record(record! {
|
||||
"name" => Value::test_string("test"),
|
||||
"filename" => Value::test_string("test.scenario.env")
|
||||
})])),
|
||||
}]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
_plugin: &OncePlugin,
|
||||
_engine: &EngineInterface,
|
||||
call: &EvaluatedCall,
|
||||
_input: &Value,
|
||||
) -> Result<Value, LabeledError> {
|
||||
let head = call.head;
|
||||
let list = vec![
|
||||
Value::record(
|
||||
record! {
|
||||
"name" => Value::test_string("dev"),
|
||||
"filename" => Value::test_string("dev.scenario.env")
|
||||
},
|
||||
head,
|
||||
),
|
||||
Value::record(
|
||||
record! {
|
||||
"name" => Value::test_string("certbot"),
|
||||
"filename" => Value::test_string("certbot.scenario.env")
|
||||
},
|
||||
head,
|
||||
),
|
||||
];
|
||||
Ok(Value::list(list, head))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
||||
use nu_plugin_test_support::PluginTest;
|
||||
PluginTest::new("once", OncePlugin.into())?.test_command_examples(&Scenario)
|
||||
}
|
65
crates/nu_plugin_once/src/commands/scenario_deploy.rs
Normal file
65
crates/nu_plugin_once/src/commands/scenario_deploy.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use nu_plugin::{EngineInterface, EvaluatedCall, SimplePluginCommand};
|
||||
use nu_protocol::{Category, Example, LabeledError, Signature, SyntaxShape, Value};
|
||||
|
||||
use crate::OncePlugin;
|
||||
|
||||
pub struct ScenarioDeploy;
|
||||
|
||||
impl SimplePluginCommand for ScenarioDeploy {
|
||||
type Plugin = OncePlugin;
|
||||
|
||||
fn name(&self) -> &str {
|
||||
"once scenario.deploy"
|
||||
}
|
||||
|
||||
fn usage(&self) -> &str {
|
||||
"Deploy once scenarios on local or remote servers."
|
||||
}
|
||||
|
||||
fn extra_usage(&self) -> &str {
|
||||
"Extra usage for once scenario.deploy"
|
||||
}
|
||||
|
||||
fn signature(&self) -> Signature {
|
||||
// The signature defines the usage of the command inside Nu, and also automatically
|
||||
// generates its help page.
|
||||
Signature::build(self.name())
|
||||
.required("a", SyntaxShape::Int, "required integer value")
|
||||
.required("b", SyntaxShape::String, "required string value")
|
||||
.switch("flag", "a flag for the signature", Some('f'))
|
||||
.optional("opt", SyntaxShape::Int, "Optional number")
|
||||
.named("named", SyntaxShape::String, "named string", Some('n'))
|
||||
.rest("rest", SyntaxShape::String, "rest value string")
|
||||
.category(Category::Experimental)
|
||||
}
|
||||
|
||||
fn search_terms(&self) -> Vec<&str> {
|
||||
vec!["once", "scenario", "deploy"]
|
||||
}
|
||||
|
||||
fn examples(&self) -> Vec<Example> {
|
||||
vec![Example {
|
||||
example: "once scenario.deploy 3 bb",
|
||||
description: "running scenario.deploy with an int value and string value",
|
||||
result: None,
|
||||
}]
|
||||
}
|
||||
|
||||
fn run(
|
||||
&self,
|
||||
plugin: &OncePlugin,
|
||||
_engine: &EngineInterface,
|
||||
call: &EvaluatedCall,
|
||||
input: &Value,
|
||||
) -> Result<Value, LabeledError> {
|
||||
plugin.print_values(1, call, input)?;
|
||||
|
||||
Ok(Value::nothing(call.head))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_examples() -> Result<(), nu_protocol::ShellError> {
|
||||
use nu_plugin_test_support::PluginTest;
|
||||
PluginTest::new("once", OncePlugin.into())?.test_command_examples(&ScenarioDeploy)
|
||||
}
|
25
crates/nu_plugin_once/src/lib.rs
Normal file
25
crates/nu_plugin_once/src/lib.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use nu_plugin::{Plugin, PluginCommand};
|
||||
|
||||
mod commands;
|
||||
mod once;
|
||||
|
||||
pub use commands::*;
|
||||
pub use once::OncePlugin;
|
||||
|
||||
impl Plugin for OncePlugin {
|
||||
fn version(&self) -> String {
|
||||
env!("CARGO_PKG_VERSION").into()
|
||||
}
|
||||
|
||||
fn commands(&self) -> Vec<Box<dyn PluginCommand<Plugin = Self>>> {
|
||||
// This is a list of all of the commands you would like Nu to register when your plugin is
|
||||
// loaded.
|
||||
//
|
||||
// If it doesn't appear on this list, it won't be added.
|
||||
vec![
|
||||
Box::new(Main),
|
||||
Box::new(Scenario),
|
||||
Box::new(ScenarioDeploy)
|
||||
]
|
||||
}
|
||||
}
|
30
crates/nu_plugin_once/src/main.rs
Normal file
30
crates/nu_plugin_once/src/main.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
use nu_plugin::{serve_plugin, MsgPackSerializer};
|
||||
use nu_plugin_once::OncePlugin;
|
||||
|
||||
fn main() {
|
||||
// When defining your plugin, you can select the Serializer that could be
|
||||
// used to encode and decode the messages. The available options are
|
||||
// MsgPackSerializer and JsonSerializer. Both are defined in the serializer
|
||||
// folder in nu-plugin.
|
||||
serve_plugin(&OncePlugin {}, MsgPackSerializer {})
|
||||
|
||||
// Note
|
||||
// When creating plugins in other languages one needs to consider how a plugin
|
||||
// is added and used in nushell.
|
||||
// The steps are:
|
||||
// - The plugin is register. In this stage nushell calls the binary file of
|
||||
// the plugin sending information using the encoded PluginCall::PluginSignature object.
|
||||
// Use this encoded data in your plugin to design the logic that will return
|
||||
// the encoded signatures.
|
||||
// Nushell is expecting and encoded PluginResponse::PluginSignature with all the
|
||||
// plugin signatures
|
||||
// - When calling the plugin, nushell sends to the binary file the encoded
|
||||
// PluginCall::CallInfo which has all the call information, such as the
|
||||
// values of the arguments, the name of the signature called and the input
|
||||
// from the pipeline.
|
||||
// Use this data to design your plugin login and to create the value that
|
||||
// will be sent to nushell
|
||||
// Nushell expects an encoded PluginResponse::Value from the plugin
|
||||
// - If an error needs to be sent back to nushell, one can encode PluginResponse::Error.
|
||||
// This is a labeled error that nushell can format for pretty printing
|
||||
}
|
53
crates/nu_plugin_once/src/once.rs
Normal file
53
crates/nu_plugin_once/src/once.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
use nu_plugin::EvaluatedCall;
|
||||
use nu_protocol::{LabeledError, Value};
|
||||
|
||||
pub struct OncePlugin;
|
||||
|
||||
impl OncePlugin {
|
||||
pub fn print_values(
|
||||
&self,
|
||||
index: u32,
|
||||
call: &EvaluatedCall,
|
||||
input: &Value,
|
||||
) -> Result<(), LabeledError> {
|
||||
// Note. When debugging your plugin, you may want to print something to the console
|
||||
// Use the eprintln macro to print your messages. Trying to print to stdout will
|
||||
// cause a decoding error for your message
|
||||
eprintln!("Calling test {index} signature");
|
||||
eprintln!("value received {input:?}");
|
||||
|
||||
// To extract the arguments from the Call object you can use the functions req, has_flag,
|
||||
// opt, rest, and get_flag
|
||||
//
|
||||
// Note that plugin calls only accept simple arguments, this means that you can
|
||||
// pass to the plug in Int and String. This should be improved when the plugin has
|
||||
// the ability to call back to NuShell to extract more information
|
||||
// Keep this in mind when designing your plugin signatures
|
||||
let a: i64 = call.req(0)?;
|
||||
let b: String = call.req(1)?;
|
||||
let flag = call.has_flag("flag")?;
|
||||
let opt: Option<i64> = call.opt(2)?;
|
||||
let named: Option<String> = call.get_flag("named")?;
|
||||
let rest: Vec<String> = call.rest(3)?;
|
||||
|
||||
eprintln!("Required values");
|
||||
eprintln!("a: {a:}");
|
||||
eprintln!("b: {b:}");
|
||||
eprintln!("flag: {flag:}");
|
||||
eprintln!("rest: {rest:?}");
|
||||
|
||||
if let Some(v) = opt {
|
||||
eprintln!("Found optional value opt: {v:}")
|
||||
} else {
|
||||
eprintln!("No optional value found")
|
||||
}
|
||||
|
||||
if let Some(v) = named {
|
||||
eprintln!("Named value: {v:?}")
|
||||
} else {
|
||||
eprintln!("No named value found")
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user