1use errors::Result;
4use linked_hash_map::LinkedHashMap;
5use std::cell::RefCell;
6use std::fs;
7use std::io;
8use std::path::{Path, PathBuf};
9use std::rc::Rc;
10use {RelativePath, RelativePathBuf};
11
12pub trait Handle {
13 fn is_dir(&self, path: &RelativePath) -> bool;
15
16 fn is_file(&self, path: &RelativePath) -> bool;
18
19 fn create_dir_all(&self, path: &RelativePath) -> Result<()>;
21
22 fn create(&self, path: &RelativePath) -> Result<Box<io::Write>>;
24}
25
26pub trait Filesystem {
28 fn open_root(&self, root: Option<&Path>) -> Result<Box<Handle>>;
30}
31
32pub struct RealFilesystem {}
34
35impl RealFilesystem {
36 pub fn new() -> RealFilesystem {
37 Self {}
38 }
39}
40
41impl Filesystem for RealFilesystem {
42 fn open_root(&self, root: Option<&Path>) -> Result<Box<Handle>> {
43 let root = root.ok_or_else(|| {
44 "Missing root directory, specify using `--out`, or `output` key in manifest"
45 })?
46 .to_owned();
47
48 return Ok(Box::new(RealHandle { root: root }));
49
50 struct RealHandle {
51 root: PathBuf,
52 }
53
54 impl Handle for RealHandle {
55 fn is_dir(&self, path: &RelativePath) -> bool {
56 path.to_path(&self.root).is_dir()
57 }
58
59 fn is_file(&self, path: &RelativePath) -> bool {
60 path.to_path(&self.root).is_file()
61 }
62
63 fn create_dir_all(&self, path: &RelativePath) -> Result<()> {
64 let path = path.to_path(&self.root);
65 Ok(fs::create_dir_all(&path)?)
66 }
67
68 fn create(&self, path: &RelativePath) -> Result<Box<io::Write>> {
69 let path = path.to_path(&self.root);
70 Ok(Box::new(fs::File::create(&path)?))
71 }
72 }
73 }
74}
75
76pub struct CapturingFilesystem {
80 files: Rc<RefCell<LinkedHashMap<RelativePathBuf, Vec<u8>>>>,
81}
82
83impl CapturingFilesystem {
84 pub fn new() -> CapturingFilesystem {
85 Self {
86 files: Rc::new(RefCell::new(LinkedHashMap::new())),
87 }
88 }
89
90 pub fn filesystem(&self) -> Box<Filesystem> {
92 Box::new(CapturingFilesystem {
93 files: self.files.clone(),
94 })
95 }
96
97 pub fn files(&self) -> &Rc<RefCell<LinkedHashMap<RelativePathBuf, Vec<u8>>>> {
99 &self.files
100 }
101}
102
103impl Filesystem for CapturingFilesystem {
104 fn open_root(&self, _root: Option<&Path>) -> Result<Box<Handle>> {
105 return Ok(Box::new(CapturingHandle {
106 files: self.files.clone(),
107 }));
108 }
109}
110
111struct CapturingHandle {
113 files: Rc<RefCell<LinkedHashMap<RelativePathBuf, Vec<u8>>>>,
114}
115
116impl Handle for CapturingHandle {
117 fn is_dir(&self, _path: &RelativePath) -> bool {
118 true
119 }
120
121 fn is_file(&self, path: &RelativePath) -> bool {
122 self.files.borrow().contains_key(path)
123 }
124
125 fn create_dir_all(&self, _path: &RelativePath) -> Result<()> {
126 Ok(())
127 }
128
129 fn create(&self, path: &RelativePath) -> Result<Box<io::Write>> {
130 Ok(Box::new(CapturingFileCreate {
131 files: self.files.clone(),
132 path: path.to_owned(),
133 buffer: Vec::new(),
134 }))
135 }
136}
137
138struct CapturingFileCreate {
140 files: Rc<RefCell<LinkedHashMap<RelativePathBuf, Vec<u8>>>>,
141 path: RelativePathBuf,
142 buffer: Vec<u8>,
143}
144
145impl io::Write for CapturingFileCreate {
146 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
147 self.buffer.write(buf)
148 }
149
150 fn flush(&mut self) -> io::Result<()> {
151 self.buffer.flush()
152 }
153}
154
155impl Drop for CapturingFileCreate {
156 fn drop(&mut self) {
157 let mut files = self.files.borrow_mut();
158 files.insert(self.path.clone(), self.buffer.clone());
159 }
160}