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.

141 lines
3.2 KiB

7 years ago
7 years ago
2 years ago
5 years ago
5 years ago
7 years ago
7 years ago
7 years ago
5 years ago
5 years ago
7 years ago
7 years ago
7 years ago
5 years ago
7 years ago
5 years ago
5 years ago
7 years ago
7 years ago
5 years ago
7 years ago
7 years ago
5 years ago
5 years ago
7 years ago
7 years ago
5 years ago
  1. use crate::command_runner::CommandRunner;
  2. use crate::storage::Storage;
  3. use crate::symbols::Symbol;
  4. use async_trait::async_trait;
  5. use std::borrow::Borrow;
  6. use std::error::Error;
  7. use std::fs;
  8. use std::io;
  9. use std::marker::PhantomData;
  10. use std::path::Path;
  11. use std::str::FromStr;
  12. #[derive(Debug, PartialEq, Eq)]
  13. pub enum StorageDirection {
  14. Load,
  15. Store,
  16. }
  17. #[derive(Debug)]
  18. pub struct SavedDirectory<_C, C, P, S> {
  19. path: P,
  20. storage: S,
  21. dir: StorageDirection,
  22. command_runner: C,
  23. phantom: PhantomData<_C>,
  24. }
  25. impl<_C, C, P, S> SavedDirectory<_C, C, P, S> {
  26. pub fn new(path: P, storage: S, dir: StorageDirection, command_runner: C) -> Self {
  27. Self {
  28. path,
  29. storage,
  30. dir,
  31. command_runner,
  32. phantom: PhantomData::default(),
  33. }
  34. }
  35. }
  36. #[async_trait(?Send)]
  37. impl<_C: CommandRunner, C: Borrow<_C>, P: AsRef<Path>, S: Storage> Symbol
  38. for SavedDirectory<_C, C, P, S>
  39. {
  40. async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
  41. let metadata = fs::metadata(self.path.as_ref());
  42. // Check if dir exists
  43. if let Err(e) = metadata {
  44. return if e.kind() == io::ErrorKind::NotFound {
  45. Ok(self.dir == StorageDirection::Store)
  46. } else {
  47. Err(Box::new(e))
  48. };
  49. }
  50. if !metadata.unwrap().is_dir() {
  51. return Err(Box::new(io::Error::new(
  52. io::ErrorKind::AlreadyExists,
  53. "Could not create a directory, non-directory file exists",
  54. )));
  55. }
  56. let dump_date = self.storage.recent_date()?;
  57. let output = self
  58. .command_runner
  59. .borrow()
  60. .get_output(
  61. "sh",
  62. args![
  63. "-c",
  64. format!(
  65. "find {} -printf '%T@\\n' | sort -r | head -n1 | grep '^[0-9]\\+' -o",
  66. self.path.as_ref().to_str().unwrap()
  67. ),
  68. ],
  69. )
  70. .await?;
  71. let modified_date = u64::from_str(std::str::from_utf8(&output)?.trim_end())?;
  72. if if self.dir == StorageDirection::Store {
  73. modified_date > dump_date
  74. } else {
  75. dump_date > modified_date
  76. } {
  77. let output = self
  78. .command_runner
  79. .borrow()
  80. .run_with_args(
  81. "diff",
  82. args![
  83. "-rq",
  84. self.storage.read_filename()?.as_os_str(),
  85. self.path.as_ref()
  86. ],
  87. )
  88. .await?;
  89. match output.status.code() {
  90. Some(0) => Ok(true),
  91. Some(1) => Ok(false),
  92. _ => Err(std::str::from_utf8(&output.stderr)?.into()),
  93. }
  94. } else {
  95. Ok(true)
  96. }
  97. }
  98. async fn execute(&self) -> Result<(), Box<dyn Error>> {
  99. if self.dir == StorageDirection::Load {
  100. self
  101. .command_runner
  102. .borrow()
  103. .run_successfully("rm", args!["-rf", self.path.as_ref()])
  104. .await?;
  105. self
  106. .command_runner
  107. .borrow()
  108. .run_successfully(
  109. "cp",
  110. args![
  111. "-a",
  112. self.storage.read_filename()?.as_os_str(),
  113. self.path.as_ref()
  114. ],
  115. )
  116. .await
  117. } else {
  118. self
  119. .command_runner
  120. .borrow()
  121. .run_successfully(
  122. "cp",
  123. args![
  124. "-a",
  125. self.path.as_ref(),
  126. self.storage.write_filename().as_os_str()
  127. ],
  128. )
  129. .await
  130. }
  131. }
  132. }
  133. #[cfg(test)]
  134. mod test {}