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.
 
 
 
 

209 lines
8.0 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 field_idents = vec![];
  82. for f in &s.fields {
  83. let ident = &f.ident;
  84. let ty = &f.ty;
  85. let attrs = f
  86. .attrs
  87. .iter()
  88. .filter_map(|f| {
  89. let mut new_attr = f.clone();
  90. if let quote::__private::TokenTree::Group(g) =
  91. f.tokens.clone().into_iter().next().unwrap()
  92. {
  93. let attr_inner_value = f.tokens.to_string();
  94. if !attr_inner_value.starts_with("( default")
  95. && !attr_inner_value.starts_with("( default =")
  96. && !attr_inner_value.starts_with("(default")
  97. && !attr_inner_value.starts_with("(default =")
  98. {
  99. return Some(new_attr);
  100. }
  101. if attr_inner_value.starts_with("( default =")
  102. || attr_inner_value.starts_with("(default =")
  103. {
  104. let rest = g.stream().into_iter().skip(4);
  105. new_attr.tokens = quote! { ( #(#rest)*) };
  106. match new_attr.tokens.to_string().as_str() {
  107. "( )" | "()" => {
  108. return None;
  109. }
  110. _ => {}
  111. }
  112. } else if attr_inner_value.starts_with("( default")
  113. || attr_inner_value.starts_with("(default")
  114. {
  115. let rest = g.stream().into_iter().skip(2);
  116. new_attr.tokens = quote! { ( #(#rest)*) };
  117. match new_attr.tokens.to_string().as_str() {
  118. "( )" | "()" => {
  119. return None;
  120. }
  121. _ => {}
  122. }
  123. }
  124. }
  125. Some(new_attr)
  126. })
  127. .collect::<Vec<_>>();
  128. let t = quote! {
  129. #(#attrs)*
  130. #[serde(default)]
  131. pub #ident : Option<#ty>
  132. };
  133. field_idents.push(ident);
  134. field_tokentrees.push(t);
  135. }
  136. //let fields = &s.fields;
  137. let literal_struct = quote! {
  138. #[derive(Debug, Serialize, Deserialize, Clone)]
  139. #[serde(deny_unknown_fields)]
  140. pub struct #override_ident {
  141. #(#field_tokentrees),*
  142. }
  143. impl Default for #override_ident {
  144. fn default() -> Self {
  145. #override_ident {
  146. #(#field_idents: None),*
  147. }
  148. }
  149. }
  150. };
  151. output_string.push_str(&literal_struct.to_string());
  152. output_string.push_str("\n\n");
  153. }
  154. }
  155. }
  156. let rustfmt_closure = move |output_file: &mut File, output_string: &str| {
  157. let mut rustfmt = Command::new("rustfmt")
  158. .stdin(Stdio::piped())
  159. .stdout(Stdio::piped())
  160. .stderr(Stdio::piped())
  161. .spawn()
  162. .map_err(|err| format!("failed to execute rustfmt {}", err))?;
  163. {
  164. // limited borrow of stdin
  165. let stdin = rustfmt
  166. .stdin
  167. .as_mut()
  168. .ok_or("failed to get rustfmt stdin")?;
  169. stdin
  170. .write_all(output_string.as_bytes())
  171. .map_err(|err| format!("failed to write to rustfmt stdin {}", err))?;
  172. }
  173. let output = rustfmt
  174. .wait_with_output()
  175. .map_err(|err| format!("failed to wait on rustfmt child {}", err))?;
  176. if !output.stderr.is_empty() {
  177. return Err(format!(
  178. "rustfmt invocation replied with: `{}`",
  179. String::from_utf8_lossy(&output.stderr)
  180. ));
  181. }
  182. output_file
  183. .write_all(&output.stdout)
  184. .expect("failed to write to src/conf/overrides.rs");
  185. Ok(())
  186. };
  187. if let Err(err) = rustfmt_closure(&mut output_file, &output_string) {
  188. println!("Tried rustfmt on overrides module, got error: {}", err);
  189. output_file.write_all(output_string.as_bytes()).unwrap();
  190. }
  191. }