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.

92 lines
2.3 KiB

7 years ago
7 years ago
7 years ago
  1. use std::error::Error;
  2. use std::fmt;
  3. use std::io;
  4. use std::ops::Deref;
  5. use symbols::Symbol;
  6. #[derive(Debug)]
  7. pub enum FileError<E: Error> {
  8. ExecError(E),
  9. GenericError
  10. }
  11. impl From<io::Error> for FileError<io::Error> {
  12. fn from(err: io::Error) -> FileError<io::Error> {
  13. FileError::ExecError(err)
  14. }
  15. }
  16. impl<E: Error> Error for FileError<E> {
  17. fn description(&self) -> &str {
  18. match self {
  19. &FileError::ExecError(ref e) => e.description(),
  20. &FileError::GenericError => "Generic error"
  21. }
  22. }
  23. fn cause(&self) -> Option<&Error> {
  24. match self {
  25. &FileError::ExecError(ref e) => Some(e),
  26. _ => None
  27. }
  28. }
  29. }
  30. impl<E: Error> fmt::Display for FileError<E> {
  31. fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
  32. write!(f, "{}", self.description())
  33. }
  34. }
  35. use std::convert::AsRef;
  36. pub struct File<C, D> where C: Deref<Target=str>, D: AsRef<str> + fmt::Display {
  37. path: D,
  38. content: C
  39. }
  40. impl<C, D> File<C, D> where C: Deref<Target=str>, D: AsRef<str> + fmt::Display {
  41. pub fn new(path: D, content: C) -> Self {
  42. File {
  43. path: path,
  44. content: content
  45. }
  46. }
  47. }
  48. use std::fs::File as FsFile;
  49. use std::io::{Read, Write};
  50. impl<C, D> Symbol for File<C, D> where C: Deref<Target=str>, D: AsRef<str> + fmt::Display {
  51. type Error = FileError<io::Error>;
  52. fn target_reached(&self) -> Result<bool, Self::Error> {
  53. let file = FsFile::open(self.path.as_ref());
  54. // Check if file exists
  55. if let Err(e) = file {
  56. return if e.kind() == io::ErrorKind::NotFound {
  57. Ok(false)
  58. } else {
  59. Err(e.into())
  60. };
  61. }
  62. // Check if content is the same
  63. let file_content = file.unwrap().bytes();
  64. let content_equal = try!(self.content.bytes().zip(file_content).fold(
  65. Ok(true),
  66. |state, (target_byte, file_byte_option)| state.and_then(|s| file_byte_option.map(|file_byte| s && file_byte == target_byte))
  67. ));
  68. return Ok(content_equal)
  69. }
  70. fn execute(&self) -> Result<(), Self::Error> {
  71. let mut file = try!(FsFile::create(self.path.as_ref()));
  72. try!(file.write_all(self.content.as_bytes()));
  73. Ok(())
  74. }
  75. }
  76. impl<C, D> fmt::Display for File<C, D> where C: Deref<Target=str>, D: AsRef<str> + fmt::Display {
  77. fn fmt(&self, f: &mut fmt::Formatter) -> Result<(),fmt::Error>{
  78. write!(f, "File {}", self.path)
  79. }
  80. }