#![warn(missing_docs)]
pub mod declarative;
pub mod metadata;
pub mod properties;
pub mod repo;
pub mod resolve;
pub mod script_eval;
use anyhow::Context;
use async_trait::async_trait;
use declarative::{deserialize_declarative_package, validate_declarative_package};
use mcvm_shared::pkg::{ArcPkgReq, PackageID};
use metadata::PackageMetadata;
use properties::PackageProperties;
#[cfg(feature = "schema")]
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
pub use mcvm_parse as parse;
pub use mcvm_shared::pkg::{PkgRequest, PkgRequestSource};
pub fn parse_and_validate(contents: &str, content_type: PackageContentType) -> anyhow::Result<()> {
match content_type {
PackageContentType::Script => {
let parsed = parse::parse::lex_and_parse(contents).context("Parsing failed")?;
metadata::eval_metadata(&parsed).context("Metadata evaluation failed")?;
properties::eval_properties(&parsed).context("Properties evaluation failed")?;
}
PackageContentType::Declarative => {
let contents = deserialize_declarative_package(contents).context("Parsing failed")?;
validate_declarative_package(&contents).context("Package was invalid")?;
}
}
Ok(())
}
#[derive(Deserialize, Serialize, Debug, Copy, Clone, Default)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "snake_case")]
pub enum PackageContentType {
#[default]
Script,
Declarative,
}
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)]
pub struct RequiredPackage {
pub value: PackageID,
pub explicit: bool,
}
#[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
pub struct RecommendedPackage {
pub value: PackageID,
#[serde(default)]
#[serde(skip_serializing_if = "is_false")]
pub invert: bool,
}
fn is_false(x: &bool) -> bool {
!x
}
#[async_trait]
pub trait PackageEvaluator<'a> {
type CommonInput;
type EvalInput<'b>: Clone;
type EvalRelationsResult<'b>: PackageEvalRelationsResult;
type ConfiguredPackage: ConfiguredPackage<EvalInput<'a> = Self::EvalInput<'a>>;
async fn eval_package_relations(
&mut self,
pkg: &ArcPkgReq,
input: &Self::EvalInput<'a>,
common_input: &Self::CommonInput,
) -> anyhow::Result<Self::EvalRelationsResult<'a>>;
async fn get_package_properties<'b>(
&'b mut self,
pkg: &ArcPkgReq,
common_input: &Self::CommonInput,
) -> anyhow::Result<&'b PackageProperties>;
}
pub trait ConfiguredPackage: Clone {
type EvalInput<'a>: Clone;
fn get_package(&self) -> ArcPkgReq;
fn override_configured_package_input(
&self,
properties: &PackageProperties,
input: &mut Self::EvalInput<'_>,
) -> anyhow::Result<()>;
}
pub trait PackageEvalRelationsResult {
fn get_deps(&self) -> Vec<Vec<RequiredPackage>>;
fn get_conflicts(&self) -> Vec<PackageID>;
fn get_recommendations(&self) -> Vec<RecommendedPackage>;
fn get_bundled(&self) -> Vec<PackageID>;
fn get_compats(&self) -> Vec<(PackageID, PackageID)>;
fn get_extensions(&self) -> Vec<PackageID>;
}
pub fn is_open_source(meta: &PackageMetadata, properties: &PackageProperties) -> bool {
if let Some(open_source) = &properties.open_source {
return *open_source;
}
if let Some(license) = &meta.license {
if let "ARR" | "All Rights Reserved" = license.as_str() {
return false;
}
}
true
}