summaryrefslogtreecommitdiffstats
path: root/tedge
diff options
context:
space:
mode:
authorMatthias Beyer <matthias.beyer@ifm.com>2022-07-03 11:28:15 +0200
committerMatthias Beyer <matthias.beyer@ifm.com>2022-07-03 11:28:15 +0200
commit9fe671af827a99f2ee5bd59ba21e0824fc935b24 (patch)
treecc2dd2482ac1093b43855726a739557092ac35c9 /tedge
parent5ed9a35bde99763a88c40758952d23ce5a311100 (diff)
parent36553ba01a959d012e248bf27527a0041da860e9 (diff)
Merge branch 'feature/add_tedge_api/cli-as-lib-and-bin' into feature/add_tedge_api_impl
Diffstat (limited to 'tedge')
-rw-r--r--tedge/Cargo.toml8
-rw-r--r--tedge/src/cli.rs14
-rw-r--r--tedge/src/lib.rs103
-rw-r--r--tedge/src/logging.rs2
-rw-r--r--tedge/src/main.rs302
-rw-r--r--tedge/src/registry.rs78
6 files changed, 281 insertions, 226 deletions
diff --git a/tedge/Cargo.toml b/tedge/Cargo.toml
index 533526af..9e81f7cd 100644
--- a/tedge/Cargo.toml
+++ b/tedge/Cargo.toml
@@ -5,6 +5,14 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+[lib]
+name = "tedge_cli"
+path = "src/lib.rs"
+
+[[bin]]
+name = "tedge-cli"
+path = "src/main.rs"
+
[dependencies]
clap = { version = "3", features = ["derive", "cargo", "suggestions"] }
toml = "0.5.8"
diff --git a/tedge/src/cli.rs b/tedge/src/cli.rs
index 821b1cd9..e01bc313 100644
--- a/tedge/src/cli.rs
+++ b/tedge/src/cli.rs
@@ -6,7 +6,7 @@ use std::path::PathBuf;
version = clap::crate_version!(),
about = clap::crate_description!()
)]
-pub(crate) struct Cli {
+pub struct Cli {
/// Enable logging
///
/// If not specified, only WARN and ERROR messages will be logged.
@@ -14,26 +14,26 @@ pub(crate) struct Cli {
///
/// This setting overwrites the logging specification set via the RUST_LOG env variable.
#[clap(short, long, arg_enum)]
- pub(crate) logging: Option<LoggingSpec>,
+ pub logging: Option<LoggingSpec>,
/// Enable chrome compatible tracing output
///
/// If set, chrome-compatible tracing output will be written to the file specified.
#[clap(long)]
- pub(crate) chrome_logging: Option<PathBuf>,
+ pub chrome_logging: Option<PathBuf>,
/// Enable tracy compatible tracing output
///
/// If set, "tracy" compatible tracing output will be produced
#[clap(long)]
- pub(crate) tracy_logging: bool,
+ pub tracy_logging: bool,
#[clap(subcommand)]
- pub(crate) command: CliCommand,
+ pub command: CliCommand,
}
#[derive(Copy, Clone, Debug, clap::ArgEnum)]
-pub(crate) enum LoggingSpec {
+pub enum LoggingSpec {
False,
Off,
Trace,
@@ -44,7 +44,7 @@ pub(crate) enum LoggingSpec {
}
#[derive(Debug, clap::Subcommand)]
-pub(crate) enum CliCommand {
+pub enum CliCommand {
/// Run thin-edge with the passed configuration
#[clap(name = "run")]
Run { config: PathBuf },
diff --git a/tedge/src/lib.rs b/tedge/src/lib.rs
new file mode 100644
index 00000000..69cc0b3e
--- /dev/null
+++ b/tedge/src/lib.rs
@@ -0,0 +1,103 @@
+#![doc = include_str!("../README.md")]
+
+use miette::IntoDiagnostic;
+use tracing::debug;
+use tracing::error;
+use tracing::info;
+
+use tedge_core::TedgeApplication;
+use tedge_core::TedgeApplicationCancelSender;
+
+pub mod cli;
+pub mod config;
+pub mod logging;
+mod registry;
+
+pub use crate::registry::Registry;
+
+pub async fn run_app(args: crate::cli::Cli, registry: Registry) -> miette::Result<()> {
+ match args.command {
+ cli::CliCommand::Run { config } => {
+ let (cancel_sender, application) =
+ registry.app_builder.with_config_from_path(config).await?;
+ info!("Application built");
+
+ debug!("Verifying the configuration");
+ application.verify_configurations().await?;
+
+ debug!("Going to run the application");
+ run(cancel_sender, application).await
+ }
+ cli::CliCommand::ValidateConfig { config } => {
+ let (_, application) = registry.app_builder.with_config_from_path(config).await?;
+ info!("Application built");
+
+ debug!("Only going to validate the configuration");
+ application.verify_configurations().await?;
+ info!("Configuration validated");
+ Ok(())
+ }
+ cli::CliCommand::GetPluginKinds => {
+ use std::io::Write;
+
+ let mut out = std::io::stdout();
+ for name in registry.app_builder.plugin_kind_names() {
+ writeln!(out, "{}", name).into_diagnostic()?;
+ }
+ Ok(())
+ }
+ cli::CliCommand::Doc { plugin_name } => {
+ let mut registry = registry;
+ if let Some(plugin_name) = plugin_name {
+ let printer = registry
+ .doc_printers
+ .remove(&plugin_name)
+ .ok_or_else(|| miette::miette!("Plugin named '{}' not found", plugin_name))?;
+
+ (printer)()?;
+ } else {
+ for printer in registry.doc_printers.into_values() {
+ printer()?;
+ }
+ }
+
+ Ok(())
+ }
+ }
+}
+
+async fn run(
+ cancel_sender: TedgeApplicationCancelSender,
+ application: TedgeApplication,
+) -> miette::Result<()> {
+ info!("Booting app now.");
+ let mut run_fut = Box::pin(application.run());
+
+ let kill_app = |fut| -> miette::Result<()> {
+ error!("Killing application");
+ drop(fut);
+ miette::bail!("Application killed")
+ };
+
+ let res = tokio::select! {
+ res = &mut run_fut => {
+ res
+ },
+
+ _int = tokio::signal::ctrl_c() => {
+ if !cancel_sender.is_cancelled() {
+ info!("Shutting down...");
+ cancel_sender.cancel_app();
+ tokio::select! {
+ res = &mut run_fut => res,
+ _ = tokio::signal::ctrl_c() => return kill_app(run_fut),
+ }
+ } else {
+ return kill_app(run_fut);
+ }
+ },
+ };
+
+ info!("Bye");
+ Ok(res?)
+}
diff --git a/tedge/src/logging.rs b/tedge/src/logging.rs
index 0be2a1fa..3b4fd837 100644
--- a/tedge/src/logging.rs
+++ b/tedge/src/logging.rs
@@ -7,7 +7,7 @@ use tracing_subscriber::Layer;
use crate::cli::LoggingSpec;
-pub(crate) fn setup_logging(
+pub fn setup_logging(
spec: Option<LoggingSpec>,
chrome_logging: Option<&PathBuf>,
tracy_logging: bool,
diff --git a/tedge/src/main.rs b/tedge/src/main.rs
index 6800c45a..58b4ef68 100644
--- a/tedge/src/main.rs
+++ b/tedge/src/main.rs
@@ -1,87 +1,16 @@
-#![doc = include_str!("../README.md")]
-
-use std::collections::HashMap;
-use std::collections::HashSet;
-use std::io::Write;
-
use clap::Parser;
-use miette::IntoDiagnostic;
-
-use pretty::Arena;
-use tedge_api::PluginBuilder;
-use tedge_core::TedgeApplication;
-use tedge_core::TedgeApplicationBuilder;
-use tedge_core::TedgeApplicationCancelSender;
-use tedge_lib::measurement::Measurement;
-use tedge_lib::notification::Notification;
use tracing::debug;
-use tracing::error;
use tracing::info;
-mod cli;
-mod config;
-mod logging;
-
-/// Helper type for registering PluginBuilder instances and doc-printing functions
-struct Registry {
- app_builder: TedgeApplicationBuilder,
- plugin_kinds: HashSet<String>,
- doc_printers: HashMap<String, Box<dyn FnOnce() -> Result<(), miette::Error>>>,
-}
-
-macro_rules! register_plugin {
- ($registry:ident, $cfg:tt, $pluginbuilder:ty, $pbinstance:expr) => {{
- cfg_if::cfg_if! {
- if #[cfg(feature = $cfg)] {
- let kind_name: &'static str = <$pluginbuilder as PluginBuilder<tedge_core::PluginDirectory>>::kind_name();
- info!(%kind_name, "Registering plugin builder");
- let mut registry = $registry;
- if !registry.plugin_kinds.insert(kind_name.to_string()) {
- miette::bail!("Plugin kind '{}' was already registered, cannot register!", kind_name)
- }
-
- let kind_name_str = kind_name.to_string();
- registry.doc_printers.insert(kind_name.to_string(), Box::new(move || {
- let mut stdout = std::io::stdout();
- if let Some(config_desc) = <$pluginbuilder as PluginBuilder<tedge_core::PluginDirectory>>::kind_configuration() {
- let terminal_width = term_size::dimensions().map(|(w, _)| w).unwrap_or(80);
- let arena = Arena::new();
-
- let rendered_doc = crate::config::as_terminal_doc(&config_desc, &arena);
-
- let mut output = String::new();
- rendered_doc.render_fmt(terminal_width, &mut output).into_diagnostic()?;
-
- writeln!(stdout, " ----- Documentation for plugin '{}'", kind_name_str)
- .into_diagnostic()?;
-
- writeln!(stdout, "{}", output).into_diagnostic()?;
- } else {
- let msg = format!(" Documentation for plugin '{}' is unavailable", kind_name);
- writeln!(stdout, "{}", nu_ansi_term::Color::Red.bold().paint(msg))
- .into_diagnostic()?;
- }
- Ok(())
- }));
-
- Registry {
- app_builder: registry.app_builder.with_plugin_builder($pbinstance),
- plugin_kinds: registry.plugin_kinds,
- doc_printers: registry.doc_printers,
- }
- } else {
- tracing::trace!("Not supporting plugins of type {}", std::stringify!($pluginbuilder));
- $registry
- }
- }
- }}
-}
+use tedge_cli::Registry;
+use tedge_lib::measurement::Measurement;
+use tedge_lib::notification::Notification;
#[tokio::main]
#[tracing::instrument]
async fn main() -> miette::Result<()> {
- let args = crate::cli::Cli::parse();
- let _guard = crate::logging::setup_logging(
+ let args = tedge_cli::cli::Cli::parse();
+ let _guard = tedge_cli::logging::setup_logging(
args.logging,
args.chrome_logging.as_ref(),
args.tracy_logging,
@@ -89,162 +18,99 @@ async fn main() -> miette::Result<()> {
info!("Tedge booting...");
debug!(?args, "Tedge CLI");
- let registry = Registry {
- app_builder: TedgeApplication::builder(),
- plugin_kinds: HashSet::new(),
- doc_printers: HashMap::new(),
- };
+ let registry = tedge_cli::Registry::new();
info!("Building application");
let registry = {
cfg_table::cfg_table! {
- [not(feature = "mqtt")] => register_plugin!(
- registry,
- "builtin_plugin_log",
- plugin_log::LogPluginBuilder<(Measurement, Notification)>,
- plugin_log::LogPluginBuilder::<(Measurement, Notification)>::new()
- ),
-
- [feature = "mqtt"] => register_plugin!(
- registry,
- "builtin_plugin_log",
- plugin_log::LogPluginBuilder<(Measurement, Notification, plugin_mqtt::IncomingMessage)>,
- plugin_log::LogPluginBuilder::<(Measurement, Notification, plugin_mqtt::IncomingMessage)>::new()
- ),
+ [not(feature = "mqtt")] => {
+ tedge_cli::register_plugin!(
+ if feature "builtin_plugin_log" is enabled then
+ register on registry
+ builder of type plugin_log::LogPluginBuilder<(Measurement, Notification)>,
+ with instance {
+ plugin_log::LogPluginBuilder::<(Measurement, Notification)>::new()
+ }
+ )
+ },
+
+ [feature = "mqtt"] => {
+ tedge_cli::register_plugin!(
+ if feature "builtin_plugin_log" is enabled then
+ register on registry
+ builder of type plugin_log::LogPluginBuilder<(Measurement, Notification, plugin_mqtt::IncomingMessage)>,
+ with instance {
+ plugin_log::LogPluginBuilder::<(Measurement, Notification, plugin_mqtt::IncomingMessage)>::new()
+ }
+ )
+ },
}
};
- let registry = register_plugin!(
- registry,
- "builtin_plugin_avg",
- plugin_avg::AvgPluginBuilder,
- plugin_avg::AvgPluginBuilder
- );
- let registry = register_plugin!(
- registry,
- "builtin_plugin_sysstat",
- plugin_sysstat::SysStatPluginBuilder,
- plugin_sysstat::SysStatPluginBuilder
- );
- let registry = register_plugin!(
- registry,
- "builtin_plugin_inotify",
- plugin_inotify::InotifyPluginBuilder,
- plugin_inotify::InotifyPluginBuilder
- );
- let registry = register_plugin!(
- registry,
- "builtin_plugin_httpstop",
- plugin_httpstop::HttpStopPluginBuilder,
- plugin_httpstop::HttpStopPluginBuilder
- );
- let registry = register_plugin!(
- registry,
- "builtin_plugin_measurement_filter",
- plugin_measurement_filter::MeasurementFilterPluginBuilder,
- plugin_measurement_filter::MeasurementFilterPluginBuilder
+ let registry = tedge_cli::register_plugin!(
+ if feature "builtin_plugin_avg" is enabled then
+ register on registry
+ builder of type plugin_avg::AvgPluginBuilder,
+ with instance {
+ plugin_avg::AvgPluginBuilder
+ }
);
- let registry = register_plugin!(
- registry,
- "mqtt",
- plugin_mqtt::MqttPluginBuilder,
- plugin_mqtt::MqttPluginBuilder::new()
+ let registry = tedge_cli::register_plugin!(
+ if feature "builtin_plugin_sysstat" is enabled then
+ register on registry
+ builder of type plugin_sysstat::SysStatPluginBuilder,
+ with instance {
+ plugin_sysstat::SysStatPluginBuilder
+ }
);
- let registry = register_plugin!(
- registry,
- "mqtt",
- plugin_mqtt_measurement_bridge::MqttMeasurementBridgePluginBuilder,
- plugin_mqtt_measurement_bridge::MqttMeasurementBridgePluginBuilder::new()
+ let registry = tedge_cli::register_plugin!(
+ if feature "builtin_plugin_inotify" is enabled then
+ register on registry
+ builder of type plugin_inotify::InotifyPluginBuilder,
+ with instance {
+ plugin_inotify::InotifyPluginBuilder
+ }
);
- let registry = register_plugin!(
- registry,
- "builtin_plugin_notification",
- plugin_notification::NotificationPluginBuilder,
- plugin_notification::NotificationPluginBuilder
+ let registry = tedge_cli::register_plugin!(
+ if feature "builtin_plugin_httpstop" is enabled then
+ register on registry
+ builder of type plugin_httpstop::HttpStopPluginBuilder,
+ with instance {
+ plugin_httpstop::HttpStopPluginBuilder
+ }
);
-
- match args.command {
- cli::CliCommand::Run { config } => {
- let (cancel_sender, application) =
- registry.app_builder.with_config_from_path(config).await?;
- info!("Application built");
-
- debug!("Verifying the configuration");
- application.verify_configurations().await?;
-
- debug!("Going to run the application");
- run(cancel_sender, application).await
+ let registry = tedge_cli::register_plugin!(
+ if feature "builtin_plugin_measurement_filter" is enabled then
+ register on registry
+ builder of type plugin_measurement_filter::MeasurementFilterPluginBuilder,
+ with instance {
+ plugin_measurement_filter::MeasurementFilterPluginBuilder
}
- cli::CliCommand::ValidateConfig { config } => {
- let (_, application) = registry.app_builder.with_config_from_path(config).await?;
- info!("Application built");
-
- debug!("Only going to validate the configuration");
- application.verify_configurations().await?;
- info!("Configuration validated");
- Ok(())
+ );
+ let registry = tedge_cli::register_plugin!(
+ if feature "mqtt" is enabled then
+ register on registry
+ builder of type plugin_mqtt::MqttPluginBuilder,
+ with instance {
+ plugin_mqtt::MqttPluginBuilder::new()
}
- cli::CliCommand::GetPluginKinds => {
- use std::io::Write;
-
- let mut out = std::io::stdout();
- for name in registry.app_builder.plugin_kind_names() {
- writeln!(out, "{}", name).into_diagnostic()?;
- }
- Ok(())
+ );
+ let registry = tedge_cli::register_plugin!(
+ if feature "mqtt" is enabled then
+ register on registry
+ builder of type plugin_mqtt_measurement_bridge::MqttMeasurementBridgePluginBuilder,
+ with instance {
+ plugin_mqtt_measurement_bridge::MqttMeasurementBridgePluginBuilder::new()
}
- cli::CliCommand::Doc { plugin_name } => {
- let mut registry = registry;
- if let Some(plugin_name) = plugin_name {
- let printer = registry
- .doc_printers
- .remove(&plugin_name)
- .ok_or_else(|| miette::miette!("Plugin named '{}' not found", plugin_name))?;
-
- (printer)()?;
- } else {
- for printer in registry.doc_printers.into_values() {
- printer()?;
- }
- }
-
- Ok(())
+ );
+ let registry = tedge_cli::register_plugin!(
+ if feature "builtin_plugin_notification" is enabled then
+ register on registry
+ builder of type plugin_notification::NotificationPluginBuilder,
+ with instance {
+ plugin_notification::NotificationPluginBuilder
}
- }
-}
-
-async fn run(
- cancel_sender: TedgeApplicationCancelSender,
- application: TedgeApplication,
-) -> miette::Result<()> {
- info!("Booting app now.");
- let mut run_fut = Box::pin(application.run());
-
- let kill_app = |fut| -> miette::Result<()> {
- error!("Killing application");
- drop(fut);
- miette::bail!("Application killed")
- };
-
- let res = tokio::select! {
- res = &mut run_fut => {
- res
- },
-
- _int = tokio::signal::ctrl_c() => {
- if !cancel_sender.is_cancelled() {
- info!("Shutting down...");
- cancel_sender.cancel_app();
- tokio::select! {
- res = &mut run_fut => res,
- _ = tokio::signal::ctrl_c() => return kill_app(run_fut),
- }
- } else {
- return kill_app(run_fut);
- }
- },
- };
+ );
- info!("Bye");
- Ok(res?)
+ tedge_cli::run_app(args, registry).await
}
diff --git a/tedge/src/registry.rs b/tedge/src/registry.rs
new file mode 100644
index 00000000..5db4da45
--- /dev/null
+++ b/tedge/src/registry.rs
@@ -0,0 +1,78 @@
+use std::collections::HashMap;
+use std::collections::HashSet;
+
+use tedge_core::TedgeApplicationBuilder;
+
+/// Helper type for registering PluginBuilder instances and doc-printing functions
+pub struct Registry {
+ pub app_builder: TedgeApplicationBuilder,
+ pub plugin_kinds: HashSet<String>,
+ pub doc_printers: HashMap<String, Box<dyn FnOnce() -> Result<(), miette::Error>>>,
+}
+
+impl Registry {
+ pub fn new() -> Self {
+ Registry {
+ app_builder: tedge_core::TedgeApplication::builder(),
+ plugin_kinds: HashSet::new(),
+ doc_printers: HashMap::new(),
+ }
+ }
+}
+
+#[macro_export]
+macro_rules! register_plugin {
+ (if feature $cfg:tt is enabled then
+ register on $registry:ident
+ builder of type $pluginbuilder:ty,
+ with instance $pbinstance:expr
+ ) => {{
+ cfg_if::cfg_if! {
+ if #[cfg(feature = $cfg)] {
+ let kind_name: &'static str = <$pluginbuilder as tedge_api::PluginBuilder<tedge_core::PluginDirectory>>::kind_name();
+ info!(%kind_name, "Registering plugin builder");
+ let mut registry = $registry;
+ if !registry.plugin_kinds.insert(kind_name.to_string()) {
+ miette::bail!("Plugin kind '{}' was already registered, cannot register!", kind_name)
+ }
+
+ let kind_name_str = kind_name.to_string();
+ registry.doc_printers.insert(kind_name.to_string(), Box::new(move || {
+ use std::io::Write;
+ use miette::IntoDiagnostic;
+ use pretty::Arena;
+
+ let mut stdout = std::io::stdout();
+ if let Some(config_desc) = <$pluginbuilder as tedge_api::PluginBuilder<tedge_core::PluginDirectory>>::kind_configuration() {
+ let terminal_width = term_size::dimensions().map(|(w, _)| w).unwrap_or(80);
+ let arena = Arena::new();
+
+ let rendered_doc = tedge_cli::config::as_terminal_doc(&config_desc, &arena);
+
+ let mut output = String::new();
+ rendered_doc.render_fmt(terminal_width, &mut output).into_diagnostic()?;
+
+ writeln!(stdout, " ----- Documentation for plugin '{}'", kind_name_str)
+ .into_diagnostic()?;
+
+ writeln!(stdout, "{}", output).into_diagnostic()?;
+ } else {
+ let msg = format!(" Documentation for plugin '{}' is unavailable", kind_name);
+ writeln!(stdout, "{}", nu_ansi_term::Color::Red.bold().paint(msg))
+ .into_diagnostic()?;
+ }
+ Ok(())
+ }));
+
+ Registry {
+ app_builder: registry.app_builder.with_plugin_builder($pbinstance),
+ plugin_kinds: registry.plugin_kinds,
+ doc_printers: registry.doc_printers,
+ }
+ } else {
+ tracing::trace!("Not supporting plugins of type {}", std::stringify!($pluginbuilder));
+ $registry
+ }
+ }
+ }}
+}