1use std::fs::FileType;
2use std::io;
3use std::path::{Path, PathBuf};
4
5pub fn copy_symlink(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
8 let src = src.as_ref();
9 let dst = dst.as_ref();
10 let metadata = symlink_metadata(src);
11 if let Err(e) = copy_symlink_raw(metadata.file_type(), src, dst) {
12 panic!("failed to copy symlink from `{}` to `{}`: {e}", src.display(), dst.display(),);
13 }
14}
15
16fn copy_symlink_raw(ty: FileType, src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
17 let target_path = std::fs::read_link(src)?;
19
20 let new_symlink_path = dst.as_ref();
21 #[cfg(windows)]
22 {
23 use std::os::windows::fs::FileTypeExt;
24 if ty.is_symlink_dir() {
25 std::os::windows::fs::symlink_dir(&target_path, new_symlink_path)?;
26 } else {
27 std::os::windows::fs::symlink_file(&target_path, new_symlink_path)?;
30 }
31 }
32 #[cfg(unix)]
33 {
34 let _ = ty;
35 std::os::unix::fs::symlink(target_path, new_symlink_path)?;
36 }
37 #[cfg(not(any(windows, unix)))]
38 {
39 let _ = ty;
40 unimplemented!("unsupported target");
43 }
44 Ok(())
45}
46
47pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
50 fn copy_dir_all_inner(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
51 let dst = dst.as_ref();
52 if !dst.is_dir() {
53 std::fs::create_dir_all(&dst)?;
54 }
55 for entry in std::fs::read_dir(src)? {
56 let entry = entry?;
57 let ty = entry.file_type()?;
58 if ty.is_dir() {
59 copy_dir_all_inner(entry.path(), dst.join(entry.file_name()))?;
60 } else if ty.is_symlink() {
61 copy_symlink_raw(ty, entry.path(), dst.join(entry.file_name()))?;
62 } else {
63 std::fs::copy(entry.path(), dst.join(entry.file_name()))?;
64 }
65 }
66 Ok(())
67 }
68
69 if let Err(e) = copy_dir_all_inner(&src, &dst) {
70 panic!(
72 "failed to copy `{}` to `{}`: {:?}",
73 src.as_ref().display(),
74 dst.as_ref().display(),
75 e
76 );
77 }
78}
79
80pub fn read_dir_entries<P: AsRef<Path>, F: FnMut(&Path)>(dir: P, mut callback: F) {
82 for entry in read_dir(dir) {
83 callback(&entry.unwrap().path());
84 }
85}
86
87#[track_caller]
93pub fn recursive_remove<P: AsRef<Path>>(path: P) {
94 if let Err(e) = build_helper::fs::recursive_remove(path.as_ref()) {
95 panic!(
96 "failed to recursive remove filesystem entities at `{}`: {e}",
97 path.as_ref().display()
98 );
99 }
100}
101
102#[track_caller]
104pub fn remove_file<P: AsRef<Path>>(path: P) {
105 if let Err(e) = std::fs::remove_file(path.as_ref()) {
106 panic!("failed to remove file at `{}`: {e}", path.as_ref().display());
107 }
108}
109
110#[track_caller]
112pub fn remove_dir<P: AsRef<Path>>(path: P) {
113 if let Err(e) = std::fs::remove_dir(path.as_ref()) {
114 panic!("failed to remove directory at `{}`: {e}", path.as_ref().display());
115 }
116}
117
118#[track_caller]
120pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
121 std::fs::copy(from.as_ref(), to.as_ref()).expect(&format!(
122 "the file \"{}\" could not be copied over to \"{}\"",
123 from.as_ref().display(),
124 to.as_ref().display(),
125 ));
126}
127
128#[track_caller]
130pub fn create_file<P: AsRef<Path>>(path: P) {
131 std::fs::File::create(path.as_ref())
132 .expect(&format!("the file in path \"{}\" could not be created", path.as_ref().display()));
133}
134
135#[track_caller]
137pub fn read<P: AsRef<Path>>(path: P) -> Vec<u8> {
138 std::fs::read(path.as_ref())
139 .expect(&format!("the file in path \"{}\" could not be read", path.as_ref().display()))
140}
141
142#[track_caller]
144pub fn read_to_string<P: AsRef<Path>>(path: P) -> String {
145 std::fs::read_to_string(path.as_ref()).expect(&format!(
146 "the file in path \"{}\" could not be read into a String",
147 path.as_ref().display()
148 ))
149}
150
151#[track_caller]
153pub fn read_dir<P: AsRef<Path>>(path: P) -> std::fs::ReadDir {
154 std::fs::read_dir(path.as_ref())
155 .expect(&format!("the directory in path \"{}\" could not be read", path.as_ref().display()))
156}
157
158#[track_caller]
160pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) {
161 std::fs::write(path.as_ref(), contents.as_ref()).expect(&format!(
162 "the file in path \"{}\" could not be written to",
163 path.as_ref().display()
164 ));
165}
166
167#[track_caller]
169pub fn remove_dir_all<P: AsRef<Path>>(path: P) {
170 std::fs::remove_dir_all(path.as_ref()).expect(&format!(
171 "the directory in path \"{}\" could not be removed alongside all its contents",
172 path.as_ref().display(),
173 ));
174}
175
176#[track_caller]
178pub fn create_dir<P: AsRef<Path>>(path: P) {
179 std::fs::create_dir(path.as_ref()).expect(&format!(
180 "the directory in path \"{}\" could not be created",
181 path.as_ref().display()
182 ));
183}
184
185#[track_caller]
187pub fn create_dir_all<P: AsRef<Path>>(path: P) {
188 std::fs::create_dir_all(path.as_ref()).expect(&format!(
189 "the directory (and all its parents) in path \"{}\" could not be created",
190 path.as_ref().display()
191 ));
192}
193
194#[track_caller]
200pub fn metadata<P: AsRef<Path>>(path: P) -> std::fs::Metadata {
201 match std::fs::metadata(path.as_ref()) {
202 Ok(m) => m,
203 Err(e) => panic!("failed to read file metadata at `{}`: {e}", path.as_ref().display()),
204 }
205}
206
207#[track_caller]
213pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> std::fs::Metadata {
214 match std::fs::symlink_metadata(path.as_ref()) {
215 Ok(m) => m,
216 Err(e) => {
217 panic!("failed to read file metadata (shallow) at `{}`: {e}", path.as_ref().display())
218 }
219 }
220}
221
222#[track_caller]
224pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) {
225 std::fs::rename(from.as_ref(), to.as_ref()).expect(&format!(
226 "the file \"{}\" could not be moved over to \"{}\"",
227 from.as_ref().display(),
228 to.as_ref().display(),
229 ));
230}
231
232#[track_caller]
234pub fn set_permissions<P: AsRef<Path>>(path: P, perm: std::fs::Permissions) {
235 std::fs::set_permissions(path.as_ref(), perm).expect(&format!(
236 "the file's permissions in path \"{}\" could not be changed",
237 path.as_ref().display()
238 ));
239}
240
241#[track_caller]
243pub fn shallow_find_dir_entries<P: AsRef<Path>>(dir: P) -> Vec<PathBuf> {
244 let paths = read_dir(dir);
245 let mut output = Vec::new();
246 for path in paths {
247 output.push(path.unwrap().path());
248 }
249 output
250}
251
252pub fn symlink_dir<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
263 #[cfg(unix)]
264 {
265 if let Err(e) = std::os::unix::fs::symlink(original.as_ref(), link.as_ref()) {
266 panic!(
267 "failed to create symlink: original=`{}`, link=`{}`: {e}",
268 original.as_ref().display(),
269 link.as_ref().display()
270 );
271 }
272 }
273 #[cfg(windows)]
274 {
275 if let Err(e) = std::os::windows::fs::symlink_dir(original.as_ref(), link.as_ref()) {
276 panic!(
277 "failed to create symlink-to-directory: original=`{}`, link=`{}`: {e}",
278 original.as_ref().display(),
279 link.as_ref().display()
280 );
281 }
282 }
283 #[cfg(not(any(windows, unix)))]
284 {
285 unimplemented!("target family not currently supported")
286 }
287}
288
289pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(original: P, link: Q) {
296 #[cfg(unix)]
297 {
298 if let Err(e) = std::os::unix::fs::symlink(original.as_ref(), link.as_ref()) {
299 panic!(
300 "failed to create symlink: original=`{}`, link=`{}`: {e}",
301 original.as_ref().display(),
302 link.as_ref().display()
303 );
304 }
305 }
306 #[cfg(windows)]
307 {
308 if let Err(e) = std::os::windows::fs::symlink_file(original.as_ref(), link.as_ref()) {
309 panic!(
310 "failed to create symlink-to-file: original=`{}`, link=`{}`: {e}",
311 original.as_ref().display(),
312 link.as_ref().display()
313 );
314 }
315 }
316 #[cfg(not(any(windows, unix)))]
317 {
318 unimplemented!("target family not currently supported")
319 }
320}