diff options
-rw-r--r-- | fondant_derive/src/lib.rs | 73 |
1 files changed, 41 insertions, 32 deletions
diff --git a/fondant_derive/src/lib.rs b/fondant_derive/src/lib.rs index 946c130..0c66d62 100644 --- a/fondant_derive/src/lib.rs +++ b/fondant_derive/src/lib.rs | |||
@@ -1,16 +1,15 @@ | |||
1 | extern crate proc_macro; | 1 | extern crate proc_macro; |
2 | 2 | ||
3 | use ::std::ffi::{OsStr, OsString}; | 3 | use ::std::ffi::{OsStr, OsString}; |
4 | use ::std::path::{Path, PathBuf}; | 4 | use ::std::path::Path; |
5 | use directories::ProjectDirs; | ||
6 | use proc_macro::TokenStream; | 5 | use proc_macro::TokenStream; |
7 | use proc_macro2::Span; | 6 | use proc_macro2::Span; |
8 | use quote::quote; | 7 | use quote::quote; |
9 | use syn::{parse_macro_input, DeriveInput, Error, Ident, Lit, Meta, MetaNameValue, Result}; | 8 | use syn::{parse_macro_input, DeriveInput, Ident, Lit, Meta, MetaNameValue}; |
10 | 9 | ||
11 | #[derive(Debug, Default)] | 10 | #[derive(Debug, Default)] |
12 | struct ConfigPath { | 11 | struct ConfigPath { |
13 | parent: Option<PathBuf>, | 12 | parent: String, |
14 | filename: Option<OsString>, | 13 | filename: Option<OsString>, |
15 | extension: Option<OsString>, | 14 | extension: Option<OsString>, |
16 | } | 15 | } |
@@ -33,13 +32,9 @@ fn extract_attributes(ast: &DeriveInput) -> ConfigPath { | |||
33 | if let Lit::Str(f) = lit { | 32 | if let Lit::Str(f) = lit { |
34 | let f = f.value(); | 33 | let f = f.value(); |
35 | let fp = Path::new(&f); | 34 | let fp = Path::new(&f); |
36 | let blank = Path::new(""); | 35 | let parent = fp.parent().unwrap_or(Path::new("")); |
37 | let parent = match fp.parent() { | ||
38 | Some(blank) => None, | ||
39 | other => other, | ||
40 | }; | ||
41 | return ConfigPath { | 36 | return ConfigPath { |
42 | parent: parent.map(Path::to_path_buf), | 37 | parent: parent.to_str().unwrap().into(), |
43 | filename: fp.file_stem().map(OsStr::to_os_string), | 38 | filename: fp.file_stem().map(OsStr::to_os_string), |
44 | extension: fp.extension().map(OsStr::to_os_string), | 39 | extension: fp.extension().map(OsStr::to_os_string), |
45 | }; | 40 | }; |
@@ -80,42 +75,53 @@ fn gen_impl(ast: &DeriveInput, cfg_path: ConfigPath) -> TokenStream { | |||
80 | 75 | ||
81 | let filename = cfg_path | 76 | let filename = cfg_path |
82 | .filename | 77 | .filename |
83 | .unwrap_or(OsStr::new("config").to_os_string()); | 78 | .unwrap_or(OsStr::new("config").to_os_string()) |
79 | .into_string() | ||
80 | .unwrap(); | ||
81 | |||
84 | let filetype = cfg_path | 82 | let filetype = cfg_path |
85 | .extension | 83 | .extension |
86 | .unwrap_or(OsStr::new("toml").to_os_string()); | 84 | .unwrap_or(OsStr::new("toml").to_os_string()) |
87 | |||
88 | let filename = filename.into_string().unwrap(); | ||
89 | let filetype = filetype.into_string().unwrap(); | ||
90 | |||
91 | let pkg_name = env!("CARGO_PKG_NAME"); | ||
92 | let project = ProjectDirs::from("rs", "", pkg_name).unwrap(); | ||
93 | let default_dir = project.config_dir(); | ||
94 | let config_dir = cfg_path.parent.as_deref().unwrap_or(default_dir); | ||
95 | |||
96 | let tip = Path::new(&filename).with_extension(&filetype); | ||
97 | let config_file = [config_dir, tip.as_ref()] | ||
98 | .iter() | ||
99 | .collect::<PathBuf>() | ||
100 | .into_os_string() | ||
101 | .into_string() | 85 | .into_string() |
102 | .unwrap(); | 86 | .unwrap(); |
103 | let parent: String = config_dir.to_str().unwrap().into(); | 87 | |
88 | let parent = cfg_path.parent; | ||
104 | 89 | ||
105 | let (ser, ser_fn) = pick_serializer(&filetype); | 90 | let (ser, ser_fn) = pick_serializer(&filetype); |
106 | 91 | ||
107 | let gen = quote! { | 92 | let includes = quote! { |
108 | use ::fondant::{Configure, ProjectDirs, toml, serde_json, serde_yaml, FondantError}; | 93 | use ::fondant::*; |
109 | use ::std::option::Option; | 94 | use ::std::option::Option; |
110 | use ::std::fs::{self, File, OpenOptions}; | 95 | use ::std::fs::{self, File, OpenOptions}; |
111 | use ::std::io::prelude::*; | 96 | use ::std::io::prelude::*; |
112 | use ::std::io::{ ErrorKind::NotFound, Write }; | 97 | use ::std::io::{ ErrorKind::NotFound, Write }; |
113 | use ::std::ffi::{OsStr, OsString}; | 98 | use ::std::ffi::{OsStr, OsString}; |
114 | use ::std::path::{Path, PathBuf}; | 99 | use ::std::path::{Path, PathBuf}; |
100 | }; | ||
115 | 101 | ||
102 | let load_paths = quote! { | ||
103 | let pkg_name = env!("CARGO_PKG_NAME"); | ||
104 | let project = ProjectDirs::from("rs", "", pkg_name).unwrap(); | ||
105 | let default_dir: String = project.config_dir().to_str().unwrap().into(); | ||
106 | |||
107 | let d = if #parent != "" { #parent.into() } else { default_dir }; | ||
108 | let config_dir: String = expand_tilde(d) | ||
109 | .as_path() | ||
110 | .to_str() | ||
111 | .unwrap() | ||
112 | .into(); | ||
113 | |||
114 | let tip = Path::new(&#filename).with_extension(&#filetype); | ||
115 | let mut config_file = PathBuf::from(&config_dir); | ||
116 | config_file.push(tip); | ||
117 | }; | ||
118 | |||
119 | let gen = quote! { | ||
120 | #includes | ||
116 | impl Configure for #struct_ident { | 121 | impl Configure for #struct_ident { |
117 | fn load() -> Result<#struct_ident, FondantError> { | 122 | fn load() -> Result<#struct_ident, FondantError> { |
118 | match File::open(&#config_file) { | 123 | #load_paths |
124 | match File::open(&config_file) { | ||
119 | Ok(mut cfg) => { | 125 | Ok(mut cfg) => { |
120 | let mut cfg_data = String::new(); | 126 | let mut cfg_data = String::new(); |
121 | cfg.read_to_string(&mut cfg_data); | 127 | cfg.read_to_string(&mut cfg_data); |
@@ -125,7 +131,9 @@ fn gen_impl(ast: &DeriveInput, cfg_path: ConfigPath) -> TokenStream { | |||
125 | return Ok(config); | 131 | return Ok(config); |
126 | }, | 132 | }, |
127 | Err(ref e) if e.kind() == NotFound => { | 133 | Err(ref e) if e.kind() == NotFound => { |
128 | fs::create_dir_all(#parent).map_err(FondantError::DirCreateErr)?; | 134 | if !Path::new(&config_dir).is_dir() { |
135 | fs::create_dir_all(config_dir).map_err(FondantError::DirCreateErr)?; | ||
136 | } | ||
129 | let default_impl = #struct_ident::default(); | 137 | let default_impl = #struct_ident::default(); |
130 | Configure::store(&default_impl)?; | 138 | Configure::store(&default_impl)?; |
131 | return Ok(default_impl); | 139 | return Ok(default_impl); |
@@ -134,11 +142,12 @@ fn gen_impl(ast: &DeriveInput, cfg_path: ConfigPath) -> TokenStream { | |||
134 | }; | 142 | }; |
135 | } | 143 | } |
136 | fn store(&self) -> Result<(), FondantError> { | 144 | fn store(&self) -> Result<(), FondantError> { |
145 | #load_paths | ||
137 | let mut f = OpenOptions::new() | 146 | let mut f = OpenOptions::new() |
138 | .write(true) | 147 | .write(true) |
139 | .create(true) | 148 | .create(true) |
140 | .truncate(true) | 149 | .truncate(true) |
141 | .open(#config_file) | 150 | .open(config_file) |
142 | .map_err(|_| FondantError::FileOpenError)?; | 151 | .map_err(|_| FondantError::FileOpenError)?; |
143 | 152 | ||
144 | let s = #ser::#ser_fn(self).map_err(|_| FondantError::ConfigParseError)?; | 153 | let s = #ser::#ser_fn(self).map_err(|_| FondantError::ConfigParseError)?; |