]>
Commit | Line | Data |
---|---|---|
ea8adc8c XL |
1 | use std::path::{Path, PathBuf, Component}; |
2 | use errors::*; | |
3 | use std::io::Read; | |
7cac9316 XL |
4 | use std::fs::{self, File}; |
5 | ||
6 | /// Takes a path to a file and try to read the file into a String | |
ea8adc8c XL |
7 | pub fn file_to_string<P: AsRef<Path>>(path: P) -> Result<String> { |
8 | let path = path.as_ref(); | |
7cac9316 XL |
9 | let mut file = match File::open(path) { |
10 | Ok(f) => f, | |
11 | Err(e) => { | |
12 | debug!("[*]: Failed to open {:?}", path); | |
ea8adc8c | 13 | bail!(e); |
7cac9316 XL |
14 | }, |
15 | }; | |
16 | ||
17 | let mut content = String::new(); | |
18 | ||
19 | if let Err(e) = file.read_to_string(&mut content) { | |
20 | debug!("[*]: Failed to read {:?}", path); | |
ea8adc8c | 21 | bail!(e); |
7cac9316 XL |
22 | } |
23 | ||
24 | Ok(content) | |
25 | } | |
26 | ||
041b39d2 XL |
27 | /// Takes a path and returns a path containing just enough `../` to point to |
28 | /// the root of the given path. | |
7cac9316 | 29 | /// |
041b39d2 XL |
30 | /// This is mostly interesting for a relative path to point back to the |
31 | /// directory from where the path starts. | |
7cac9316 | 32 | /// |
ea8adc8c XL |
33 | /// ```rust |
34 | /// # extern crate mdbook; | |
35 | /// # | |
36 | /// # use std::path::Path; | |
37 | /// # use mdbook::utils::fs::path_to_root; | |
38 | /// # | |
39 | /// # fn main() { | |
40 | /// let path = Path::new("some/relative/path"); | |
41 | /// assert_eq!(path_to_root(path), "../../"); | |
42 | /// # } | |
7cac9316 XL |
43 | /// ``` |
44 | /// | |
041b39d2 XL |
45 | /// **note:** it's not very fool-proof, if you find a situation where |
46 | /// it doesn't return the correct path. | |
47 | /// Consider [submitting a new issue](https://github.com/azerupi/mdBook/issues) | |
48 | /// or a [pull-request](https://github.com/azerupi/mdBook/pulls) to improve it. | |
7cac9316 | 49 | |
ea8adc8c | 50 | pub fn path_to_root<P: Into<PathBuf>>(path: P) -> String { |
7cac9316 XL |
51 | debug!("[fn]: path_to_root"); |
52 | // Remove filename and add "../" for every directory | |
53 | ||
ea8adc8c | 54 | path.into() |
7cac9316 XL |
55 | .parent() |
56 | .expect("") | |
57 | .components() | |
58 | .fold(String::new(), |mut s, c| { | |
59 | match c { | |
60 | Component::Normal(_) => s.push_str("../"), | |
61 | _ => { | |
62 | debug!("[*]: Other path component... {:?}", c); | |
63 | }, | |
64 | } | |
65 | s | |
66 | }) | |
67 | } | |
68 | ||
69 | ||
70 | ||
041b39d2 XL |
71 | /// This function creates a file and returns it. But before creating the file |
72 | /// it checks every directory in the path to see if it exists, | |
73 | /// and if it does not it will be created. | |
7cac9316 | 74 | |
ea8adc8c | 75 | pub fn create_file(path: &Path) -> Result<File> { |
7cac9316 XL |
76 | debug!("[fn]: create_file"); |
77 | ||
78 | // Construct path | |
79 | if let Some(p) = path.parent() { | |
80 | debug!("Parent directory is: {:?}", p); | |
81 | ||
041b39d2 | 82 | fs::create_dir_all(p)?; |
7cac9316 XL |
83 | } |
84 | ||
85 | debug!("[*]: Create file: {:?}", path); | |
ea8adc8c | 86 | File::create(path).map_err(|e| e.into()) |
7cac9316 XL |
87 | } |
88 | ||
89 | /// Removes all the content of a directory but not the directory itself | |
90 | ||
ea8adc8c | 91 | pub fn remove_dir_content(dir: &Path) -> Result<()> { |
041b39d2 | 92 | for item in fs::read_dir(dir)? { |
7cac9316 XL |
93 | if let Ok(item) = item { |
94 | let item = item.path(); | |
95 | if item.is_dir() { | |
041b39d2 | 96 | fs::remove_dir_all(item)?; |
7cac9316 | 97 | } else { |
041b39d2 | 98 | fs::remove_file(item)?; |
7cac9316 XL |
99 | } |
100 | } | |
101 | } | |
102 | Ok(()) | |
103 | } | |
104 | ||
105 | /// | |
106 | /// | |
041b39d2 XL |
107 | /// Copies all files of a directory to another one except the files |
108 | /// with the extensions given in the `ext_blacklist` array | |
7cac9316 | 109 | |
041b39d2 | 110 | pub fn copy_files_except_ext(from: &Path, to: &Path, recursive: bool, ext_blacklist: &[&str]) |
ea8adc8c | 111 | -> Result<()> { |
7cac9316 XL |
112 | debug!("[fn] copy_files_except_ext"); |
113 | // Check that from and to are different | |
114 | if from == to { | |
115 | return Ok(()); | |
116 | } | |
117 | debug!("[*] Loop"); | |
041b39d2 XL |
118 | for entry in fs::read_dir(from)? { |
119 | let entry = entry?; | |
7cac9316 | 120 | debug!("[*] {:?}", entry.path()); |
041b39d2 | 121 | let metadata = entry.metadata()?; |
7cac9316 XL |
122 | |
123 | // If the entry is a dir and the recursive option is enabled, call itself | |
124 | if metadata.is_dir() && recursive { | |
125 | if entry.path() == to.to_path_buf() { | |
126 | continue; | |
127 | } | |
128 | debug!("[*] is dir"); | |
129 | ||
130 | // check if output dir already exists | |
131 | if !to.join(entry.file_name()).exists() { | |
041b39d2 | 132 | fs::create_dir(&to.join(entry.file_name()))?; |
7cac9316 XL |
133 | } |
134 | ||
041b39d2 | 135 | copy_files_except_ext(&from.join(entry.file_name()), &to.join(entry.file_name()), true, ext_blacklist)?; |
7cac9316 XL |
136 | } else if metadata.is_file() { |
137 | ||
138 | // Check if it is in the blacklist | |
139 | if let Some(ext) = entry.path().extension() { | |
140 | if ext_blacklist.contains(&ext.to_str().unwrap()) { | |
141 | continue; | |
142 | } | |
143 | } | |
144 | debug!("[*] creating path for file: {:?}", | |
041b39d2 XL |
145 | &to.join(entry |
146 | .path() | |
147 | .file_name() | |
148 | .expect("a file should have a file name..."))); | |
7cac9316 XL |
149 | |
150 | info!("[*] Copying file: {:?}\n to {:?}", | |
151 | entry.path(), | |
041b39d2 XL |
152 | &to.join(entry |
153 | .path() | |
154 | .file_name() | |
155 | .expect("a file should have a file name..."))); | |
156 | fs::copy(entry.path(), | |
157 | &to.join(entry | |
158 | .path() | |
159 | .file_name() | |
160 | .expect("a file should have a file name...")))?; | |
7cac9316 XL |
161 | } |
162 | } | |
163 | Ok(()) | |
164 | } | |
165 | ||
166 | ||
167 | // ------------------------------------------------------------------------------------------------ | |
168 | // ------------------------------------------------------------------------------------------------ | |
169 | ||
170 | // tests | |
171 | ||
172 | #[cfg(test)] | |
173 | mod tests { | |
174 | extern crate tempdir; | |
175 | ||
176 | use super::copy_files_except_ext; | |
177 | use std::fs; | |
178 | ||
179 | #[test] | |
180 | fn copy_files_except_ext_test() { | |
181 | let tmp = match tempdir::TempDir::new("") { | |
182 | Ok(t) => t, | |
183 | Err(_) => panic!("Could not create a temp dir"), | |
184 | }; | |
185 | ||
186 | // Create a couple of files | |
187 | if let Err(_) = fs::File::create(&tmp.path().join("file.txt")) { | |
188 | panic!("Could not create file.txt") | |
189 | } | |
190 | if let Err(_) = fs::File::create(&tmp.path().join("file.md")) { | |
191 | panic!("Could not create file.md") | |
192 | } | |
193 | if let Err(_) = fs::File::create(&tmp.path().join("file.png")) { | |
194 | panic!("Could not create file.png") | |
195 | } | |
196 | if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir")) { | |
197 | panic!("Could not create sub_dir") | |
198 | } | |
199 | if let Err(_) = fs::File::create(&tmp.path().join("sub_dir/file.png")) { | |
200 | panic!("Could not create sub_dir/file.png") | |
201 | } | |
202 | if let Err(_) = fs::create_dir(&tmp.path().join("sub_dir_exists")) { | |
203 | panic!("Could not create sub_dir_exists") | |
204 | } | |
205 | if let Err(_) = fs::File::create(&tmp.path().join("sub_dir_exists/file.txt")) { | |
206 | panic!("Could not create sub_dir_exists/file.txt") | |
207 | } | |
208 | ||
209 | // Create output dir | |
210 | if let Err(_) = fs::create_dir(&tmp.path().join("output")) { | |
211 | panic!("Could not create output") | |
212 | } | |
213 | if let Err(_) = fs::create_dir(&tmp.path().join("output/sub_dir_exists")) { | |
214 | panic!("Could not create output/sub_dir_exists") | |
215 | } | |
216 | ||
217 | match copy_files_except_ext(&tmp.path(), &tmp.path().join("output"), true, &["md"]) { | |
218 | Err(e) => panic!("Error while executing the function:\n{:?}", e), | |
219 | Ok(_) => {}, | |
220 | } | |
221 | ||
222 | // Check if the correct files where created | |
223 | if !(&tmp.path().join("output/file.txt")).exists() { | |
224 | panic!("output/file.txt should exist") | |
225 | } | |
226 | if (&tmp.path().join("output/file.md")).exists() { | |
227 | panic!("output/file.md should not exist") | |
228 | } | |
229 | if !(&tmp.path().join("output/file.png")).exists() { | |
230 | panic!("output/file.png should exist") | |
231 | } | |
232 | if !(&tmp.path().join("output/sub_dir/file.png")).exists() { | |
233 | panic!("output/sub_dir/file.png should exist") | |
234 | } | |
235 | if !(&tmp.path().join("output/sub_dir_exists/file.txt")).exists() { | |
236 | panic!("output/sub_dir/file.png should exist") | |
237 | } | |
238 | ||
239 | } | |
240 | } |