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.

104 lines
4.0 KiB

7 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
6 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 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 symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner};
  11. use resources::Resource;
  12. pub struct WordpressTranslation<'a, C, D, R> where C: AsRef<str> + fmt::Display, D: AsRef<str> + fmt::Display, R: 'a + CommandRunner {
  13. path: D,
  14. version: &'a str,
  15. locale: C,
  16. command_runner: &'a R
  17. }
  18. impl<'a, C, R> WordpressTranslation<'a, C, String, R> where C: AsRef<str> + fmt::Display, R: CommandRunner {
  19. pub fn new<D: AsRef<str> + fmt::Display>(path: D, version: &'a str, locale: C, command_runner: &'a R) -> Self {
  20. WordpressTranslation {
  21. path: Path::new(path.as_ref()).join("wp-content/languages").to_string_lossy().to_string(),
  22. version: version,
  23. locale: locale,
  24. command_runner: command_runner
  25. }
  26. }
  27. }
  28. impl<'a, C, D, R> WordpressTranslation<'a, C, D, R> where C: AsRef<str> + fmt::Display, D: AsRef<str> + fmt::Display, R: CommandRunner {
  29. fn get_pairs(&self) -> Vec<(String, String)> {
  30. let version_x = self.version.trim_right_matches(|c: char| c.is_digit(10)).to_owned() + "x";
  31. let locale: &str = self.locale.as_ref();
  32. let path_locale = if locale == "de_DE" { "de".to_owned() } else { locale.to_lowercase().replace('_', "-") };
  33. let mut res = vec![];
  34. for &(in_slug, out_slug) in [("", ""), ("cc/", "continents-cities-"), ("admin/", "admin-"), ("admin/network/", "admin-network-")].into_iter() {
  35. for format in ["po", "mo"].into_iter() {
  36. res.push((
  37. format!("https://translate.wordpress.org/projects/wp/{}/{}{}/default/export-translations?format={}", version_x, in_slug, path_locale, format),
  38. format!("{}/{}{}.{}", self.path, out_slug, self.locale, format)
  39. ))
  40. }
  41. }
  42. res
  43. }
  44. }
  45. impl<'a, C, D, R> Symbol for WordpressTranslation<'a, C, D, R> where C: AsRef<str> + fmt::Display, D: AsRef<str> + fmt::Display, R: CommandRunner {
  46. fn target_reached(&self) -> Result<bool, Box<Error>> {
  47. let mut newest = String::new();
  48. let match_date = Regex::new("(?m)^\"PO-Revision-Date: (.+)\\+0000\\\\n\"$").unwrap();
  49. for (_, target) in self.get_pairs() {
  50. match FsFile::open(target.clone()) {
  51. Err(e) => {
  52. // Check if file exists
  53. return if e.kind() == io::ErrorKind::NotFound {
  54. Ok(false)
  55. } else {
  56. Err(Box::new(e))
  57. };
  58. },
  59. Ok(mut file) => if target.ends_with(".po") {
  60. let mut reader = BufReader::new(file);
  61. for content in reader.lines() {
  62. if let Some(match_result) = match_date.captures(&try!(content)) {
  63. newest = max(newest, match_result[1].to_string());
  64. break;
  65. }
  66. }
  67. }
  68. }
  69. }
  70. let upstream = try!(self.command_runner.get_output("curl", &[&format!("https://api.wordpress.org/core/version-check/1.7/?version={}&locale={}", self.version, self.locale)]));
  71. Ok(try!(String::from_utf8(upstream)).contains(&format!(r###"language":"{}","version":"{}","updated":"{}"###, self.locale, self.version, newest)))
  72. }
  73. fn execute(&self) -> Result<(), Box<Error>> {
  74. for (source, target) in self.get_pairs() {
  75. try!(self.command_runner.run_successfully("curl", &["--compressed", "-o", &target, &source]));
  76. }
  77. Ok(())
  78. }
  79. fn get_prerequisites(&self) -> Vec<Resource> {
  80. vec![ Resource::new("dir", self.path.as_ref()) ]
  81. }
  82. fn as_action<'b>(&'b self, runner: &'b SymbolRunner) -> Box<Action + 'b> {
  83. Box::new(SymbolAction::new(runner, self))
  84. }
  85. fn into_action<'b>(self: Box<Self>, runner: &'b SymbolRunner) -> Box<Action + 'b> where Self: 'b {
  86. Box::new(OwnedSymbolAction::new(runner, *self))
  87. }
  88. }
  89. impl<'a, C, D, R> fmt::Display for WordpressTranslation<'a, C, D, R> where C: AsRef<str> + fmt::Display, D: AsRef<str> + fmt::Display, R: CommandRunner {
  90. fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{
  91. write!(f, "WordpressTranslation {}", self.path)
  92. }
  93. }