Skip to content

Commit

Permalink
Remove variables factor assumption of toml
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Levick <[email protected]>
  • Loading branch information
rylev committed Jul 23, 2024
1 parent 8b895af commit 53d75ad
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 81 deletions.
69 changes: 29 additions & 40 deletions crates/factor-variables/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,42 @@
pub mod provider;
pub mod spin_cli;

use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

use serde::Deserialize;
use serde::{de::DeserializeOwned, Deserialize};
use spin_expressions::ProviderResolver;
use spin_factors::{
anyhow::{self, bail, Context},
ConfigureAppContext, Factor, FactorRuntimeConfig, InitContext, InstanceBuilders,
anyhow, ConfigureAppContext, Factor, FactorRuntimeConfig, InitContext, InstanceBuilders,
PrepareContext, RuntimeFactors, SelfInstanceBuilder,
};
use spin_world::{async_trait, v1, v2::variables};

pub use provider::{MakeVariablesProvider, StaticVariables};
pub use provider::MakeVariablesProvider;

#[derive(Default)]
pub struct VariablesFactor {
provider_types: HashMap<&'static str, provider::ProviderFromToml>,
pub struct VariablesFactor<C> {
provider_types: Vec<Box<dyn MakeVariablesProvider<RuntimeConfig = C>>>,
}

impl VariablesFactor {
pub fn add_provider_type<T: MakeVariablesProvider>(
impl<C> Default for VariablesFactor<C> {
fn default() -> Self {
Self {
provider_types: Default::default(),
}
}
}

impl<C> VariablesFactor<C> {
pub fn add_provider_type<T: MakeVariablesProvider<RuntimeConfig = C>>(
&mut self,
provider_type: T,
) -> anyhow::Result<()> {
if self
.provider_types
.insert(
T::RUNTIME_CONFIG_TYPE,
provider::provider_from_toml_fn(provider_type),
)
.is_some()
{
bail!("duplicate provider type {:?}", T::RUNTIME_CONFIG_TYPE);
}
self.provider_types.push(Box::new(provider_type) as _);
Ok(())
}
}

impl Factor for VariablesFactor {
type RuntimeConfig = RuntimeConfig;
impl<C: DeserializeOwned + 'static> Factor for VariablesFactor<C> {
type RuntimeConfig = RuntimeConfig<C>;
type AppState = AppState;
type InstanceBuilder = InstanceState;

Expand All @@ -64,13 +62,12 @@ impl Factor for VariablesFactor {
}

if let Some(runtime_config) = ctx.take_runtime_config() {
for ProviderConfig { type_, config } in runtime_config.provider_configs {
let provider_maker = self
.provider_types
.get(type_.as_str())
.with_context(|| format!("unknown variables provider type {type_:?}"))?;
let provider = provider_maker(config)?;
resolver.add_provider(provider);
for config in runtime_config.provider_configs {
for make_provider in self.provider_types.iter() {
if let Some(provider) = make_provider.make_provider(&config)? {
resolver.add_provider(provider);
}
}
}
}

Expand All @@ -95,22 +92,14 @@ impl Factor for VariablesFactor {

#[derive(Deserialize)]
#[serde(transparent)]
pub struct RuntimeConfig {
provider_configs: Vec<ProviderConfig>,
pub struct RuntimeConfig<C> {
provider_configs: Vec<C>,
}

impl FactorRuntimeConfig for RuntimeConfig {
impl<C: DeserializeOwned> FactorRuntimeConfig for RuntimeConfig<C> {
const KEY: &'static str = "variable_provider";
}

#[derive(Deserialize)]
struct ProviderConfig {
#[serde(rename = "type")]
type_: String,
#[serde(flatten)]
config: toml::Table,
}

pub struct AppState {
resolver: Arc<ProviderResolver>,
}
Expand Down
31 changes: 9 additions & 22 deletions crates/factor-variables/src/provider.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,17 @@
mod env;
mod statik;

pub use env::EnvVariables;
pub use statik::StaticVariables;

use serde::de::DeserializeOwned;
use spin_expressions::Provider;
use spin_factors::anyhow;

/// A trait for converting a runtime configuration into a variables provider.
pub trait MakeVariablesProvider: 'static {
const RUNTIME_CONFIG_TYPE: &'static str;

/// Serialized configuration for the provider.
type RuntimeConfig: DeserializeOwned;
type Provider: Provider;

fn make_provider(&self, runtime_config: Self::RuntimeConfig) -> anyhow::Result<Self::Provider>;
}

pub(crate) type ProviderFromToml = Box<dyn Fn(toml::Table) -> anyhow::Result<Box<dyn Provider>>>;

pub(crate) fn provider_from_toml_fn<T: MakeVariablesProvider>(
provider_type: T,
) -> ProviderFromToml {
Box::new(move |table| {
let runtime_config: T::RuntimeConfig = table.try_into()?;
let provider = provider_type.make_provider(runtime_config)?;
Ok(Box::new(provider))
})
/// Create a variables provider from the given runtime configuration.
///
/// Returns `Ok(None)` if the provider is not applicable to the given configuration.
fn make_provider(
&self,
runtime_config: &Self::RuntimeConfig,
) -> anyhow::Result<Option<Box<dyn Provider>>>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,26 @@ use tracing::{instrument, Level};

use crate::MakeVariablesProvider;

use super::RuntimeConfig;

/// Creator of a environment variables provider.
pub struct EnvVariables;

impl MakeVariablesProvider for EnvVariables {
const RUNTIME_CONFIG_TYPE: &'static str = "env";

type RuntimeConfig = EnvVariablesConfig;
type Provider = EnvVariablesProvider;
type RuntimeConfig = RuntimeConfig;

fn make_provider(&self, runtime_config: Self::RuntimeConfig) -> anyhow::Result<Self::Provider> {
Ok(EnvVariablesProvider::new(
runtime_config.prefix,
fn make_provider(
&self,
runtime_config: &Self::RuntimeConfig,
) -> anyhow::Result<Option<Box<dyn Provider>>> {
let RuntimeConfig::Env(runtime_config) = runtime_config else {
return Ok(None);
};
Ok(Some(Box::new(EnvVariablesProvider::new(
runtime_config.prefix.clone(),
|key| std::env::var(key),
runtime_config.dotenv_path,
))
runtime_config.dotenv_path.clone(),
))))
}
}

Expand Down
17 changes: 17 additions & 0 deletions crates/factor-variables/src/spin_cli/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//! The runtime configuration for the variables factor used in the Spin CLI.

mod env;
mod statik;

pub use env::EnvVariables;
pub use statik::StaticVariables;

use serde::Deserialize;
use statik::StaticVariablesProvider;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case", tag = "type")]
pub enum RuntimeConfig {
Static(StaticVariablesProvider),
Env(env::EnvVariablesConfig),
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,27 @@ use spin_factors::anyhow;

use crate::MakeVariablesProvider;

use super::RuntimeConfig;

/// Creator of a static variables provider.
pub struct StaticVariables;

impl MakeVariablesProvider for StaticVariables {
const RUNTIME_CONFIG_TYPE: &'static str = "static";

type RuntimeConfig = StaticVariablesProvider;
type Provider = StaticVariablesProvider;

fn make_provider(&self, runtime_config: Self::RuntimeConfig) -> anyhow::Result<Self::Provider> {
Ok(runtime_config)
type RuntimeConfig = RuntimeConfig;

fn make_provider(
&self,
runtime_config: &Self::RuntimeConfig,
) -> anyhow::Result<Option<Box<dyn Provider>>> {
let RuntimeConfig::Static(config) = runtime_config else {
return Ok(None);
};
Ok(Some(Box::new(config.clone()) as _))
}
}

/// A variables provider that reads variables from an static map.
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub struct StaticVariablesProvider {
values: Arc<HashMap<String, String>>,
}
Expand Down
5 changes: 3 additions & 2 deletions crates/factor-variables/tests/factor_test.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use spin_factor_variables::{StaticVariables, VariablesFactor};
use spin_factor_variables::spin_cli::{RuntimeConfig, StaticVariables};
use spin_factor_variables::VariablesFactor;
use spin_factors::{anyhow, RuntimeFactors};
use spin_factors_test::{toml, TestEnvironment};

#[derive(RuntimeFactors)]
struct TestFactors {
variables: VariablesFactor,
variables: VariablesFactor<RuntimeConfig>,
}

fn test_env() -> TestEnvironment {
Expand Down

0 comments on commit 53d75ad

Please sign in to comment.