You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
8.5 KiB

  1. /*
  2. * meli -
  3. *
  4. * Copyright Manos Pitsidianakis
  5. *
  6. * This file is part of meli.
  7. *
  8. * meli is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * meli is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with meli. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. use std::fs::File;
  22. use std::io::prelude::*;
  23. use std::process::{Command, Stdio};
  24. use quote::{format_ident, quote};
  25. // Write ConfigStructOverride to overrides.rs
  26. pub fn override_derive(filenames: &[(&str, &str)]) {
  27. let mut output_file =
  28. File::create("src/conf/overrides.rs").expect("Unable to open output file");
  29. let mut output_string = r##"/*
  30. * meli - conf/overrides.rs
  31. *
  32. * Copyright 2020 Manos Pitsidianakis
  33. *
  34. * This file is part of meli.
  35. *
  36. * meli is free software: you can redistribute it and/or modify
  37. * it under the terms of the GNU General Public License as published by
  38. * the Free Software Foundation, either version 3 of the License, or
  39. * (at your option) any later version.
  40. *
  41. * meli is distributed in the hope that it will be useful,
  42. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  43. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  44. * GNU General Public License for more details.
  45. *
  46. * You should have received a copy of the GNU General Public License
  47. * along with meli. If not, see <http://www.gnu.org/licenses/>.
  48. */
  49. #![allow(clippy::derivable_impls)]
  50. //! This module is automatically generated by config_macros.rs.
  51. use super::*;
  52. "##
  53. .to_string();
  54. 'file_loop: for (filename, ident) in filenames {
  55. println!("cargo:rerun-if-changed={}", filename);
  56. let mut file = File::open(&filename)
  57. .unwrap_or_else(|err| panic!("Unable to open file `{}` {}", filename, err));
  58. let mut src = String::new();
  59. file.read_to_string(&mut src).expect("Unable to read file");
  60. let syntax = syn::parse_file(&src).expect("Unable to parse file");
  61. if syntax.items.iter().any(|item| {
  62. if let syn::Item::Struct(s) = item {
  63. if s.ident.to_string().ends_with("Override") {
  64. println!("ident {} exists, skipping {}", ident, filename);
  65. return true;
  66. }
  67. }
  68. false
  69. }) {
  70. continue 'file_loop;
  71. }
  72. for item in syntax.items.iter() {
  73. if let syn::Item::Struct(s) = item {
  74. if s.ident != ident {
  75. continue;
  76. }
  77. if s.ident.to_string().ends_with("Override") {
  78. unreachable!();
  79. }
  80. let override_ident: syn::Ident = format_ident!("{}Override", s.ident);
  81. let mut field_tokentrees = vec![];
  82. let mut attrs_tokens = vec![];
  83. for attr in &s.attrs {
  84. if let Ok(syn::Meta::List(ml)) = attr.parse_meta() {
  85. if ml.path.get_ident().is_some() && ml.path.get_ident().unwrap() == "cfg" {
  86. attrs_tokens.push(attr);
  87. }
  88. }
  89. }
  90. let mut field_idents = vec![];
  91. for f in &s.fields {
  92. let ident = &f.ident;
  93. let ty = &f.ty;
  94. let attrs = f
  95. .attrs
  96. .iter()
  97. .filter_map(|f| {
  98. let mut new_attr = f.clone();
  99. if let quote::__private::TokenTree::Group(g) =
  100. f.tokens.clone().into_iter().next().unwrap()
  101. {
  102. let attr_inner_value = f.tokens.to_string();
  103. if !attr_inner_value.starts_with("( default")
  104. && !attr_inner_value.starts_with("( default =")
  105. && !attr_inner_value.starts_with("(default")
  106. && !attr_inner_value.starts_with("(default =")
  107. {
  108. return Some(new_attr);
  109. }
  110. if attr_inner_value.starts_with("( default =")
  111. || attr_inner_value.starts_with("(default =")
  112. {
  113. let rest = g.stream().into_iter().skip(4);
  114. new_attr.tokens = quote! { ( #(#rest)*) };
  115. match new_attr.tokens.to_string().as_str() {
  116. "( )" | "()" => {
  117. return None;
  118. }
  119. _ => {}
  120. }
  121. } else if attr_inner_value.starts_with("( default")
  122. || attr_inner_value.starts_with("(default")
  123. {
  124. let rest = g.stream().into_iter().skip(2);
  125. new_attr.tokens = quote! { ( #(#rest)*) };
  126. match new_attr.tokens.to_string().as_str() {
  127. "( )" | "()" => {
  128. return None;
  129. }
  130. _ => {}
  131. }
  132. }
  133. }
  134. Some(new_attr)
  135. })
  136. .collect::<Vec<_>>();
  137. let t = quote! {
  138. #(#attrs)*
  139. #[serde(default)]
  140. pub #ident : Option<#ty>
  141. };
  142. field_idents.push(ident);
  143. field_tokentrees.push(t);
  144. }
  145. //let fields = &s.fields;
  146. let literal_struct = quote! {
  147. #(#attrs_tokens)*
  148. #[derive(Debug, Serialize, Deserialize, Clone)]
  149. #[serde(deny_unknown_fields)]
  150. pub struct #override_ident {
  151. #(#field_tokentrees),*
  152. }
  153. #(#attrs_tokens)*
  154. impl Default for #override_ident {
  155. fn default() -> Self {
  156. #override_ident {
  157. #(#field_idents: None),*
  158. }
  159. }
  160. }
  161. };
  162. output_string.push_str(&literal_struct.to_string());
  163. output_string.push_str("\n\n");
  164. }
  165. }
  166. }
  167. let rustfmt_closure = move |output_file: &mut File, output_string: &str| {
  168. let mut rustfmt = Command::new("rustfmt")
  169. .stdin(Stdio::piped())
  170. .stdout(Stdio::piped())
  171. .stderr(Stdio::piped())
  172. .spawn()
  173. .map_err(|err| format!("failed to execute rustfmt {}", err))?;
  174. {
  175. // limited borrow of stdin
  176. let stdin = rustfmt
  177. .stdin
  178. .as_mut()
  179. .ok_or("failed to get rustfmt stdin")?;
  180. stdin
  181. .write_all(output_string.as_bytes())
  182. .map_err(|err| format!("failed to write to rustfmt stdin {}", err))?;
  183. }
  184. let output = rustfmt
  185. .wait_with_output()
  186. .map_err(|err| format!("failed to wait on rustfmt child {}", err))?;
  187. if !output.stderr.is_empty() {
  188. return Err(format!(
  189. "rustfmt invocation replied with: `{}`",
  190. String::from_utf8_lossy(&output.stderr)
  191. ));
  192. }
  193. output_file
  194. .write_all(&output.stdout)
  195. .expect("failed to write to src/conf/overrides.rs");
  196. Ok(())
  197. };
  198. if let Err(err) = rustfmt_closure(&mut output_file, &output_string) {
  199. println!("Tried rustfmt on overrides module, got error: {}", err);
  200. output_file.write_all(output_string.as_bytes()).unwrap();
  201. }
  202. }