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.

110 lines
2.8 KiB

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