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}