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",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu_plugin_once"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"nu-cmd-lang",
|
||||||
|
"nu-plugin",
|
||||||
|
"nu-plugin-test-support",
|
||||||
|
"nu-protocol",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu_plugin_polars"
|
name = "nu_plugin_polars"
|
||||||
version = "0.96.2"
|
version = "0.96.2"
|
||||||
|
|
|
@ -51,6 +51,7 @@ members = [
|
||||||
"crates/nu_plugin_query",
|
"crates/nu_plugin_query",
|
||||||
"crates/nu_plugin_custom_values",
|
"crates/nu_plugin_custom_values",
|
||||||
"crates/nu_plugin_formats",
|
"crates/nu_plugin_formats",
|
||||||
|
"crates/nu_plugin_once",
|
||||||
"crates/nu_plugin_polars",
|
"crates/nu_plugin_polars",
|
||||||
"crates/nu_plugin_stress_internals",
|
"crates/nu_plugin_stress_internals",
|
||||||
"crates/nu-std",
|
"crates/nu-std",
|
||||||
|
|
16
Cross.toml
16
Cross.toml
|
@ -1,18 +1,10 @@
|
||||||
# Configuration for cross-rs: https://github.com/cross-rs/cross
|
# Configuration for cross-rs: https://github.com/cross-rs/cross
|
||||||
# Run cross-rs like this:
|
# Run cross-rs like this:
|
||||||
# cross build --target aarch64-unknown-linux-gnu --release
|
# cross build --target i686-unknown-linux-musl --release --features=static-link-openssl
|
||||||
# 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"
|
|
||||||
]
|
|
||||||
|
|
||||||
# NOTE: for musl you will need to build with --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 = [
|
pre-build = [
|
||||||
"dpkg --add-architecture $CROSS_DEB_ARCH",
|
"dpkg --add-architecture i386",
|
||||||
"apt-get update && apt-get install --assume-yes clang"
|
"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