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.

218 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. //! This module is automatically generated by build.rs.
  50. use super::*;
  51. "##
  52. .to_string();
  53. 'file_loop: for (filename, ident) in filenames {
  54. println!("cargo:rerun-if-changed={}", filename);
  55. let mut file = File::open(&filename)
  56. .unwrap_or_else(|err| panic!("Unable to open file `{}` {}", filename, err));
  57. let mut src = String::new();
  58. file.read_to_string(&mut src).expect("Unable to read file");
  59. let syntax = syn::parse_file(&src).expect("Unable to parse file");
  60. if syntax.items.iter().any(|item| {
  61. if let syn::Item::Struct(s) = item {
  62. if s.ident.to_string().ends_with("Override") {
  63. println!("ident {} exists, skipping {}", ident, filename);
  64. return true;
  65. }
  66. }
  67. false
  68. }) {
  69. continue 'file_loop;
  70. }
  71. for item in syntax.items.iter() {
  72. if let syn::Item::Struct(s) = item {
  73. if s.ident != ident {
  74. continue;
  75. }
  76. if s.ident.to_string().ends_with("Override") {
  77. unreachable!();
  78. }
  79. let override_ident: syn::Ident = format_ident!("{}Override", s.ident);
  80. let mut field_tokentrees = vec![];
  81. let mut attrs_tokens = vec![];
  82. for attr in &s.attrs {
  83. if let Ok(syn::Meta::List(ml)) = attr.parse_meta() {
  84. if ml.path.get_ident().is_some() && ml.path.get_ident().unwrap() == "cfg" {
  85. attrs_tokens.push(attr);
  86. }
  87. }
  88. }
  89. let mut field_idents = vec![];
  90. for f in &s.fields {
  91. let ident = &f.ident;
  92. let ty = &f.ty;
  93. let attrs = f
  94. .attrs
  95. .iter()
  96. .filter_map(|f| {
  97. let mut new_attr = f.clone();
  98. if let quote::__private::TokenTree::Group(g) =
  99. f.tokens.clone().into_iter().next().unwrap()
  100. {
  101. let attr_inner_value = f.tokens.to_string();
  102. if !attr_inner_value.starts_with("( default")
  103. && !attr_inner_value.starts_with("( default =")
  104. && !attr_inner_value.starts_with("(default")
  105. && !attr_inner_value.starts_with("(default =")
  106. {
  107. return Some(new_attr);
  108. }
  109. if attr_inner_value.starts_with("( default =")
  110. || attr_inner_value.starts_with("(default =")
  111. {
  112. let rest = g.stream().into_iter().skip(4);
  113. new_attr.tokens = quote! { ( #(#rest)*) };
  114. match new_attr.tokens.to_string().as_str() {
  115. "( )" | "()" => {
  116. return None;
  117. }
  118. _ => {}
  119. }
  120. } else if attr_inner_value.starts_with("( default")
  121. || attr_inner_value.starts_with("(default")
  122. {
  123. let rest = g.stream().into_iter().skip(2);
  124. new_attr.tokens = quote! { ( #(#rest)*) };
  125. match new_attr.tokens.to_string().as_str() {
  126. "( )" | "()" => {
  127. return None;
  128. }
  129. _ => {}
  130. }
  131. }
  132. }
  133. Some(new_attr)
  134. })
  135. .collect::<Vec<_>>();
  136. let t = quote! {
  137. #(#attrs)*
  138. #[serde(default)]
  139. pub #ident : Option<#ty>
  140. };
  141. field_idents.push(ident);
  142. field_tokentrees.push(t);
  143. }
  144. //let fields = &s.fields;
  145. let literal_struct = quote! {
  146. #(#attrs_tokens)*
  147. #[derive(Debug, Serialize, Deserialize, Clone)]
  148. #[serde(deny_unknown_fields)]
  149. pub struct #override_ident {
  150. #(#field_tokentrees),*
  151. }
  152. #(#attrs_tokens)*
  153. impl Default for #override_ident {
  154. fn default() -> Self {
  155. #override_ident {
  156. #(#field_idents: None),*
  157. }
  158. }
  159. }
  160. };
  161. output_string.push_str(&literal_struct.to_string());
  162. output_string.push_str("\n\n");
  163. }
  164. }
  165. }
  166. let rustfmt_closure = move |output_file: &mut File, output_string: &str| {
  167. let mut rustfmt = Command::new("rustfmt")
  168. .stdin(Stdio::piped())
  169. .stdout(Stdio::piped())
  170. .stderr(Stdio::piped())
  171. .spawn()
  172. .map_err(|err| format!("failed to execute rustfmt {}", err))?;
  173. {
  174. // limited borrow of stdin
  175. let stdin = rustfmt
  176. .stdin
  177. .as_mut()
  178. .ok_or("failed to get rustfmt stdin")?;
  179. stdin
  180. .write_all(output_string.as_bytes())
  181. .map_err(|err| format!("failed to write to rustfmt stdin {}", err))?;
  182. }
  183. let output = rustfmt
  184. .wait_with_output()
  185. .map_err(|err| format!("failed to wait on rustfmt child {}", err))?;
  186. if !output.stderr.is_empty() {
  187. return Err(format!(
  188. "rustfmt invocation replied with: `{}`",
  189. String::from_utf8_lossy(&output.stderr)
  190. ));
  191. }
  192. output_file
  193. .write_all(&output.stdout)
  194. .expect("failed to write to src/conf/overrides.rs");
  195. Ok(())
  196. };
  197. if let Err(err) = rustfmt_closure(&mut output_file, &output_string) {
  198. println!("Tried rustfmt on overrides module, got error: {}", err);
  199. output_file.write_all(output_string.as_bytes()).unwrap();
  200. }
  201. }