Skip to content

Commit 1a4aa72

Browse files
author
Nichol Yip
committed
Fixed error message when no similar configs are found.
Added linting for EnvOp Signed-off-by: Nichol Yip <[email protected]>
1 parent f4adb9f commit 1a4aa72

File tree

3 files changed

+62
-38
lines changed

3 files changed

+62
-38
lines changed

crates/spk-schema/src/environ.rs

+48-22
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Sony Pictures Imageworks, et al.
22
// SPDX-License-Identifier: Apache-2.0
33
// https://github.com/imageworks/spk
4+
use ngrammatic::CorpusBuilder;
45
use serde::{Deserialize, Serialize};
56
use spk_schema_foundation::option_map::Stringified;
67

@@ -18,7 +19,7 @@ const OP_COMMENT: &str = "comment";
1819
const OP_PREPEND: &str = "prepend";
1920
const OP_PRIORITY: &str = "priority";
2021
const OP_SET: &str = "set";
21-
const OP_NAMES: &[&str] = &[OP_APPEND, OP_COMMENT, OP_PREPEND, OP_SET];
22+
const OP_NAMES: &[&str] = &[OP_APPEND, OP_COMMENT, OP_PREPEND, OP_SET, OP_PRIORITY];
2223

2324
/// The set of operation types for use in deserialization
2425
#[derive(Copy, Clone, Debug, PartialEq)]
@@ -126,6 +127,7 @@ impl<'de> Deserialize<'de> for EnvOp {
126127
op_and_var: Option<(OpKind, ConfKind)>,
127128
value: Option<String>,
128129
separator: Option<String>,
130+
lints: Vec<String>,
129131
}
130132

131133
impl<'de> serde::de::Visitor<'de> for EnvOpVisitor {
@@ -175,7 +177,24 @@ impl<'de> Deserialize<'de> for EnvOp {
175177
"separator" => {
176178
self.separator = map.next_value::<Option<Stringified>>()?.map(|s| s.0)
177179
}
178-
_ => {
180+
unknown_config => {
181+
self.lints
182+
.push(format!("Unknown config: {unknown_config}. "));
183+
let mut corpus = CorpusBuilder::new().finish();
184+
for op_name in OP_NAMES.iter() {
185+
corpus.add_text(op_name);
186+
}
187+
188+
match corpus.search(unknown_config, 0.6).first() {
189+
Some(s) => self
190+
.lints
191+
.push(format!("The most similar config is: {}", s.text)),
192+
None => self.lints.push(format!(
193+
"No similar config found for: {}.",
194+
unknown_config
195+
)),
196+
};
197+
179198
// ignore any unknown field for the sake of
180199
// forward compatibility
181200
map.next_value::<serde::de::IgnoredAny>()?;
@@ -184,12 +203,15 @@ impl<'de> Deserialize<'de> for EnvOp {
184203
}
185204

186205
// Comments and priority configs don't have any values.
187-
let value = match self.op_and_var.as_ref().unwrap().0 {
188-
OpKind::Comment | OpKind::Priority => String::from(""),
189-
_ => self
190-
.value
191-
.take()
192-
.ok_or_else(|| serde::de::Error::missing_field("value"))?,
206+
let value = match self.op_and_var.as_ref() {
207+
Some(v) => match v.0 {
208+
OpKind::Comment | OpKind::Priority => String::from(""),
209+
_ => self
210+
.value
211+
.take()
212+
.ok_or_else(|| serde::de::Error::missing_field("value"))?,
213+
},
214+
None => String::from(""),
193215
};
194216

195217
let value = shellexpand::env(&value)
@@ -198,30 +220,34 @@ impl<'de> Deserialize<'de> for EnvOp {
198220

199221
match self.op_and_var.take() {
200222
Some((op, var)) => match op {
201-
OpKind::Prepend => Ok(EnvOp::Prepend(PrependEnv{
223+
OpKind::Prepend => Ok(EnvOp::Prepend(PrependEnv {
202224
prepend: var.get_op(),
203225
separator: self.separator.take(),
204-
value
226+
value,
205227
})),
206-
OpKind::Append => Ok(EnvOp::Append(AppendEnv{
228+
OpKind::Append => Ok(EnvOp::Append(AppendEnv {
207229
append: var.get_op(),
208230
separator: self.separator.take(),
209-
value
231+
value,
210232
})),
211-
OpKind::Set => Ok(EnvOp::Set(SetEnv{
233+
OpKind::Set => Ok(EnvOp::Set(SetEnv {
212234
set: var.get_op(),
213-
value
235+
value,
236+
})),
237+
OpKind::Comment => Ok(EnvOp::Comment(CommentEnv {
238+
comment: var.get_op(),
214239
})),
215-
OpKind::Comment => Ok(EnvOp::Comment(CommentEnv{
216-
comment: var.get_op()
240+
OpKind::Priority => Ok(EnvOp::Priority(Priority {
241+
priority: var.get_priority(),
217242
})),
218-
OpKind::Priority => Ok(EnvOp::Priority(Priority{
219-
priority: var.get_priority()
220-
}))
221243
},
222-
None => Err(serde::de::Error::custom(format!(
223-
"missing field to define operation and variable, expected one of {OP_NAMES:?}",
224-
))),
244+
None => {
245+
let mut err_msg = String::from("");
246+
for lint in self.lints.iter() {
247+
err_msg = err_msg + lint;
248+
}
249+
Err(serde::de::Error::custom(err_msg))
250+
}
225251
}
226252
}
227253
}

crates/spk-schema/src/install_spec.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -144,16 +144,15 @@ where
144144
corpus.add_text("components");
145145
corpus.add_text("environment");
146146

147-
let results = corpus.search(unknown_config, 0.6);
148-
let no_match = format!("No similar config found for: {}", unknown_config);
149-
let top_match = match results.first() {
150-
Some(s) => &s.text,
151-
None => &no_match,
147+
match corpus.search(unknown_config, 0.6).first() {
148+
Some(s) => self
149+
.lints
150+
.push(format!("The most similar config is: {}", s.text)),
151+
None => self
152+
.lints
153+
.push(format!("No similar config found for: {}.", unknown_config)),
152154
};
153155

154-
self.lints
155-
.push(format!("The most similar config is: {}", top_match));
156-
157156
// ignore any unrecognized field, but consume the value anyway
158157
// TODO: could we warn about fields that look like typos?
159158
map.next_value::<serde::de::IgnoredAny>()?;

crates/spk-schema/src/v0/spec.rs

+7-8
Original file line numberDiff line numberDiff line change
@@ -994,16 +994,15 @@ where
994994
corpus.add_text("install");
995995
corpus.add_text("api");
996996

997-
let results = corpus.search(unknown_config, 0.6);
998-
let no_match = format!("No similar config found for: {}", unknown_config);
999-
let top_match = match results.first() {
1000-
Some(s) => &s.text,
1001-
None => &no_match,
997+
match corpus.search(unknown_config, 0.6).first() {
998+
Some(s) => self
999+
.lints
1000+
.push(format!("The most similar config is: {}", s.text)),
1001+
None => self
1002+
.lints
1003+
.push(format!("No similar config found for: {}.", unknown_config)),
10021004
};
10031005

1004-
self.lints
1005-
.push(format!("The most similar config is: {}", top_match));
1006-
10071006
// ignore any unrecognized field, but consume the value anyway
10081007
// TODO: could we warn about fields that look like typos?
10091008
map.next_value::<serde::de::IgnoredAny>()?;

0 commit comments

Comments
 (0)