-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proc macro for tedge config #1936
Merged
didier-wenzek
merged 28 commits into
thin-edge:main
from
jarhodes314:feat/tedge-config-refactoring-proc
May 22, 2023
Merged
Changes from 2 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
375bc6c
POC proc macro for tedge config
jarhodes314 fb59fda
Make example realistic
jarhodes314 5e9b80d
Refactor tests and example into appropriate places
jarhodes314 f4c67a1
Ensure missing key error contains the field name
jarhodes314 1aab677
Store the key regardless of success/failure
jarhodes314 771db4c
Replace all or nothing logic in macro with library function
jarhodes314 80fe910
Add doc comments and support for read only configurations
jarhodes314 ffff8d1
Begin to use new macro in tedge_config
jarhodes314 8d59006
Migrate old accessors to new DTOs
jarhodes314 c7490e9
Fix test failures in tedge
jarhodes314 1868294
Merge remote-tracking branch 'upstream/main' into feat/tedge-config-r…
jarhodes314 86af093
Update tedge config set to use the new dto
jarhodes314 28dcee3
Migrate `tedge config unset` to new dto
jarhodes314 8cd46ad
Fix clippy warning
jarhodes314 6471e1f
Migrate `tedge config list` to new dto/reader
jarhodes314 98f4a85
Run formatter
jarhodes314 6e2e3d0
Actually support renaming
jarhodes314 6556d1c
Update references to renamed keys
jarhodes314 98e5201
Migrate `tedge cert` to new dto
jarhodes314 5b513a0
Fix integration tests and add some tests for backwards compatibility
jarhodes314 4696954
Merge remote-tracking branch 'upstream/main' into feat/tedge-config-r…
jarhodes314 5d3e4e4
Finish implementing private reader fields and optional paths
jarhodes314 81b7193
Support renaming groups
jarhodes314 ce77b22
Log only if we actually migrate tedge.toml
jarhodes314 b2ef8fa
Add more documentation and tests for the macro, fix clippy errors
jarhodes314 3b95375
Add documentation
jarhodes314 501b756
Fix unused dependency error
jarhodes314 d2063d5
Merge remote-tracking branch 'upstream/main' into feat/tedge-config-r…
jarhodes314 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "tedge_config_macros" | ||
version = "0.1.0" | ||
edition = "2021" | ||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
camino = { version = "*", features = ["serde1"] } | ||
doku = "0.21.0" | ||
once_cell = "*" | ||
serde = "*" | ||
tedge_config_macros-macro = { path = "macro" } | ||
thiserror = "1.0" | ||
tracing = "*" | ||
url = "*" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[package] | ||
name = "tedge_config_macros-impl" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
darling = "0.14.4" | ||
heck = "0.4.1" | ||
optional-error = "0.1.1" | ||
proc-macro2 = "1" | ||
quote = "1" | ||
syn = { version = "1", features = ["full", "extra-traits"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
use proc_macro2::TokenStream; | ||
use quote::quote; | ||
use syn::parse_quote_spanned; | ||
use syn::spanned::Spanned; | ||
|
||
use crate::input::FieldOrGroup; | ||
use crate::prefixed_type_name; | ||
|
||
pub fn generate(name: proc_macro2::Ident, items: &[FieldOrGroup]) -> TokenStream { | ||
let mut idents = Vec::new(); | ||
let mut tys = Vec::<syn::Type>::new(); | ||
let mut sub_dtos = Vec::new(); | ||
let mut attrs = Vec::new(); | ||
|
||
for item in items { | ||
match item { | ||
FieldOrGroup::Field(field) => { | ||
if !field.dto().skip && field.read_only().is_none() { | ||
idents.push(field.ident()); | ||
tys.push({ | ||
let ty = field.ty(); | ||
parse_quote_spanned!(ty.span()=> Option<#ty>) | ||
}); | ||
sub_dtos.push(None); | ||
attrs.push(field.attrs().iter().filter(is_preserved).collect()); | ||
} | ||
} | ||
FieldOrGroup::Group(group) => { | ||
if !group.dto.skip { | ||
let sub_dto_name = prefixed_type_name(&name, group); | ||
idents.push(&group.ident); | ||
tys.push(parse_quote_spanned!(group.ident.span()=> #sub_dto_name)); | ||
sub_dtos.push(Some(generate(sub_dto_name, &group.contents))); | ||
attrs.push(Vec::new()); | ||
} | ||
} | ||
} | ||
} | ||
|
||
quote! { | ||
#[derive(Debug, Default, ::serde::Deserialize, ::serde::Serialize)] | ||
#[non_exhaustive] | ||
pub struct #name { | ||
#( | ||
#(#attrs)* | ||
#idents: #tys, | ||
)* | ||
} | ||
|
||
#(#sub_dtos)* | ||
} | ||
} | ||
|
||
fn is_preserved(attr: &&syn::Attribute) -> bool { | ||
match attr.parse_meta() { | ||
// Maybe cfg is useful. Certainly seems sensible to preserve it | ||
Ok(syn::Meta::List(list)) => list.path.is_ident("serde") || list.path.is_ident("cfg"), | ||
Ok(syn::Meta::NameValue(nv)) => nv.path.is_ident("doc"), | ||
_ => false, | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use syn::parse_quote; | ||
|
||
use super::*; | ||
|
||
#[test] | ||
fn doc_comments_are_preserved() { | ||
assert!(is_preserved(&&parse_quote!( | ||
/// Test | ||
))) | ||
} | ||
|
||
#[test] | ||
fn serde_attributes_are_preserved() { | ||
assert!(is_preserved(&&parse_quote!( | ||
#[serde(rename = "something")] | ||
))) | ||
} | ||
|
||
#[test] | ||
fn unrecognised_attributes_are_not_preserved() { | ||
assert!(!is_preserved(&&parse_quote!( | ||
#[unknown_crate(unknown_bool)] | ||
))) | ||
} | ||
|
||
#[test] | ||
fn unrecognised_attributes_of_the_wrong_type_are_not_preserved() { | ||
assert!(!is_preserved(&&parse_quote!( | ||
#[unknown_attribute = "some value"] | ||
))) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
use optional_error::OptionalError; | ||
|
||
pub fn combine_errors<T>( | ||
items: impl Iterator<Item = Result<T, syn::Error>>, | ||
) -> Result<Vec<T>, syn::Error> { | ||
let mut error = OptionalError::default(); | ||
let mut successful_values = Vec::new(); | ||
for item in items { | ||
match item { | ||
Ok(value) => successful_values.push(value), | ||
Err(e) => error.combine(e), | ||
} | ||
} | ||
error.try_throw().and(Ok(successful_values)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
mod parse; | ||
mod validate; | ||
|
||
pub use validate::*; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't help but remember Parse, don’t validate ;-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ironically, that's pretty much what validate is doing. It could do with clearer naming to distinguish between "things that can be parsed with syn and darling" and "things that are meaningful for the rest of the application, after e.g. converting boolean flags into enum discriminants" (which is currently in the validate module, even though it's following the idea of "Parse, don't validate").