tinymist_package/pack/
fs.rs1use std::{fs::File, io::Write};
2
3use super::*;
4
5#[derive(Clone)]
7pub struct DirPack<P> {
8 pub path: P,
10}
11
12impl<P: AsRef<Path>> DirPack<P> {
13 pub fn new(path: P) -> Self {
15 Self { path }
16 }
17}
18
19impl<P: AsRef<Path>> fmt::Debug for DirPack<P> {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 write!(f, "DirPack({})", self.path.as_ref().display())
22 }
23}
24
25impl<P: AsRef<Path>> PackFs for DirPack<P> {
26 fn read_all(
27 &mut self,
28 f: &mut (dyn FnMut(&str, PackFile) -> PackageResult<()> + Send + Sync),
29 ) -> PackageResult<()> {
30 self.filter(|_| true).read_all(f)
31 }
32}
33
34impl<P: AsRef<Path>> Pack for DirPack<P> {}
35impl<P: AsRef<Path>> PackExt for DirPack<P> {
36 fn filter(&mut self, f: impl Fn(&str) -> bool + Send + Sync) -> impl Pack
37 where
38 Self: std::marker::Sized,
39 {
40 FilterDirPack {
41 path: &self.path,
42 f,
43 }
44 }
45}
46
47impl<P: AsRef<Path>> CloneIntoPack for DirPack<P> {
48 fn clone_into_pack(&mut self, pack: &mut impl PackFs) -> std::io::Result<()> {
49 let base = self.path.as_ref();
50 pack.read_all(&mut |path, file| {
51 let path = base.join(path);
52 std::fs::create_dir_all(path.parent().unwrap()).map_err(other)?;
53 let mut dst = std::fs::File::create(path).map_err(other)?;
54 match file {
55 PackFile::Read(mut reader) => {
56 std::io::copy(&mut reader, &mut dst).map_err(other)?;
57 }
58 PackFile::Data(data) => {
59 dst.write_all(&data.into_inner()).map_err(other)?;
60 }
61 }
62
63 Ok(())
64 })
65 .map_err(other_io)?;
66 Ok(())
67 }
68}
69
70struct FilterDirPack<'a, P, F> {
71 pub path: &'a P,
73 pub f: F,
75}
76
77impl<S: AsRef<Path>, F> fmt::Debug for FilterDirPack<'_, S, F> {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 write!(f, "FilterDirPack({:?}, ..)", self.path.as_ref())
80 }
81}
82impl<Src: AsRef<Path>, F: Fn(&str) -> bool + Send + Sync> PackFs for FilterDirPack<'_, Src, F> {
83 fn read_all(
84 &mut self,
85 f: &mut (dyn FnMut(&str, PackFile) -> PackageResult<()> + Send + Sync),
86 ) -> PackageResult<()> {
87 let w = walkdir::WalkDir::new(self.path.as_ref())
88 .follow_links(true)
89 .into_iter()
90 .filter_entry(|e| !e.file_name().to_string_lossy().starts_with('.'))
91 .filter_map(|e| e.ok())
92 .filter(|e| e.file_type().is_file());
93
94 for entry in w {
95 let path = entry.path();
96 let rel_path = path.strip_prefix(self.path.as_ref()).map_err(other)?;
97
98 let file_path = rel_path.to_string_lossy();
99 if !(self.f)(&file_path) {
100 continue;
101 }
102
103 let pack_file = PackFile::Read(Box::new(File::open(path).map_err(other)?));
104 f(&file_path, pack_file)?;
105 }
106
107 Ok(())
108 }
109}
110
111impl<Src: AsRef<Path>, F: Fn(&str) -> bool + Send + Sync> Pack for FilterDirPack<'_, Src, F> {}