A library for writing host-specific, single-binary configuration management and deployment tools
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.

164 lines
4.2 KiB

7 years ago
6 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
5 years ago
6 years ago
7 years ago
5 years ago
5 years ago
5 years ago
7 years ago
5 years ago
7 years ago
5 years ago
5 years ago
7 years ago
5 years ago
5 years ago
6 years ago
7 years ago
5 years ago
5 years ago
7 years ago
6 years ago
5 years ago
5 years ago
5 years ago
6 years ago
7 years ago
5 years ago
5 years ago
5 years ago
5 years ago
7 years ago
5 years ago
7 years ago
5 years ago
5 years ago
5 years ago
7 years ago
5 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
7 years ago
7 years ago
5 years ago
6 years ago
7 years ago
  1. use regex::Regex;
  2. use std::cmp::max;
  3. use std::error::Error;
  4. use std::fmt;
  5. use std::fs::File as FsFile;
  6. use std::io;
  7. use std::io::{BufRead, BufReader};
  8. use std::path::Path;
  9. use command_runner::CommandRunner;
  10. use resources::Resource;
  11. use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
  12. pub struct WordpressTranslation<'a, C, D, R>
  13. where
  14. C: AsRef<str>,
  15. D: AsRef<str>,
  16. R: 'a + CommandRunner,
  17. {
  18. path: D,
  19. version: &'a str,
  20. locale: C,
  21. command_runner: &'a R,
  22. }
  23. impl<'a, C, R> WordpressTranslation<'a, C, String, R>
  24. where
  25. C: AsRef<str>,
  26. R: CommandRunner,
  27. {
  28. pub fn new<D: AsRef<str>>(path: D, version: &'a str, locale: C, command_runner: &'a R) -> Self {
  29. WordpressTranslation {
  30. path: Path::new(path.as_ref())
  31. .join("wp-content/languages")
  32. .to_string_lossy()
  33. .to_string(),
  34. version,
  35. locale,
  36. command_runner,
  37. }
  38. }
  39. }
  40. impl<'a, C, D, R> WordpressTranslation<'a, C, D, R>
  41. where
  42. C: AsRef<str>,
  43. D: AsRef<str>,
  44. R: CommandRunner,
  45. {
  46. fn get_pairs(&self) -> Vec<(String, String)> {
  47. let version_x = self
  48. .version
  49. .trim_end_matches(|c: char| c.is_digit(10))
  50. .to_owned()
  51. + "x";
  52. let locale: &str = self.locale.as_ref();
  53. let path_locale = if locale == "de_DE" {
  54. "de".to_owned()
  55. } else {
  56. locale.to_lowercase().replace('_', "-")
  57. };
  58. let mut res = vec![];
  59. for &(in_slug, out_slug) in [
  60. ("", ""),
  61. ("cc/", "continents-cities-"),
  62. ("admin/", "admin-"),
  63. ("admin/network/", "admin-network-"),
  64. ]
  65. .iter()
  66. {
  67. for format in ["po", "mo"].iter() {
  68. res.push((
  69. format!("https://translate.wordpress.org/projects/wp/{}/{}{}/default/export-translations?format={}", version_x, in_slug, path_locale, format),
  70. format!("{}/{}{}.{}", self.path.as_ref(), out_slug, self.locale.as_ref(), format)
  71. ))
  72. }
  73. }
  74. res
  75. }
  76. }
  77. impl<'a, C, D, R> Symbol for WordpressTranslation<'a, C, D, R>
  78. where
  79. C: AsRef<str>,
  80. D: AsRef<str>,
  81. R: CommandRunner,
  82. {
  83. fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  84. let mut newest = String::new();
  85. let match_date = Regex::new("(?m)^\"PO-Revision-Date: (.+)\\+0000\\\\n\"$").unwrap();
  86. for (_, target) in self.get_pairs() {
  87. match FsFile::open(target.clone()) {
  88. Err(e) => {
  89. // Check if file exists
  90. return if e.kind() == io::ErrorKind::NotFound {
  91. Ok(false)
  92. } else {
  93. Err(Box::new(e))
  94. };
  95. }
  96. Ok(file) => {
  97. if target.ends_with(".po") {
  98. let reader = BufReader::new(file);
  99. for content in reader.lines() {
  100. if let Some(match_result) = match_date.captures(&content?) {
  101. newest = max(newest, match_result[1].to_string());
  102. break;
  103. }
  104. }
  105. }
  106. }
  107. }
  108. }
  109. let upstream = self.command_runner.get_output(
  110. "curl",
  111. &[&format!(
  112. "https://api.wordpress.org/core/version-check/1.7/?version={}&locale={}",
  113. self.version,
  114. self.locale.as_ref()
  115. )],
  116. )?;
  117. Ok(String::from_utf8(upstream)?.contains(&format!(
  118. r###"language":"{}","version":"{}","updated":"{}"###,
  119. self.locale.as_ref(),
  120. self.version,
  121. newest
  122. )))
  123. }
  124. fn execute(&self) -> Result<(), Box<dyn Error>> {
  125. for (source, target) in self.get_pairs() {
  126. self
  127. .command_runner
  128. .run_successfully("curl", &["--compressed", "-o", &target, &source])?;
  129. }
  130. Ok(())
  131. }
  132. fn get_prerequisites(&self) -> Vec<Resource> {
  133. vec![Resource::new("dir", self.path.as_ref())]
  134. }
  135. fn as_action<'b>(&'b self, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b> {
  136. Box::new(SymbolAction::new(runner, self))
  137. }
  138. fn into_action<'b>(self: Box<Self>, runner: &'b dyn SymbolRunner) -> Box<dyn Action + 'b>
  139. where
  140. Self: 'b,
  141. {
  142. Box::new(OwnedSymbolAction::new(runner, *self))
  143. }
  144. }
  145. impl<'a, C, D, R> fmt::Display for WordpressTranslation<'a, C, D, R>
  146. where
  147. C: AsRef<str>,
  148. D: AsRef<str>,
  149. R: CommandRunner,
  150. {
  151. fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
  152. write!(f, "WordpressTranslation {}", self.path.as_ref())
  153. }
  154. }