Skip to main content

dre_core/config/
dependencies.rs

1//! The shapes of `dependencies.yml` (or `packages.yml`): `plugins:`, the plugin packages, which
2//! any project YAML file may also declare, and `packages:`, the macro packages.
3
4use schemars::JsonSchema;
5use serde::Deserialize;
6use serde::de::Deserializer;
7
8use super::de::{Located, Loose, Map, OneOf, UnknownKeys};
9
10/// Plugin packages and macro packages, in `dependencies.yml` or `packages.yml` at the project root.
11#[derive(Deserialize, JsonSchema)]
12#[schemars(title = "DRE dependencies", deny_unknown_fields)]
13pub struct DependenciesFile {
14    #[serde(default)]
15    #[schemars(schema_with = "plugins")]
16    pub plugins: Option<PluginsSection>,
17    /// Macro packages (git or local). Their macros are called through the package name, e.g. `{{ dre_utils.star(...) }}`. Exact commits are pinned in `dre.lock`.
18    pub packages: Option<Located<Loose<Vec<Loose<Package>>>>>,
19}
20
21/// The `plugins:` key of any project YAML file.
22#[derive(Deserialize)]
23pub struct PluginsKey {
24    pub plugins: Option<PluginsSection>,
25}
26
27/// `plugins:`: a list of packages, or package names mapped to versions.
28pub type PluginsSection = Located<Loose<OneOf<Vec<Located<Loose<PluginItem>>>, Map<serde_json::Value>>>>;
29
30/// One `plugins:` item (see [`Item`] for its description).
31pub type PluginItem = OneOf<PackageName, OneOf<PinnedVersion, PluginEntry>>;
32
33/// A package name, e.g. `duckdb`. Any version.
34#[derive(Deserialize, JsonSchema)]
35#[serde(transparent)]
36#[schemars(inline)]
37pub struct PackageName(pub String);
38
39/// A package name mapped to a version constraint, e.g. `duckdb: ">=1.0"`.
40#[derive(JsonSchema)]
41#[schemars(inline, extend("additionalProperties" = true, "minProperties" = 1, "maxProperties" = 1))]
42pub struct PinnedVersion {
43    #[schemars(skip)]
44    pub name: Located<String>,
45    #[schemars(skip)]
46    pub version: serde_json::Value,
47}
48
49impl<'de> Deserialize<'de> for PinnedVersion {
50    /// One key, which isn't `name` (that's a [`PluginEntry`]).
51    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
52        let m = Map::<serde_json::Value>::deserialize(d)?;
53        match <[_; 1]>::try_from(m.0) {
54            Ok([(name, version)]) if name.value != "name" => Ok(PinnedVersion { name, version }),
55            _ => Err(serde::de::Error::custom("not a single `name: version` pair")),
56        }
57    }
58}
59
60/// A package with its source.
61#[derive(Deserialize, JsonSchema)]
62#[schemars(deny_unknown_fields, inline)]
63pub struct PluginEntry {
64    /// The package name: lowercase letters, digits and `_`.
65    #[schemars(with = "String")]
66    pub name: Loose<String>,
67    /// A version constraint such as `1.2.0` or `>=1.0`. Not allowed with `local`.
68    #[serde(default)]
69    #[schemars(with = "String")]
70    pub version: Option<serde_json::Value>,
71    /// Install from the releases of this GitHub repository, `owner/repo`.
72    #[serde(default)]
73    #[schemars(with = "String")]
74    pub github: Option<serde_json::Value>,
75    /// Use the package folder at this path as it is.
76    #[serde(default)]
77    #[schemars(with = "String")]
78    pub local: Option<serde_json::Value>,
79    /// Install from this registry index (a URL or a path) instead of the default one.
80    #[serde(default)]
81    #[schemars(with = "String")]
82    pub registry: Option<serde_json::Value>,
83    #[serde(rename = "$unknown", default)]
84    #[schemars(skip)]
85    pub unknown: UnknownKeys,
86}
87
88/// A macro package, from git or from a folder.
89#[derive(Deserialize, JsonSchema)]
90#[schemars(rename = "package", deny_unknown_fields)]
91#[schemars(extend("oneOf" = [{"required": ["git", "revision"]}, {"required": ["local"]}]))]
92pub struct Package {
93    /// The git URL of the package. Needs `revision`.
94    pub git: Option<Loose<String>>,
95    /// A tag, branch or commit of the git package.
96    pub revision: Option<Loose<String>>,
97    /// The path of a package folder in this project's tree.
98    pub local: Option<Loose<String>>,
99    /// The registry name of a package: not available yet, read only to say so.
100    #[schemars(skip)]
101    pub package: Option<Loose<String>>,
102}
103
104/// Package names mapped to version constraints.
105#[derive(JsonSchema)]
106#[schemars(inline, extend("additionalProperties" = true))]
107#[allow(dead_code)]
108struct VersionMap {}
109
110/// The plugin packages this project uses. DRE installs them on demand into `dre_deps/` and pins them in `dre.lock`. May be written in any project YAML file; `dependencies.yml` is the usual place.
111#[derive(JsonSchema)]
112#[schemars(inline, extend("x-doc-type" = "list of plugin packages: a name, `name: \"<version>\"`, or a map (see below)"))]
113#[allow(dead_code)]
114struct Plugins(OneOf<Vec<Item>, OneOf<VersionMap, ()>>);
115
116/// One plugin package: just its name, a `name: "<version>"` pair, or a map with `name` and where to get it.
117#[derive(JsonSchema)]
118#[schemars(inline)]
119#[allow(dead_code)]
120struct Item(PluginItem);
121
122/// The schema of `plugins:`, wherever it's written.
123pub(super) fn plugins(g: &mut schemars::SchemaGenerator) -> schemars::Schema {
124    g.subschema_for::<Plugins>()
125}