mod.rs 6.3 KB

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