1use crate::scripts::{ALL_EXTS, ARCHIVE_EXTS};
3use std::fs;
4use std::io;
5use std::io::{Read, Write};
6use std::path::{Path, PathBuf};
7
8pub fn relative_path<P: AsRef<Path>, T: AsRef<Path>>(root: P, target: T) -> PathBuf {
10 let root = root
11 .as_ref()
12 .canonicalize()
13 .unwrap_or_else(|_| root.as_ref().to_path_buf());
14 let target = target
15 .as_ref()
16 .canonicalize()
17 .unwrap_or_else(|_| target.as_ref().to_path_buf());
18
19 let mut root_components: Vec<_> = root.components().collect();
20 let mut target_components: Vec<_> = target.components().collect();
21
22 while !root_components.is_empty()
24 && !target_components.is_empty()
25 && root_components[0] == target_components[0]
26 {
27 root_components.remove(0);
28 target_components.remove(0);
29 }
30
31 let mut result = PathBuf::new();
33 for _ in root_components {
34 result.push("..");
35 }
36
37 for component in target_components {
39 result.push(component);
40 }
41
42 result
43}
44
45pub fn find_files(path: &str, recursive: bool, no_ext_filter: bool) -> io::Result<Vec<String>> {
47 let mut result = Vec::new();
48 let dir_path = Path::new(&path);
49
50 if dir_path.is_dir() {
51 for entry in fs::read_dir(dir_path)? {
52 let entry = entry?;
53 let path = entry.path();
54
55 if path.is_file()
56 && (no_ext_filter
57 || path.file_name().map_or(false, |file| {
58 path.extension().map_or(true, |_| {
59 let file = file.to_string_lossy().to_lowercase();
60 for ext in ALL_EXTS.iter() {
61 if file.ends_with(&format!(".{}", ext)) {
62 return true;
63 }
64 }
65 false
66 })
67 }))
68 {
69 if let Some(path_str) = path.to_str() {
70 result.push(path_str.to_string());
71 }
72 } else if recursive && path.is_dir() {
73 if let Some(path_str) = path.to_str() {
74 let mut sub_files =
75 find_files(&path_str.to_string(), recursive, no_ext_filter)?;
76 result.append(&mut sub_files);
77 }
78 }
79 }
80 }
81
82 Ok(result)
83}
84
85pub fn find_arc_files(path: &str, recursive: bool) -> io::Result<Vec<String>> {
87 let mut result = Vec::new();
88 let dir_path = Path::new(&path);
89
90 if dir_path.is_dir() {
91 for entry in fs::read_dir(dir_path)? {
92 let entry = entry?;
93 let path = entry.path();
94
95 if path.is_file()
96 && path.file_name().map_or(false, |file| {
97 path.extension().map_or(true, |_| {
98 let file = file.to_string_lossy().to_lowercase();
99 for ext in ARCHIVE_EXTS.iter() {
100 if file.ends_with(&format!(".{}", ext)) {
101 return true;
102 }
103 }
104 false
105 })
106 })
107 {
108 if let Some(path_str) = path.to_str() {
109 result.push(path_str.to_string());
110 }
111 } else if recursive && path.is_dir() {
112 if let Some(path_str) = path.to_str() {
113 let mut sub_files = find_arc_files(&path_str.to_string(), recursive)?;
114 result.append(&mut sub_files);
115 }
116 }
117 }
118 }
119
120 Ok(result)
121}
122
123pub fn collect_files(
125 path: &str,
126 recursive: bool,
127 no_ext_filter: bool,
128) -> io::Result<(Vec<String>, bool)> {
129 let pa = Path::new(path);
130 if pa.is_dir() {
131 return Ok((find_files(path, recursive, no_ext_filter)?, true));
132 }
133 if pa.is_file() {
134 return Ok((vec![path.to_string()], false));
135 }
136 Err(io::Error::new(
137 io::ErrorKind::NotFound,
138 format!("Path {} is neither a file nor a directory", pa.display()),
139 ))
140}
141
142pub fn collect_arc_files(path: &str, recursive: bool) -> io::Result<(Vec<String>, bool)> {
144 let pa = Path::new(path);
145 if pa.is_dir() {
146 return Ok((find_arc_files(path, recursive)?, true));
147 }
148 if pa.is_file() {
149 return Ok((vec![path.to_string()], false));
150 }
151 Err(io::Error::new(
152 io::ErrorKind::NotFound,
153 format!("Path {} is neither a file nor a directory", pa.display()),
154 ))
155}
156
157pub fn read_file<F: AsRef<Path> + ?Sized>(f: &F) -> io::Result<Vec<u8>> {
159 let mut content = Vec::new();
160 if f.as_ref() == Path::new("-") {
161 io::stdin().read_to_end(&mut content)?;
162 } else {
163 content = fs::read(f)?;
164 }
165 Ok(content)
166}
167
168pub fn write_file<F: AsRef<Path> + ?Sized>(f: &F) -> io::Result<Box<dyn Write>> {
170 Ok(if f.as_ref() == Path::new("-") {
171 Box::new(io::stdout())
172 } else {
173 Box::new(fs::File::create(f)?)
174 })
175}
176
177pub fn make_sure_dir_exists<F: AsRef<Path> + ?Sized>(f: &F) -> io::Result<()> {
179 let path = f.as_ref();
180 if let Some(parent) = path.parent() {
181 if !parent.exists() {
182 fs::create_dir_all(parent)?;
183 }
184 }
185 Ok(())
186}