summaryrefslogtreecommitdiffstats
path: root/src/utils/fileutil.rs
blob: 3caea184ba7157229c54230dedf3a660772d00cb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use super::misc;
use std::io::prelude::*;
use std::io::{BufRead, BufReader};
use std::path::{Path, PathBuf};
use std::{fs, io};
use std::fs::OpenOptions;

use icalwrap::IcalVCalendar;

pub fn file_iter(dir: &Path) -> impl Iterator<Item = PathBuf> {
  use walkdir::WalkDir;

  WalkDir::new(dir).into_iter()
    .filter_map(|e| e.ok())
    .filter(|e| e.file_type().is_file())
    .map(|entry| entry.into_path())
}

pub fn write_file(filepath: &Path, contents: &str) -> io::Result<()> {
  let mut file = fs::File::create(filepath)?;
  file.write_all(contents.as_bytes())
}

pub fn append_file(filepath: &Path, contents: &str) -> io::Result<()> {
  let mut file = OpenOptions::new()
              .append(true)
              .create(true)
              .open(filepath)?;
  file.write_all(contents.as_bytes())
}

pub fn write_cal(cal: &IcalVCalendar) -> Result<(), String> {
  match cal.get_path() {
    Some(path) => write_file(&path, &cal.to_string()).map_err(|error| format!("{}", error)),
    None => Err("calendar has no path".to_string()),
  }
}

pub fn read_lines_from_file(filepath: &Path) -> io::Result<impl Iterator<Item = String>> {
  let f = fs::File::open(filepath)?;
  let f = BufReader::new(f);
  let lines: Result<Vec<String>, io::Error> = f.lines().collect();
  match lines {
    Ok(result) => Ok(result.into_iter()),
    Err(error) => Err(error)
  }
}

pub fn read_lines_from_stdin() -> io::Result<impl Iterator<Item = String>> {
  let stdin = io::stdin();
  let handle = stdin.lock();

  let lines: Result<Vec<String>, io::Error> = handle.lines().collect();
  match lines {
    Ok(result) => Ok(result.into_iter()),
    Err(error) => Err(error)
  }
}

pub fn read_file_to_string(path: &Path) -> Result<String, String> {
  if let Ok(mut file) = fs::File::open(&path) {
    let mut contents = String::new();
    if file.read_to_string(&mut contents).is_ok() {
      Ok(contents)
    } else {
      Err("Something went wrong reading the file".to_string())
    }
  } else {
    Err(format!("Could not open {} for reading", path.display()))
  }
}

pub fn read_calendar_from_path(path: &Path) -> Result<IcalVCalendar, String> {
  trace!("Reading calendar from {}", path.to_string_lossy());
  let content = match fs::read_to_string(path) {
    Ok(content) => content,
    Err(error) => return Err(format!("{} {:?}", error, path))
  };
  IcalVCalendar::from_str(&content, Some(path))
}

pub fn read_calendar_from_file(filepath: &str) -> Result<IcalVCalendar, String> {
  let path = Path::new(filepath);
  read_calendar_from_path(path)
}

pub fn read_calendars_from_files(files: &mut Iterator<Item = String>) -> Result<Vec<IcalVCalendar>, String> {
  files.map(|file| read_khaleesi_line(&file)).collect()
}

pub fn read_khaleesi_line(kline: &str) -> Result<IcalVCalendar, String> {
  let parts: Vec<&str> = kline.splitn(2, ' ').collect();
  if let Some(timestamp) = misc::datetime_from_timestamp(parts[0]) {
    let path = Path::new(parts[1]);
    let calendar = read_calendar_from_path(path)?;
    let calendar = calendar.with_internal_timestamp(timestamp);
    Ok(calendar)
  } else {
    let path = Path::new(parts[0]);
    let calendar = read_calendar_from_path(path)?;
    Ok(calendar)
  }
}

pub fn print_cals(cals: impl Iterator<Item = IcalVCalendar>) {
  for cal in cals {
    if let Some(line) = cal.get_principal_event().get_khaleesi_line() {
      println!("{}", line);
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  use testutils::prepare_testdir;
  use assert_fs::prelude::*;

  #[test]
  fn test_append_file() {
    let testdir = prepare_testdir("testdir");
    let file = testdir.child("f");

    append_file(file.path(), "x\ny\n").unwrap();
    file.assert("x\ny\n");

    append_file(file.path(), "z\n").unwrap();
    file.assert("x\ny\nz\n");
  }

  #[test]
  fn test_write_file() {
    let testdir = prepare_testdir("testdir");
    let file = testdir.child("f");

    write_file(file.path(), "x\ny\n").unwrap();
    file.assert("x\ny\n");

    write_file(file.path(), "z\n").unwrap();
    file.assert("z\n");
  }
}