bbq/lib.rs
1use std::fs;
2use std::path::Path;
3use std::time::SystemTime;
4
5#[derive(Debug)]
6pub struct FileInfo {
7 pub file_name: String,
8 pub file_type: String,
9 pub file_path: String,
10 pub created_time: SystemTime,
11 pub modified_time: SystemTime,
12 pub size: u64,
13 pub size_kb: u64,
14 pub size_mb: u64,
15}
16
17/// Compresses the specified directory into a tar.gz file.
18///
19/// # Arguments
20///
21/// * `dir` - The path of the directory to be compressed. The generated tar.gz file will be created in the same directory and named after this directory.
22///
23/// * `name` - The name of the tar.gz file.
24///
25/// # Return Value
26///
27/// * If successful, returns `Ok(())`.
28/// * If failed, returns an `Err` containing the error information.
29///
30/// # Example
31///
32/// ```
33/// use your_crate::tar_dir;
34///
35/// let result = tar_dir("/path/to/dir", "archive");
36/// assert!(result.is_ok());
37/// ```
38pub fn archive_dir(dir: &str, name: &str) -> std::io::Result<()> {
39 let tar_gz = format!("{}.tar.gz", name);
40 let output = std::process::Command::new("tar")
41 .arg("czvf")
42 .arg(&tar_gz)
43 .arg(dir)
44 .output()?;
45 if !output.status.success() {
46 return Err(std::io::Error::new(std::io::ErrorKind::Other, "tar failed"));
47 }
48 Ok(())
49}
50
51/// Removes the specified directory.
52///
53/// # Arguments
54///
55/// * `dir` - A string slice that holds the name of the directory
56///
57/// # Examples
58///
59/// ```
60/// use crate::remove_dir;
61///
62/// let dir = "some_directory";
63/// remove_dir(dir);
64/// ```
65pub fn remove_dir(dir: &str) -> std::io::Result<()> {
66 fs::remove_dir_all(dir)
67}
68
69/// Removes the specified file.
70///
71/// # Arguments
72///
73/// * `file` - A string slice that holds the name of the file
74///
75/// # Examples
76///
77/// ```
78/// use crate::remove_file;
79///
80/// let file = "some_file";
81/// remove_file(file);
82/// ```
83pub fn remove_file(file: &str) -> std::io::Result<()> {
84 fs::remove_file(file)
85}
86
87/// Reads a file as binary data.
88///
89/// # Arguments
90///
91/// * `file` - A string slice that holds the name of the file to read.
92///
93/// # Returns
94///
95/// * `std::io::Result<Vec<u8>>` - A Result type. If the operation was successful, it will contain a vector of bytes. If it was not successful, it will contain an error.
96pub fn read_file(file: &str) -> std::io::Result<Vec<u8>> {
97 fs::read(file)
98}
99
100/// Writes binary data to a file.
101///
102/// # Arguments
103///
104/// * `file` - A string slice that holds the name of the file to write to.
105/// * `data` - A byte slice that contains the data to write to the file.
106///
107/// # Returns
108///
109/// * `std::io::Result<()>` - A Result type. If the operation was successful, it will contain an empty tuple. If it was not successful, it will contain an error.
110pub fn write_file(file: &str, data: &[u8]) -> std::io::Result<()> {
111 fs::write(file, data)
112}
113
114/// Reads a file as a text string.
115///
116/// # Arguments
117///
118/// * `file` - A string slice that holds the name of the file to read.
119///
120/// # Returns
121///
122/// * `std::io::Result<String>` - A Result type. If the operation was successful, it will contain a string. If it was not successful, it will contain an error.
123pub fn read_text_file(file: &str) -> std::io::Result<String> {
124 fs::read_to_string(file)
125}
126
127/// Writes a text string to a file.
128///
129/// # Arguments
130///
131/// * `file` - A string slice that holds the name of the file to write to.
132/// * `data` - A string slice that contains the text to write to the file.
133///
134/// # Returns
135///
136/// * `std::io::Result<()>` - A Result type. If the operation was successful, it will contain an empty tuple. If it was not successful, it will contain an error.
137pub fn write_text_file(file: &str, data: &str) -> std::io::Result<()> {
138 fs::write(file, data)
139}
140
141/// Moves a file from one location to another.
142///
143/// # Arguments
144///
145/// * `src` - A string slice that holds the name of the source file.
146/// * `dest` - A string slice that holds the name of the destination file.
147///
148/// # Examples
149///
150/// ```
151/// let src = "src.txt";
152/// let dest = "dest.txt";
153/// move_file(src, dest);
154/// ```
155pub fn move_file(src: &str, dest: &str) -> std::io::Result<()> {
156 fs::rename(src, dest)
157}
158
159pub fn get_dir_info(dir: &str) -> std::io::Result<Vec<FileInfo>> {
160 let mut files_info = Vec::new();
161 if let Ok(entries) = fs::read_dir(dir) {
162 for entry in entries {
163 let entry = entry?;
164 let path = entry.path();
165 let metadata = fs::metadata(&path)?;
166 let file_name = path.file_name().unwrap().to_str().unwrap().to_string();
167 let file_type = if metadata.is_file() {
168 "File".to_string()
169 } else if metadata.is_dir() {
170 "Directory".to_string()
171 } else {
172 "Unknown".to_string()
173 };
174 let size = metadata.len();
175 let size_kb = size / 1024;
176 let size_mb = size_kb / 1024;
177 let created_time = metadata.created()?;
178 let modified_time = metadata.modified()?;
179
180 files_info.push(FileInfo {
181 file_name,
182 file_type,
183 file_path: path.to_str().unwrap().to_string(),
184 created_time,
185 modified_time,
186 size,
187 size_kb,
188 size_mb,
189 });
190 }
191 }
192
193 Ok(files_info)
194}
195
196/// The `get_size` function returns the total size (in bytes) of the specified directory.
197///
198/// # Arguments
199///
200/// * `dir` - A string slice that contains the path of the directory to query.
201///
202/// # Return
203///
204/// Returns a `std::io::Result<u64>`. If the operation is successful, it will contain the total size of the directory (in bytes).
205pub fn get_size(dir: &str) -> std::io::Result<u64> {
206 let path = Path::new(dir);
207 get_size_by_path(path)
208}
209
210fn get_size_by_path(path: &Path) -> std::io::Result<u64> {
211 let metadata = fs::metadata(path)?;
212 if metadata.is_file() {
213 Ok(metadata.len())
214 } else if metadata.is_dir() {
215 let mut total_size = 0;
216 for entry in fs::read_dir(path)? {
217 let entry = entry?;
218 let path = entry.path();
219 if path.is_symlink() {
220 continue;
221 }
222 total_size += get_size_by_path(&entry.path())?;
223 }
224 Ok(total_size)
225 } else {
226 Ok(0)
227 }
228}
229
230/// Removes old files from a directory until the total size of the directory is less than a specified size.
231///
232/// # Arguments
233///
234/// * `dir` - A string slice that holds the name of the directory.
235/// * `keep` - The maximum size (in bytes) that the directory should be. If the directory is larger than this, the oldest files will be removed until it is less than this size.
236///
237/// # Returns
238///
239/// * `std::io::Result<Vec<String>>` - A Result containing a vector of the names of the files that were removed. If an error occurred, it will contain the error.
240///
241/// # Example
242///
243/// ```
244/// let removed_files = remove_old_files("/path/to/directory", 10000);
245/// ```
246pub fn remove_old_files(dir: &str, keep: u64) -> std::io::Result<Vec<String>> {
247 let mut dir_size = get_size(dir).unwrap();
248 if dir_size < keep {
249 return Ok(vec![]);
250 }
251 let path = Path::new(dir);
252 let mut files = get_files(path)?;
253 files.retain(|path| {
254 fs::metadata(path)
255 .ok()
256 .map(|metadata| !metadata.file_type().is_symlink())
257 .unwrap_or(false)
258 });
259 files.sort_by_key(|path| {
260 fs::metadata(path)
261 .ok()
262 .and_then(|metadata| metadata.modified().ok())
263 .unwrap_or(std::time::SystemTime::UNIX_EPOCH)
264 });
265 let mut removed_files = Vec::new();
266 while dir_size > keep {
267 if let Some(file) = files.pop() {
268 if file.is_symlink() {
269 continue;
270 }
271 let metadata = fs::metadata(&file)?;
272 let size = metadata.len();
273 dir_size -= size;
274 removed_files.push(file.to_str().unwrap().to_string());
275 let _ = fs::remove_file(file.clone());
276 } else {
277 break;
278 }
279 }
280 Ok(removed_files)
281}
282
283/// Removes specified files from the system.
284///
285/// # Arguments
286///
287/// * `files` - A vector of strings that holds the names of the files to be removed.
288///
289/// # Returns
290///
291/// * `std::io::Result<()>` - A Result indicating success or failure. If an error occurred during file removal, it will contain the error.
292///
293/// # Example
294///
295/// ```
296/// let files_to_remove = vec!["/path/to/file1", "/path/to/file2"];
297/// let result = remove_files(files_to_remove);
298/// ```
299pub fn remove_files(files: Vec<String>) -> std::io::Result<()> {
300 for file in files {
301 let _ = fs::remove_file(file);
302 }
303 Ok(())
304}
305
306/// Reads multiple files and returns their content as binaries.
307///
308/// # Arguments
309///
310/// * `files` - A vector of strings that holds the names of the files to be read.
311///
312/// # Returns
313///
314/// * `std::io::Result<Vec<Vec<u8>>>` - A Result containing a vector of binary content for each file or an error.
315///
316/// # Example
317///
318/// ```
319/// let files_to_read = vec!["/path/to/file1", "/path/to/file2"];
320/// let file_contents = read_files(files_to_read);
321/// ```
322pub fn read_files(files: Vec<String>) -> std::io::Result<Vec<Vec<u8>>> {
323 let mut buffers = Vec::new();
324 for file in files {
325 let buffer = read_file(&file)?;
326 buffers.push(buffer);
327 }
328 Ok(buffers)
329}
330
331/// Retrieves all files from a specified directory, including subdirectories.
332///
333/// # Arguments
334///
335/// * `dir` - A reference to a Path that holds the directory from which files should be retrieved.
336///
337/// # Returns
338///
339/// * `std::io::Result<Vec<std::path::PathBuf>>` - A Result containing a vector of PathBuf, each representing a file in the directory. If an error occurred, it will contain the error.
340///
341/// # Example
342///
343/// ```
344/// let dir = Path::new("/path/to/directory");
345/// let files = get_files(dir);
346/// ```
347pub fn get_files(dir: &Path) -> std::io::Result<Vec<std::path::PathBuf>> {
348 let mut files = Vec::new();
349 if let Ok(entries) = fs::read_dir(dir) {
350 for entry in entries {
351 let path = entry?.path();
352 if path.is_file() {
353 if path.is_symlink() {
354 continue;
355 }
356 files.push(path);
357 } else if path.is_dir() {
358 match get_files(&path) {
359 Ok(sub_files) => files.extend(sub_files),
360 Err(_) => continue, // Ignore directories that cannot be accessed
361 }
362 }
363 }
364 }
365 Ok(files)
366}
367
368#[cfg(test)]
369mod tests_dir_info {
370 use super::*;
371
372 /// The `test_get_dir_info` function tests the functionality of the `get_dir_info` function.
373 ///
374 /// It will print out the total size of the specified directory (in bytes and MB).
375 #[test]
376 fn test_get_size() {
377 let dir = "/Users/mojih/Downloads";
378 let size = get_size(dir).unwrap();
379 println!("Total size of {} is {} bytes", dir, size);
380 // print MB
381 println!("Total size of {} is {} MB", dir, size / 1024 / 1024);
382 }
383 #[test]
384 fn test_get_dir_info() {
385 let dir = "/Users/mojih/Downloads";
386 let files_info = get_dir_info(dir).unwrap();
387 for file_info in files_info {
388 println!("{:?}\n", file_info);
389 }
390 }
391}
392
393#[cfg(test)]
394mod tests_remove_old_files {
395 use super::*;
396
397 #[test]
398 fn test_remove_old_files() {
399 let dir = "/Users/mojih/Downloads/test";
400 let keep = 1024 * 1024 * 80;
401 let removed_files = remove_old_files(dir, keep).unwrap();
402 println!("Removed files: {:?}", removed_files);
403 }
404
405 #[test]
406 fn test_get_files() {
407 let dir = "/Users/mojih/Downloads/test";
408 for entry in fs::read_dir(dir).unwrap() {
409 let entry = entry.unwrap();
410 let path = entry.path();
411 println!("path: {:?}", path);
412 }
413 }
414
415 #[test]
416 fn test_get_size_by_path() {
417 let path = "/Users/mojih/Downloads/test";
418 let size = get_size(path);
419 if size.is_err() {
420 println!("1111Error: {:?}", size);
421 } else {
422 let size = size.unwrap();
423 println!("size: {:?}", size);
424 // mb
425 println!("size: {:?}", size / 1024 / 1024);
426 }
427 }
428}