Skip to content

Commit eae90a7

Browse files
author
Nichol Yip
committed
Fix issue where EnvOpList was not properly deserialized and bypassed the multiple priority config check.
Signed-off-by: Nichol Yip <[email protected]>
1 parent 77fbd44 commit eae90a7

File tree

5 files changed

+187
-93
lines changed

5 files changed

+187
-93
lines changed

crates/spk-schema/src/embedded_packages_list.rs

+128-39
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use spk_schema_foundation::spec_ops::Named;
88
use spk_schema_foundation::IsDefault;
99
use spk_schema_ident::AnyIdent;
1010

11-
use super::{BuildSpec, InstallSpec, Spec};
11+
use super::{BuildSpec, InstallSpec, Lint, LintedItem, Lints, Spec};
1212
use crate::component_embedded_packages::ComponentEmbeddedPackage;
1313
use crate::foundation::ident_build::Build;
1414
use crate::Package;
@@ -61,53 +61,142 @@ impl std::ops::DerefMut for EmbeddedPackagesList {
6161
}
6262
}
6363

64+
#[derive(Default)]
65+
struct EmbeddedPackagesListVisitor {
66+
embedded: Vec<Spec>,
67+
lints: Vec<Lint>,
68+
}
69+
70+
impl Lints for EmbeddedPackagesListVisitor {
71+
fn lints(&mut self) -> Vec<Lint> {
72+
std::mem::take(&mut self.lints)
73+
}
74+
}
75+
76+
impl From<EmbeddedPackagesListVisitor> for EmbeddedPackagesList {
77+
fn from(value: EmbeddedPackagesListVisitor) -> Self {
78+
Self(value.embedded)
79+
}
80+
}
81+
6482
impl<'de> Deserialize<'de> for EmbeddedPackagesList {
6583
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
6684
where
67-
D: serde::Deserializer<'de>,
85+
D: serde::de::Deserializer<'de>,
86+
{
87+
Ok(deserializer
88+
.deserialize_seq(EmbeddedPackagesListVisitor::default())?
89+
.into())
90+
}
91+
}
92+
93+
impl<'de> Deserialize<'de> for LintedItem<EmbeddedPackagesList> {
94+
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
95+
where
96+
D: serde::de::Deserializer<'de>,
6897
{
69-
struct EmbeddedPackagesListVisitor;
98+
Ok(deserializer
99+
.deserialize_seq(EmbeddedPackagesListVisitor::default())?
100+
.into())
101+
}
102+
}
70103

71-
impl<'de> serde::de::Visitor<'de> for EmbeddedPackagesListVisitor {
72-
type Value = EmbeddedPackagesList;
104+
impl<'de> serde::de::Visitor<'de> for EmbeddedPackagesListVisitor {
105+
type Value = EmbeddedPackagesListVisitor;
73106

74-
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
75-
f.write_str("a list of embedded packages")
76-
}
107+
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
108+
f.write_str("a list of embedded packages")
109+
}
110+
111+
fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
112+
where
113+
A: serde::de::SeqAccess<'de>,
114+
{
115+
let size_hint = seq.size_hint().unwrap_or(0);
116+
let mut lints = Vec::new();
117+
let mut embedded_stubs = Vec::with_capacity(size_hint);
118+
let mut default_build_spec = BuildSpec::default();
119+
let mut default_install_spec = InstallSpec::default();
120+
while let Some(mut embedded) =
121+
seq.next_element::<LintedItem<super::v0::Spec<AnyIdent>>>()?
122+
{
123+
lints.append(&mut embedded.lints);
77124

78-
fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
79-
where
80-
A: serde::de::SeqAccess<'de>,
81-
{
82-
let size_hint = seq.size_hint().unwrap_or(0);
83-
let mut embedded_stubs = Vec::with_capacity(size_hint);
84-
let mut default_build_spec = BuildSpec::default();
85-
let mut default_install_spec = InstallSpec::default();
86-
while let Some(embedded) = seq.next_element::<super::v0::Spec<AnyIdent>>()? {
87-
default_build_spec
88-
.options
89-
.clone_from(&embedded.build.options);
90-
if default_build_spec != embedded.build {
91-
return Err(serde::de::Error::custom(
92-
"embedded packages can only specify build.options",
93-
));
94-
}
95-
default_install_spec.components = embedded.install.components.clone();
96-
if default_install_spec != embedded.install {
97-
return Err(serde::de::Error::custom(
98-
"embedded packages can only specify install.components",
99-
));
100-
}
101-
let embedded = embedded.map_ident(|i| {
102-
i.into_base()
103-
.into_build_ident(Build::Embedded(EmbeddedSource::Unknown))
104-
});
105-
embedded_stubs.push(Spec::V0Package(embedded));
106-
}
107-
Ok(EmbeddedPackagesList(embedded_stubs))
125+
default_build_spec
126+
.options
127+
.clone_from(&embedded.item.build.options);
128+
if default_build_spec != embedded.item.build {
129+
return Err(serde::de::Error::custom(
130+
"embedded packages can only specify build.options",
131+
));
108132
}
133+
default_install_spec.components = embedded.item.install.components.clone();
134+
if default_install_spec != embedded.item.install {
135+
return Err(serde::de::Error::custom(
136+
"embedded packages can only specify install.components",
137+
));
138+
}
139+
let embedded = embedded.item.map_ident(|i| {
140+
i.into_base()
141+
.into_build_ident(Build::Embedded(EmbeddedSource::Unknown))
142+
});
143+
embedded_stubs.push(Spec::V0Package(embedded));
109144
}
110145

111-
deserializer.deserialize_seq(EmbeddedPackagesListVisitor)
146+
Ok(Self {
147+
embedded: embedded_stubs,
148+
lints,
149+
})
112150
}
113151
}
152+
153+
// impl<'de> Deserialize<'de> for EmbeddedPackagesList {
154+
// fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
155+
// where
156+
// D: serde::Deserializer<'de>,
157+
// {
158+
// struct EmbeddedPackagesListVisitor;
159+
160+
// impl<'de> serde::de::Visitor<'de> for EmbeddedPackagesListVisitor {
161+
// type Value = EmbeddedPackagesList;
162+
163+
// fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
164+
// f.write_str("a list of embedded packages")
165+
// }
166+
167+
// fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
168+
// where
169+
// A: serde::de::SeqAccess<'de>,
170+
// {
171+
// let size_hint = seq.size_hint().unwrap_or(0);
172+
// let mut embedded_stubs = Vec::with_capacity(size_hint);
173+
// let mut default_build_spec = BuildSpec::default();
174+
// let mut default_install_spec = InstallSpec::default();
175+
// while let Some(embedded) = seq.next_element::<LintedItem<super::v0::Spec<AnyIdent>>>()? {
176+
// default_build_spec
177+
// .options
178+
// .clone_from(&embedded.item.build.options);
179+
// if default_build_spec != embedded.build {
180+
// return Err(serde::de::Error::custom(
181+
// "embedded packages can only specify build.options",
182+
// ));
183+
// }
184+
// default_install_spec.components = embedded.item.install.components.clone();
185+
// if default_install_spec != embedded.item.install {
186+
// return Err(serde::de::Error::custom(
187+
// "embedded packages can only specify install.components",
188+
// ));
189+
// }
190+
// let embedded = embedded.map_ident(|i| {
191+
// i.into_base()
192+
// .into_build_ident(Build::Embedded(EmbeddedSource::Unknown))
193+
// });
194+
// embedded_stubs.push(Spec::V0Package(embedded));
195+
// }
196+
// Ok(EmbeddedPackagesList(embedded_stubs))
197+
// }
198+
// }
199+
200+
// deserializer.deserialize_seq(EmbeddedPackagesListVisitor)
201+
// }
202+
// }

crates/spk-schema/src/environ.rs

+38-1
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,46 @@ impl EnvOp {
188188
}
189189
}
190190

191-
#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
191+
#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
192192
pub struct EnvOpList(Vec<EnvOp>);
193193

194+
impl<'de> Deserialize<'de> for EnvOpList {
195+
fn deserialize<D>(deserializer: D) -> std::result::Result<EnvOpList, D::Error>
196+
where
197+
D: serde::Deserializer<'de>,
198+
{
199+
struct EnvConfVisitor;
200+
201+
impl<'de> serde::de::Visitor<'de> for EnvConfVisitor {
202+
type Value = EnvOpList;
203+
204+
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
205+
f.write_str("an environment configuration")
206+
}
207+
208+
fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
209+
where
210+
A: serde::de::SeqAccess<'de>,
211+
{
212+
let mut vec = EnvOpList::default();
213+
214+
while let Some(elem) = seq.next_element::<EnvOp>()? {
215+
if vec.iter().any(|x: &EnvOp| x.kind() == OpKind::Priority)
216+
&& elem.kind() == OpKind::Priority
217+
{
218+
return Err(serde::de::Error::custom(
219+
"Multiple priority config cannot be set.",
220+
));
221+
};
222+
vec.push(elem);
223+
}
224+
Ok(vec)
225+
}
226+
}
227+
deserializer.deserialize_seq(EnvConfVisitor)
228+
}
229+
}
230+
194231
impl IsDefault for EnvOpList {
195232
fn is_default(&self) -> bool {
196233
self.0.is_empty()

crates/spk-schema/src/install_spec.rs

+16-49
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@ use crate::foundation::option_map::OptionMap;
1717
use crate::{
1818
ComponentSpecList,
1919
EmbeddedPackagesList,
20-
EnvOp,
2120
EnvOpList,
2221
Lint,
2322
LintedItem,
2423
Lints,
25-
OpKind,
2624
Package,
2725
RequirementsList,
2826
Result,
@@ -38,6 +36,7 @@ mod install_spec_test;
3836
Clone,
3937
Debug,
4038
Default,
39+
Deserialize,
4140
Eq,
4241
Hash,
4342
is_default_derive_macro::IsDefault,
@@ -63,7 +62,7 @@ where
6362
D: Default,
6463
{
6564
fn lints(&mut self) -> Vec<Lint> {
66-
// self.lints.extend(std::mem::take(&mut self.environment.lints));
65+
self.lints.extend(std::mem::take(&mut self.embedded.lints));
6766
std::mem::take(&mut self.lints)
6867
}
6968
}
@@ -74,21 +73,21 @@ where
7473
D: Default,
7574
{
7675
requirements: RequirementsList,
77-
embedded: EmbeddedPackagesList,
76+
embedded: LintedItem<EmbeddedPackagesList>,
7877
components: ComponentSpecList,
7978
environment: EnvOpList,
8079
lints: Vec<Lint>,
8180
_phantom: PhantomData<D>,
8281
}
8382

84-
impl<D> From<InstallSpecVisitor<D>> for InstallSpec
83+
impl<D> From<InstallSpecVisitor<D>> for RawInstallSpec
8584
where
8685
D: Default,
8786
{
8887
fn from(value: InstallSpecVisitor<D>) -> Self {
8988
Self {
9089
requirements: value.requirements,
91-
embedded: value.embedded,
90+
embedded: value.embedded.item,
9291
components: value.components,
9392
environment: value.environment,
9493
}
@@ -206,69 +205,35 @@ impl From<RawInstallSpec> for InstallSpec {
206205
}
207206
}
208207

209-
#[derive(Deserialize)]
210-
struct RawInstallSpec {
208+
/// A raw, unvalidated install spec.
209+
#[derive(Serialize, Default)]
210+
pub struct RawInstallSpec {
211211
#[serde(default)]
212212
requirements: RequirementsList,
213213
#[serde(default)]
214214
embedded: EmbeddedPackagesList,
215215
#[serde(default)]
216216
components: ComponentSpecList,
217-
#[serde(default, deserialize_with = "deserialize_env_conf")]
217+
#[serde(default)]
218218
environment: EnvOpList,
219219
}
220220

221-
impl<'de> Deserialize<'de> for InstallSpec {
221+
impl<'de> Deserialize<'de> for RawInstallSpec {
222222
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
223223
where
224224
D: serde::de::Deserializer<'de>,
225225
{
226-
deserializer.deserialize_map(InstallSpecVisitor::<InstallSpec>::default())
226+
deserializer.deserialize_map(InstallSpecVisitor::<RawInstallSpec>::default())
227227
}
228228
}
229229

230-
impl<'de> Deserialize<'de> for LintedItem<InstallSpec> {
230+
impl<'de> Deserialize<'de> for LintedItem<RawInstallSpec> {
231231
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
232232
where
233233
D: serde::de::Deserializer<'de>,
234234
{
235-
deserializer.deserialize_map(InstallSpecVisitor::<LintedItem<InstallSpec>>::default())
236-
}
237-
}
238-
239-
fn deserialize_env_conf<'de, D>(deserializer: D) -> std::result::Result<EnvOpList, D::Error>
240-
where
241-
D: serde::Deserializer<'de>,
242-
{
243-
struct EnvConfVisitor;
244-
245-
impl<'de> serde::de::Visitor<'de> for EnvConfVisitor {
246-
type Value = EnvOpList;
247-
248-
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
249-
f.write_str("an environment configuration")
250-
}
251-
252-
fn visit_seq<A>(self, mut seq: A) -> std::result::Result<Self::Value, A::Error>
253-
where
254-
A: serde::de::SeqAccess<'de>,
255-
{
256-
let mut vec = EnvOpList::default();
257-
258-
while let Some(elem) = seq.next_element::<EnvOp>()? {
259-
if vec.iter().any(|x: &EnvOp| x.kind() == OpKind::Priority)
260-
&& elem.kind() == OpKind::Priority
261-
{
262-
return Err(serde::de::Error::custom(
263-
"Multiple priority config cannot be set.",
264-
));
265-
};
266-
vec.push(elem);
267-
}
268-
Ok(vec)
269-
}
235+
deserializer.deserialize_map(InstallSpecVisitor::<LintedItem<RawInstallSpec>>::default())
270236
}
271-
deserializer.deserialize_seq(EnvConfVisitor)
272237
}
273238

274239
impl<'de, D> serde::de::Visitor<'de> for InstallSpecVisitor<D>
@@ -288,7 +253,9 @@ where
288253
while let Some(key) = map.next_key::<Stringified>()? {
289254
match key.as_str() {
290255
"requirements" => self.requirements = map.next_value::<RequirementsList>()?,
291-
"embedded" => self.embedded = map.next_value::<EmbeddedPackagesList>()?,
256+
"embedded" => {
257+
self.embedded = map.next_value::<LintedItem<EmbeddedPackagesList>>()?
258+
}
292259
"components" => self.components = map.next_value::<ComponentSpecList>()?,
293260
"environment" => self.environment = map.next_value::<EnvOpList>()?,
294261
unknown_key => {

crates/spk-schema/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ pub use environ::{
4646
};
4747
pub use error::{Error, Result};
4848
pub use input_variant::InputVariant;
49-
pub use install_spec::InstallSpec;
49+
pub use install_spec::{InstallSpec, RawInstallSpec};
5050
pub use lints::{Lint, LintedItem, Lints, UnknownKey};
5151
pub use option::{Inheritance, Opt};
5252
pub use package::{Package, PackageMut};

0 commit comments

Comments
 (0)