util.rs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. use console::Style;
  2. use similar::{ChangeTag, TextDiff};
  3. use std::path::{Path, PathBuf};
  4. use std::str::FromStr;
  5. use std::{
  6. fs::{File, OpenOptions},
  7. io::{Read, Write},
  8. };
  9. use tera::Tera;
  10. use walkdir::WalkDir;
  11. pub fn read_file(path: &str) -> Option<String> {
  12. let mut file = File::open(path).unwrap_or_else(|_| panic!("Unable to open file at {}", path));
  13. let mut content = String::new();
  14. match file.read_to_string(&mut content) {
  15. Ok(_) => Some(content),
  16. Err(e) => {
  17. log::error!("{}, with error: {:?}", path, e);
  18. Some("".to_string())
  19. },
  20. }
  21. }
  22. pub fn save_content_to_file_with_diff_prompt(content: &str, output_file: &str) {
  23. if Path::new(output_file).exists() {
  24. let old_content = read_file(output_file).unwrap();
  25. let new_content = content.to_owned();
  26. let write_to_file = || match OpenOptions::new()
  27. .create(true)
  28. .write(true)
  29. .append(false)
  30. .truncate(true)
  31. .open(output_file)
  32. {
  33. Ok(ref mut file) => {
  34. file.write_all(new_content.as_bytes()).unwrap();
  35. },
  36. Err(err) => {
  37. panic!("Failed to open log file: {}", err);
  38. },
  39. };
  40. if new_content != old_content {
  41. print_diff(old_content, new_content.clone());
  42. write_to_file()
  43. }
  44. } else {
  45. match OpenOptions::new()
  46. .create(true)
  47. .write(true)
  48. .open(output_file)
  49. {
  50. Ok(ref mut file) => file.write_all(content.as_bytes()).unwrap(),
  51. Err(err) => panic!("Open or create to {} fail: {}", output_file, err),
  52. }
  53. }
  54. }
  55. pub fn print_diff(old_content: String, new_content: String) {
  56. let diff = TextDiff::from_lines(&old_content, &new_content);
  57. for op in diff.ops() {
  58. for change in diff.iter_changes(op) {
  59. let (sign, style) = match change.tag() {
  60. ChangeTag::Delete => ("-", Style::new().red()),
  61. ChangeTag::Insert => ("+", Style::new().green()),
  62. ChangeTag::Equal => (" ", Style::new()),
  63. };
  64. match change.tag() {
  65. ChangeTag::Delete => {
  66. print!("{}{}", style.apply_to(sign).bold(), style.apply_to(change));
  67. },
  68. ChangeTag::Insert => {
  69. print!("{}{}", style.apply_to(sign).bold(), style.apply_to(change));
  70. },
  71. ChangeTag::Equal => {},
  72. };
  73. }
  74. println!("---------------------------------------------------");
  75. }
  76. }
  77. #[allow(dead_code)]
  78. pub fn is_crate_dir(e: &walkdir::DirEntry) -> bool {
  79. let cargo = e.path().file_stem().unwrap().to_str().unwrap().to_string();
  80. cargo == *"Cargo"
  81. }
  82. #[allow(dead_code)]
  83. pub fn is_proto_file(e: &walkdir::DirEntry) -> bool {
  84. if e.path().extension().is_none() {
  85. return false;
  86. }
  87. let ext = e.path().extension().unwrap().to_str().unwrap().to_string();
  88. ext == *"proto"
  89. }
  90. pub fn is_hidden(entry: &walkdir::DirEntry) -> bool {
  91. entry
  92. .file_name()
  93. .to_str()
  94. .map(|s| s.starts_with('.'))
  95. .unwrap_or(false)
  96. }
  97. pub fn create_dir_if_not_exist(dir: &Path) {
  98. if !dir.exists() {
  99. std::fs::create_dir_all(dir).unwrap();
  100. }
  101. }
  102. pub fn path_string_with_component(path: &Path, components: Vec<&str>) -> String {
  103. path_buf_with_component(path, components)
  104. .to_str()
  105. .unwrap()
  106. .to_string()
  107. }
  108. #[allow(dead_code)]
  109. pub fn path_buf_with_component(path: &Path, components: Vec<&str>) -> PathBuf {
  110. let mut path_buf = path.to_path_buf();
  111. for component in components {
  112. path_buf.push(component);
  113. }
  114. path_buf
  115. }
  116. #[allow(dead_code)]
  117. pub fn walk_dir<P: AsRef<Path>, F1, F2>(dir: P, filter: F2, mut path_and_name: F1)
  118. where
  119. F1: FnMut(String, String),
  120. F2: Fn(&walkdir::DirEntry) -> bool,
  121. {
  122. for (path, name) in WalkDir::new(dir)
  123. .into_iter()
  124. .filter_map(|e| e.ok())
  125. .filter(|e| filter(e))
  126. .map(|e| {
  127. (
  128. e.path().to_str().unwrap().to_string(),
  129. e.path().file_stem().unwrap().to_str().unwrap().to_string(),
  130. )
  131. })
  132. {
  133. path_and_name(path, name);
  134. }
  135. }
  136. #[allow(dead_code)]
  137. pub fn suffix_relative_to_path(path: &str, base: &str) -> String {
  138. let base = Path::new(base);
  139. let path = Path::new(path);
  140. path
  141. .strip_prefix(base)
  142. .unwrap()
  143. .to_str()
  144. .unwrap()
  145. .to_owned()
  146. }
  147. pub fn get_tera(directory: &str) -> Tera {
  148. let mut root = format!("{}/src/", env!("CARGO_MANIFEST_DIR"));
  149. root.push_str(directory);
  150. let root_absolute_path = match std::fs::canonicalize(&root) {
  151. Ok(p) => p.as_path().display().to_string(),
  152. Err(e) => {
  153. panic!("❌ Canonicalize file path {} failed {:?}", root, e);
  154. },
  155. };
  156. let mut template_path = format!("{}/**/*.tera", root_absolute_path);
  157. if cfg!(windows) {
  158. // remove "\\?\" prefix on windows
  159. template_path = format!("{}/**/*.tera", &root_absolute_path[4..]);
  160. }
  161. match Tera::new(template_path.as_ref()) {
  162. Ok(t) => t,
  163. Err(e) => {
  164. log::error!("Parsing error(s): {}", e);
  165. ::std::process::exit(1);
  166. },
  167. }
  168. }
  169. pub fn cache_dir() -> PathBuf {
  170. let mut path_buf = PathBuf::from_str(env!("CARGO_MANIFEST_DIR")).unwrap();
  171. path_buf.push(".cache");
  172. path_buf
  173. }