splits out types for different package pointers

This commit is contained in:
Keagan McClelland
2021-09-21 15:17:26 -06:00
committed by Aiden McClelland
parent bed4c92b26
commit 4c29d8c372
3 changed files with 135 additions and 110 deletions

View File

@@ -13,7 +13,6 @@ use rpc_toolkit::command;
use serde_json::Value; use serde_json::Value;
use crate::action::docker::DockerAction; use crate::action::docker::DockerAction;
use crate::config::spec::PackagePointerSpecVariant;
use crate::context::RpcContext; use crate::context::RpcContext;
use crate::db::model::{ use crate::db::model::{
CurrentDependencyInfo, InstalledPackageDataEntry, InstalledPackageDataEntryModel, CurrentDependencyInfo, InstalledPackageDataEntry, InstalledPackageDataEntryModel,
@@ -346,14 +345,16 @@ pub fn configure<'a, Db: DbHandle>(
.collect(); .collect();
for ptr in spec.pointers(&config)? { for ptr in spec.pointers(&config)? {
match ptr { match ptr {
ValueSpecPointer::Package(PackagePointerSpec { package_id, target }) => { ValueSpecPointer::Package(pkg_ptr) => {
if let Some(current_dependency) = current_dependencies.get_mut(&package_id) { if let Some(current_dependency) =
current_dependency.pointers.push(target); current_dependencies.get_mut(pkg_ptr.package_id())
{
current_dependency.pointers.push(pkg_ptr);
} else { } else {
current_dependencies.insert( current_dependencies.insert(
package_id, pkg_ptr.package_id().to_owned(),
CurrentDependencyInfo { CurrentDependencyInfo {
pointers: vec![target], pointers: vec![pkg_ptr],
health_checks: BTreeSet::new(), health_checks: BTreeSet::new(),
}, },
); );
@@ -448,7 +449,7 @@ pub fn configure<'a, Db: DbHandle>(
// handle backreferences // handle backreferences
for ptr in &dep_info.pointers { for ptr in &dep_info.pointers {
if let PackagePointerSpecVariant::Config(cfg_ptr) = ptr { if let PackagePointerSpec::Config(cfg_ptr) = ptr {
if cfg_ptr.select(&next) != cfg_ptr.select(&prev) { if cfg_ptr.select(&next) != cfg_ptr.select(&prev) {
if let Err(e) = configure( if let Err(e) = configure(
ctx, db, dependent, None, timeout, dry_run, overrides, breakages, ctx, db, dependent, None, timeout, dry_run, overrides, breakages,

View File

@@ -12,6 +12,7 @@ use async_trait::async_trait;
use indexmap::{IndexMap, IndexSet}; use indexmap::{IndexMap, IndexSet};
use itertools::Itertools; use itertools::Itertools;
use jsonpath_lib::Compiled as CompiledJsonPath; use jsonpath_lib::Compiled as CompiledJsonPath;
use lazy_static::__Deref;
use patch_db::{DbHandle, OptionModel}; use patch_db::{DbHandle, OptionModel};
use rand::{CryptoRng, Rng}; use rand::{CryptoRng, Rng};
use regex::Regex; use regex::Regex;
@@ -1501,54 +1502,175 @@ impl ValueSpec for ValueSpecPointer {
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(tag = "target")]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct PackagePointerSpec { pub enum PackagePointerSpec {
pub package_id: PackageId, TorAddress(TorAddressPointer),
#[serde(flatten)] LanAddress(LanAddressPointer),
pub target: PackagePointerSpecVariant, Config(ConfigPointer),
}
impl fmt::Display for PackagePointerSpec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {}", self.package_id, self.target)
}
} }
impl PackagePointerSpec { impl PackagePointerSpec {
pub fn package_id(&self) -> &PackageId {
match self {
PackagePointerSpec::TorAddress(TorAddressPointer { package_id, .. }) => package_id,
PackagePointerSpec::LanAddress(LanAddressPointer { package_id, .. }) => package_id,
PackagePointerSpec::Config(ConfigPointer { package_id, .. }) => package_id,
}
}
async fn deref<Db: DbHandle>( async fn deref<Db: DbHandle>(
&self, &self,
ctx: &RpcContext, ctx: &RpcContext,
db: &mut Db, db: &mut Db,
config_overrides: &BTreeMap<PackageId, Config>, config_overrides: &BTreeMap<PackageId, Config>,
) -> Result<Value, ConfigurationError> { ) -> Result<Value, ConfigurationError> {
match &self.target { match &self {
PackagePointerSpecVariant::Tor(TorAddressPointer { interface }) => { PackagePointerSpec::TorAddress(tor) => tor.deref(db).await,
PackagePointerSpec::LanAddress(lan) => lan.deref(db).await,
PackagePointerSpec::Config(cfg) => cfg.deref(ctx, db, config_overrides).await,
}
}
}
impl fmt::Display for PackagePointerSpec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PackagePointerSpec::TorAddress(tor) => write!(f, "{}", tor),
PackagePointerSpec::LanAddress(lan) => write!(f, "{}", lan),
PackagePointerSpec::Config(cfg) => write!(f, "{}", cfg),
}
}
}
impl Defaultable for PackagePointerSpec {
type Error = ConfigurationError;
fn gen<R: Rng + CryptoRng + Sync + Send>(
&self,
_rng: &mut R,
_timeout: &Option<Duration>,
) -> Result<Value, Self::Error> {
Ok(Value::Null)
}
}
#[async_trait]
impl ValueSpec for PackagePointerSpec {
fn matches(&self, _value: &Value) -> Result<(), NoMatchWithPath> {
Ok(())
}
fn validate(&self, manifest: &Manifest) -> Result<(), NoMatchWithPath> {
if &manifest.id != self.package_id()
&& !manifest.dependencies.0.contains_key(self.package_id())
{
return Err(NoMatchWithPath::new(MatchError::InvalidPointer(
ValueSpecPointer::Package(self.clone()),
)));
}
match self {
_ => Ok(()),
}
}
async fn update<Db: DbHandle>(
&self,
ctx: &RpcContext,
db: &mut Db,
config_overrides: &BTreeMap<PackageId, Config>,
value: &mut Value,
) -> Result<(), ConfigurationError> {
*value = self.deref(ctx, db, config_overrides).await?;
Ok(())
}
fn pointers(&self, _value: &Value) -> Result<HashSet<ValueSpecPointer>, NoMatchWithPath> {
let mut pointers = HashSet::new();
pointers.insert(ValueSpecPointer::Package(self.clone()));
Ok(pointers)
}
fn requires(&self, id: &PackageId, _value: &Value) -> bool {
self.package_id() == id
}
fn eq(&self, _lhs: &Value, _rhs: &Value) -> bool {
false
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct TorAddressPointer {
package_id: PackageId,
interface: InterfaceId,
}
impl TorAddressPointer {
async fn deref<Db: DbHandle>(&self, db: &mut Db) -> Result<Value, ConfigurationError> {
let addr = crate::db::DatabaseModel::new() let addr = crate::db::DatabaseModel::new()
.package_data() .package_data()
.idx_model(&self.package_id) .idx_model(&self.package_id)
.and_then(|pde| pde.installed()) .and_then(|pde| pde.installed())
.and_then(|installed| installed.interface_addresses().idx_model(interface)) .and_then(|installed| installed.interface_addresses().idx_model(&self.interface))
.and_then(|addresses| addresses.tor_address()) .and_then(|addresses| addresses.tor_address())
.get(db, true) .get(db, true)
.await .await
.map_err(|e| ConfigurationError::SystemError(Error::from(e)))?; .map_err(|e| ConfigurationError::SystemError(Error::from(e)))?;
Ok(addr.to_owned().map(Value::String).unwrap_or(Value::Null)) Ok(addr.to_owned().map(Value::String).unwrap_or(Value::Null))
} }
PackagePointerSpecVariant::Lan(LanAddressPointer { interface }) => { }
impl fmt::Display for TorAddressPointer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TorAddressPointer {
package_id,
interface,
} => write!(f, "{}: tor-address: {}", package_id, interface),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct LanAddressPointer {
package_id: PackageId,
interface: InterfaceId,
}
impl fmt::Display for LanAddressPointer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LanAddressPointer {
package_id,
interface,
} => write!(f, "{}: lan-address: {}", package_id, interface),
}
}
}
impl LanAddressPointer {
async fn deref<Db: DbHandle>(&self, db: &mut Db) -> Result<Value, ConfigurationError> {
let addr = crate::db::DatabaseModel::new() let addr = crate::db::DatabaseModel::new()
.package_data() .package_data()
.idx_model(&self.package_id) .idx_model(&self.package_id)
.and_then(|pde| pde.installed()) .and_then(|pde| pde.installed())
.and_then(|installed| installed.interface_addresses().idx_model(interface)) .and_then(|installed| installed.interface_addresses().idx_model(&self.interface))
.and_then(|addresses| addresses.lan_address()) .and_then(|addresses| addresses.lan_address())
.get(db, true) .get(db, true)
.await .await
.map_err(|e| ConfigurationError::SystemError(Error::from(e)))?; .map_err(|e| ConfigurationError::SystemError(Error::from(e)))?;
Ok(addr.to_owned().map(Value::String).unwrap_or(Value::Null)) Ok(addr.to_owned().map(Value::String).unwrap_or(Value::Null))
} }
PackagePointerSpecVariant::Config(ConfigPointer { selector, multi }) => { }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct ConfigPointer {
package_id: PackageId,
selector: Arc<ConfigSelector>,
multi: bool,
}
impl ConfigPointer {
pub fn select(&self, val: &Value) -> Value {
self.selector.select(self.multi, val)
}
async fn deref<Db: DbHandle>(
&self,
ctx: &RpcContext,
db: &mut Db,
config_overrides: &BTreeMap<PackageId, Config>,
) -> Result<Value, ConfigurationError> {
if let Some(cfg) = config_overrides.get(&self.package_id) { if let Some(cfg) = config_overrides.get(&self.package_id) {
Ok(selector.select(*multi, &Value::Object(cfg.clone()))) Ok(self.select(&Value::Object(cfg.clone())))
} else { } else {
let manifest_model: OptionModel<Manifest> = crate::db::DatabaseModel::new() let manifest_model: OptionModel<_> = crate::db::DatabaseModel::new()
.package_data() .package_data()
.idx_model(&self.package_id) .idx_model(&self.package_id)
.and_then(|pde| pde.installed()) .and_then(|pde| pde.installed())
@@ -1579,7 +1701,7 @@ impl PackagePointerSpec {
.await .await
.map_err(|e| ConfigurationError::SystemError(Error::from(e)))?; .map_err(|e| ConfigurationError::SystemError(Error::from(e)))?;
if let Some(cfg) = cfg_res.config { if let Some(cfg) = cfg_res.config {
Ok(selector.select(*multi, &Value::Object(cfg))) Ok(self.select(&Value::Object(cfg)))
} else { } else {
Ok(Value::Null) Ok(Value::Null)
} }
@@ -1589,112 +1711,14 @@ impl PackagePointerSpec {
} }
} }
} }
}
}
impl Defaultable for PackagePointerSpec {
type Error = ConfigurationError;
fn gen<R: Rng + CryptoRng + Sync + Send>(
&self,
_rng: &mut R,
_timeout: &Option<Duration>,
) -> Result<Value, Self::Error> {
Ok(Value::Null)
}
}
#[async_trait]
impl ValueSpec for PackagePointerSpec {
fn matches(&self, _value: &Value) -> Result<(), NoMatchWithPath> {
Ok(())
}
fn validate(&self, manifest: &Manifest) -> Result<(), NoMatchWithPath> {
if manifest.id != self.package_id && !manifest.dependencies.0.contains_key(&self.package_id)
{
return Err(NoMatchWithPath::new(MatchError::InvalidPointer(
ValueSpecPointer::Package(self.clone()),
)));
}
match self.target {
_ => Ok(()),
}
}
async fn update<Db: DbHandle>(
&self,
ctx: &RpcContext,
db: &mut Db,
config_overrides: &BTreeMap<PackageId, Config>,
value: &mut Value,
) -> Result<(), ConfigurationError> {
*value = self.deref(ctx, db, config_overrides).await?;
Ok(())
}
fn pointers(&self, _value: &Value) -> Result<HashSet<ValueSpecPointer>, NoMatchWithPath> {
let mut pointers = HashSet::new();
pointers.insert(ValueSpecPointer::Package(self.clone()));
Ok(pointers)
}
fn requires(&self, id: &PackageId, _value: &Value) -> bool {
&self.package_id == id
}
fn eq(&self, _lhs: &Value, _rhs: &Value) -> bool {
false
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(tag = "target")]
#[serde(rename_all = "kebab-case")]
pub enum PackagePointerSpecVariant {
Tor(TorAddressPointer),
Lan(LanAddressPointer),
Config(ConfigPointer),
}
impl fmt::Display for PackagePointerSpecVariant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Tor(tor) => write!(f, "{}", tor),
Self::Lan(lan) => write!(f, "{}", lan),
Self::Config(cfg) => write!(f, "{}", cfg),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct TorAddressPointer {
interface: InterfaceId,
}
impl fmt::Display for TorAddressPointer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TorAddressPointer { interface } => write!(f, "tor-address: {}", interface),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct LanAddressPointer {
interface: InterfaceId,
}
impl fmt::Display for LanAddressPointer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
LanAddressPointer { interface } => write!(f, "lan-address: {}", interface),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ConfigPointer {
selector: Arc<ConfigSelector>,
multi: bool,
}
impl ConfigPointer {
pub fn select(&self, val: &Value) -> Value {
self.selector.select(self.multi, val)
}
}
impl fmt::Display for ConfigPointer { impl fmt::Display for ConfigPointer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
ConfigPointer { selector, .. } => write!(f, "config: {}", selector), ConfigPointer {
package_id,
selector,
..
} => write!(f, "{}: config: {}", package_id, selector),
} }
} }
} }

View File

@@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use torut::onion::TorSecretKeyV3; use torut::onion::TorSecretKeyV3;
use crate::config::spec::{PackagePointerSpecVariant, SystemPointerSpec}; use crate::config::spec::{PackagePointerSpec, SystemPointerSpec};
use crate::install::progress::InstallProgress; use crate::install::progress::InstallProgress;
use crate::net::interface::InterfaceId; use crate::net::interface::InterfaceId;
use crate::s9pk::manifest::{Manifest, ManifestModel, PackageId}; use crate::s9pk::manifest::{Manifest, ManifestModel, PackageId};
@@ -235,7 +235,7 @@ pub struct StaticDependencyInfo {
#[derive(Clone, Debug, Default, Deserialize, Serialize, HasModel)] #[derive(Clone, Debug, Default, Deserialize, Serialize, HasModel)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
pub struct CurrentDependencyInfo { pub struct CurrentDependencyInfo {
pub pointers: Vec<PackagePointerSpecVariant>, pub pointers: Vec<PackagePointerSpec>,
pub health_checks: BTreeSet<HealthCheckId>, pub health_checks: BTreeSet<HealthCheckId>,
} }