mod.rs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #![allow(unused_imports)]
  2. #![allow(unused_attributes)]
  3. #![allow(dead_code)]
  4. mod ast;
  5. mod proto_gen;
  6. mod proto_info;
  7. mod template;
  8. use crate::code_gen::util::path_string_with_component;
  9. use itertools::Itertools;
  10. use log::info;
  11. pub use proto_gen::*;
  12. pub use proto_info::*;
  13. use std::fs::File;
  14. use std::io::Write;
  15. use std::path::{Path, PathBuf};
  16. use std::process::Command;
  17. use walkdir::WalkDir;
  18. pub fn gen(crate_name: &str) {
  19. let crate_path = std::fs::canonicalize(".").unwrap().as_path().display().to_string();
  20. // 1. generate the proto files to proto_file_dir
  21. #[cfg(feature = "proto_gen")]
  22. let proto_crates = gen_proto_files(crate_name, &crate_path);
  23. for proto_crate in proto_crates {
  24. let mut proto_file_paths = vec![];
  25. let mut file_names = vec![];
  26. let proto_file_output_path = proto_crate.proto_output_path().to_str().unwrap().to_string();
  27. let protobuf_output_path = proto_crate.protobuf_crate_path().to_str().unwrap().to_string();
  28. for (path, file_name) in WalkDir::new(&proto_file_output_path)
  29. .into_iter()
  30. .filter_map(|e| e.ok())
  31. .map(|e| {
  32. let path = e.path().to_str().unwrap().to_string();
  33. let file_name = e.path().file_stem().unwrap().to_str().unwrap().to_string();
  34. (path, file_name)
  35. })
  36. {
  37. if path.ends_with(".proto") {
  38. // https://stackoverflow.com/questions/49077147/how-can-i-force-build-rs-to-run-again-without-cleaning-my-whole-project
  39. println!("cargo:rerun-if-changed={}", path);
  40. proto_file_paths.push(path);
  41. file_names.push(file_name);
  42. }
  43. }
  44. let protoc_bin_path = protoc_bin_vendored::protoc_bin_path().unwrap();
  45. // 2. generate the protobuf files(Dart)
  46. #[cfg(feature = "dart")]
  47. generate_dart_protobuf_files(
  48. crate_name,
  49. &proto_file_output_path,
  50. &proto_file_paths,
  51. &file_names,
  52. &protoc_bin_path,
  53. );
  54. // 3. generate the protobuf files(Rust)
  55. generate_rust_protobuf_files(
  56. &protoc_bin_path,
  57. &proto_file_paths,
  58. &proto_file_output_path,
  59. &protobuf_output_path,
  60. );
  61. }
  62. }
  63. fn generate_rust_protobuf_files(
  64. protoc_bin_path: &Path,
  65. proto_file_paths: &[String],
  66. proto_file_output_path: &str,
  67. protobuf_output_path: &str,
  68. ) {
  69. protoc_rust::Codegen::new()
  70. .out_dir(protobuf_output_path)
  71. .protoc_path(protoc_bin_path)
  72. .inputs(proto_file_paths)
  73. .include(proto_file_output_path)
  74. .run()
  75. .expect("Running rust protoc failed.");
  76. }
  77. #[cfg(feature = "dart")]
  78. fn generate_dart_protobuf_files(
  79. name: &str,
  80. proto_file_output_path: &str,
  81. paths: &Vec<String>,
  82. file_names: &Vec<String>,
  83. protoc_bin_path: &PathBuf,
  84. ) {
  85. if std::env::var("CARGO_MAKE_WORKING_DIRECTORY").is_err() {
  86. log::warn!("CARGO_MAKE_WORKING_DIRECTORY was not set, skip generate dart pb");
  87. return;
  88. }
  89. if std::env::var("FLUTTER_FLOWY_SDK_PATH").is_err() {
  90. log::warn!("FLUTTER_FLOWY_SDK_PATH was not set, skip generate dart pb");
  91. return;
  92. }
  93. let mut output = PathBuf::new();
  94. output.push(std::env::var("CARGO_MAKE_WORKING_DIRECTORY").unwrap());
  95. output.push(std::env::var("FLUTTER_FLOWY_SDK_PATH").unwrap());
  96. output.push("lib");
  97. output.push("protobuf");
  98. output.push(name);
  99. if !output.as_path().exists() {
  100. std::fs::create_dir_all(&output).unwrap();
  101. }
  102. check_pb_dart_plugin();
  103. let protoc_bin_path = protoc_bin_path.to_str().unwrap().to_owned();
  104. paths.iter().for_each(|path| {
  105. let result = cmd_lib::run_cmd! {
  106. ${protoc_bin_path} --dart_out=${output} --proto_path=${proto_file_output_path} ${path}
  107. };
  108. if result.is_err() {
  109. panic!("Generate dart pb file failed with: {}, {:?}", path, result)
  110. };
  111. });
  112. let protobuf_dart = path_string_with_component(&output, vec!["protobuf.dart"]);
  113. match std::fs::OpenOptions::new()
  114. .create(true)
  115. .write(true)
  116. .append(false)
  117. .truncate(true)
  118. .open(&protobuf_dart)
  119. {
  120. Ok(ref mut file) => {
  121. let mut export = String::new();
  122. export.push_str("// Auto-generated, do not edit \n");
  123. for file_name in file_names {
  124. let c = format!("export './{}.pb.dart';\n", file_name);
  125. export.push_str(c.as_ref());
  126. }
  127. file.write_all(export.as_bytes()).unwrap();
  128. File::flush(file).unwrap();
  129. }
  130. Err(err) => {
  131. panic!("Failed to open file: {}", err);
  132. }
  133. }
  134. }
  135. pub fn check_pb_dart_plugin() {
  136. if cfg!(target_os = "windows") {
  137. //Command::new("cmd")
  138. // .arg("/C")
  139. // .arg(cmd)
  140. // .status()
  141. // .expect("failed to execute process");
  142. //panic!("{}", format!("\n❌ The protoc-gen-dart was not installed correctly."))
  143. } else {
  144. let exit_result = Command::new("sh")
  145. .arg("-c")
  146. .arg("command -v protoc-gen-dart")
  147. .status()
  148. .expect("failed to execute process");
  149. if !exit_result.success() {
  150. let mut msg = "\n❌ Can't find protoc-gen-dart in $PATH:\n".to_string();
  151. let output = Command::new("sh").arg("-c").arg("echo $PATH").output();
  152. let paths = String::from_utf8(output.unwrap().stdout)
  153. .unwrap()
  154. .split(':')
  155. .map(|s| s.to_string())
  156. .collect::<Vec<String>>();
  157. paths.iter().for_each(|s| msg.push_str(&format!("{}\n", s)));
  158. if let Ok(output) = Command::new("sh").arg("-c").arg("which protoc-gen-dart").output() {
  159. msg.push_str(&format!(
  160. "Installed protoc-gen-dart path: {:?}\n",
  161. String::from_utf8(output.stdout).unwrap()
  162. ));
  163. }
  164. msg.push_str("✅ You can fix that by adding:");
  165. msg.push_str("\n\texport PATH=\"$PATH\":\"$HOME/.pub-cache/bin\"\n");
  166. msg.push_str("to your shell's config file.(.bashrc, .bash, .profile, .zshrc etc.)");
  167. panic!("{}", msg)
  168. }
  169. }
  170. }
  171. #[cfg(feature = "proto_gen")]
  172. fn gen_proto_files(crate_name: &str, crate_path: &str) -> Vec<ProtobufCrate> {
  173. let crate_context = ProtoGenerator::gen(crate_name, crate_path);
  174. let proto_crates = crate_context
  175. .iter()
  176. .map(|info| info.protobuf_crate.clone())
  177. .collect::<Vec<_>>();
  178. crate_context.into_iter().flat_map(|info| info.files).for_each(|file| {
  179. println!("cargo:rerun-if-changed={}", file.file_path);
  180. });
  181. proto_crates
  182. }