extern crate log;
extern crate walkdir;
use std::cmp::Ordering;
use std::io::ErrorKind;
use std::path::Path;
use log::warn;
use walkdir::WalkDir;
pub enum SortBy {
Ascending,
Descending,
}
#[derive(Clone, Debug)]
pub struct LrgOptions {
pub min_depth: usize,
pub max_depth: usize,
pub follow_links: bool,
pub include_dirs: bool,
}
impl Default for LrgOptions {
fn default() -> LrgOptions {
LrgOptions {
min_depth: 0,
max_depth: std::usize::MAX,
follow_links: false,
include_dirs: false,
}
}
}
pub type DirEntry = walkdir::DirEntry;
#[derive(Clone, Debug)]
pub struct Lrg {
entries: Vec<DirEntry>,
}
impl Lrg {
pub fn new(path: &Path, options: &LrgOptions) -> Self {
let mut entries: Vec<DirEntry> = Vec::new();
for entry in WalkDir::new(&path)
.min_depth(options.min_depth)
.max_depth(options.max_depth)
.follow_links(options.follow_links)
{
match entry {
Ok(entry) => {
if entry.file_type().is_dir() && options.include_dirs {
entries.push(entry.to_owned())
} else if entry.file_type().is_file() || entry.file_type().is_symlink() {
entries.push(entry.to_owned());
}
}
Err(err) => {
let path = err.path().unwrap_or_else(|| Path::new("")).display();
let error_message = get_walkdir_error_str(&err);
println!("lrg: error opening '{}': {}", path, error_message);
}
}
}
Lrg { entries }
}
pub fn sort_by(&mut self, cmp: &SortBy) -> &Self {
match cmp {
SortBy::Ascending => self.sort_ascending(),
SortBy::Descending => self.sort_descending(),
}
}
pub fn sort_by_custom<F>(&mut self, cmp: F) -> &Self
where
F: FnMut(&DirEntry, &DirEntry) -> Ordering,
{
self.entries.sort_unstable_by(cmp);
self
}
pub fn sort_ascending(&mut self) -> &Self {
self.entries.sort_unstable_by(|a: &DirEntry, b: &DirEntry| {
Self::get_size(a).cmp(&Self::get_size(b))
});
self
}
pub fn sort_descending(&mut self) -> &Self {
self.entries.sort_unstable_by(|a: &DirEntry, b: &DirEntry| {
Self::get_size(b).cmp(&Self::get_size(a))
});
self
}
fn get_size(entry: &DirEntry) -> u64 {
match entry.metadata() {
Ok(meta) => meta.len(),
Err(err) => {
warn!(
"Couldn't get metadata for {}: {:?}",
entry.path().display(),
err
);
0
}
}
}
pub fn get_entries(&self) -> Vec<DirEntry> {
self.entries.clone()
}
}
pub fn get_walkdir_error_str(err: &walkdir::Error) -> String {
match err.io_error() {
Some(ioerr) => {
match ioerr.kind() {
ErrorKind::NotFound => "Entity not found".to_owned(),
ErrorKind::PermissionDenied => "Permission denied".to_owned(),
ErrorKind::ConnectionRefused => "Connection refused".to_owned(),
ErrorKind::ConnectionReset => "Connection reset".to_owned(),
ErrorKind::ConnectionAborted => "Connection aborted".to_owned(),
ErrorKind::NotConnected => "Not connected".to_owned(),
ErrorKind::AddrInUse => "Address in use".to_owned(),
ErrorKind::AddrNotAvailable => "Address not available".to_owned(),
ErrorKind::BrokenPipe => "Broken pipe".to_owned(),
ErrorKind::AlreadyExists => "Entity already exists".to_owned(),
ErrorKind::WouldBlock => "Operation would block".to_owned(),
ErrorKind::InvalidInput => "Invalid input parameter".to_owned(),
ErrorKind::InvalidData => "Invalid data".to_owned(),
ErrorKind::TimedOut => "Timed out".to_owned(),
ErrorKind::WriteZero => "Write zero".to_owned(),
ErrorKind::Interrupted => "Operation interrupted".to_owned(),
ErrorKind::Other => "Other os error".to_owned(),
ErrorKind::UnexpectedEof => "Unexpected end of file".to_owned(),
_ => "Unknown error".to_owned(),
}
}
None => "Unknown error".to_owned(),
}
}