remotefs 0.2.0

This commit is contained in:
veeso
2022-01-04 12:48:36 +01:00
committed by Christian Visintin
parent edd0842273
commit ec4daf8e25
28 changed files with 1013 additions and 1095 deletions

View File

@@ -31,13 +31,14 @@ use crate::utils::path::diff_paths;
// Ext
use bytesize::ByteSize;
use regex::Regex;
use remotefs::Entry;
use remotefs::File;
use std::path::PathBuf;
use std::time::UNIX_EPOCH;
#[cfg(target_family = "unix")]
use users::{get_group_by_gid, get_user_by_uid};
// Types
// FmtCallback: Formatter, fsentry: &Entry, cur_str, prefix, length, extra
type FmtCallback = fn(&Formatter, &Entry, &str, &str, Option<&usize>, Option<&String>) -> String;
// FmtCallback: Formatter, fsentry: &File, cur_str, prefix, length, extra
type FmtCallback = fn(&Formatter, &File, &str, &str, Option<&usize>, Option<&String>) -> String;
// Keys
const FMT_KEY_ATIME: &str = "ATIME";
@@ -64,7 +65,7 @@ lazy_static! {
static ref FMT_ATTR_REGEX: Regex = Regex::new(r"(?:([A-Z]+))(:?([0-9]+))?(:?(.+))?").ok().unwrap();
}
/// Call Chain block is a block in a chain of functions which are called in order to format the Entry.
/// Call Chain block is a block in a chain of functions which are called in order to format the File.
/// A callChain is instantiated starting from the Formatter syntax and the regex, once the groups are found
/// a chain of function is made using the Formatters method.
/// This method provides an extremely fast way to format fs entries
@@ -99,7 +100,7 @@ impl CallChainBlock {
}
/// Call next callback in the CallChain
pub fn next(&self, fmt: &Formatter, fsentry: &Entry, cur_str: &str) -> String {
pub fn next(&self, fmt: &Formatter, fsentry: &File, cur_str: &str) -> String {
// Call func
let new_str: String = (self.func)(
fmt,
@@ -161,7 +162,7 @@ impl Formatter {
}
/// Format fsentry
pub fn fmt(&self, fsentry: &Entry) -> String {
pub fn fmt(&self, fsentry: &File) -> String {
// Execute callchain blocks
self.call_chain.next(self, fsentry, "")
}
@@ -171,7 +172,7 @@ impl Formatter {
/// Format last access time
fn fmt_atime(
&self,
fsentry: &Entry,
fsentry: &File,
cur_str: &str,
prefix: &str,
fmt_len: Option<&usize>,
@@ -179,7 +180,7 @@ impl Formatter {
) -> String {
// Get date (use extra args as format or default "%b %d %Y %H:%M")
let datetime: String = fmt_time(
fsentry.metadata().atime,
fsentry.metadata().accessed.unwrap_or(UNIX_EPOCH),
match fmt_extra {
Some(fmt) => fmt.as_ref(),
None => "%b %d %Y %H:%M",
@@ -198,7 +199,7 @@ impl Formatter {
/// Format creation time
fn fmt_ctime(
&self,
fsentry: &Entry,
fsentry: &File,
cur_str: &str,
prefix: &str,
fmt_len: Option<&usize>,
@@ -206,7 +207,7 @@ impl Formatter {
) -> String {
// Get date
let datetime: String = fmt_time(
fsentry.metadata().ctime,
fsentry.metadata().created.unwrap_or(UNIX_EPOCH),
match fmt_extra {
Some(fmt) => fmt.as_ref(),
None => "%b %d %Y %H:%M",
@@ -225,7 +226,7 @@ impl Formatter {
/// Format owner group
fn fmt_group(
&self,
fsentry: &Entry,
fsentry: &File,
cur_str: &str,
prefix: &str,
fmt_len: Option<&usize>,
@@ -258,7 +259,7 @@ impl Formatter {
/// Format last change time
fn fmt_mtime(
&self,
fsentry: &Entry,
fsentry: &File,
cur_str: &str,
prefix: &str,
fmt_len: Option<&usize>,
@@ -266,7 +267,7 @@ impl Formatter {
) -> String {
// Get date
let datetime: String = fmt_time(
fsentry.metadata().mtime,
fsentry.metadata().modified.unwrap_or(UNIX_EPOCH),
match fmt_extra {
Some(fmt) => fmt.as_ref(),
None => "%b %d %Y %H:%M",
@@ -285,7 +286,7 @@ impl Formatter {
/// Format file name
fn fmt_name(
&self,
fsentry: &Entry,
fsentry: &File,
cur_str: &str,
prefix: &str,
fmt_len: Option<&usize>,
@@ -296,14 +297,14 @@ impl Formatter {
Some(l) => *l,
None => 24,
};
let name: &str = fsentry.name();
let name = fsentry.name();
let last_idx: usize = match fsentry.is_dir() {
// NOTE: For directories is l - 2, since we push '/' to name
true => file_len - 2,
false => file_len - 1,
};
let mut name: String = match name.len() >= file_len {
false => name.to_string(),
false => name,
true => format!("{}", &name[0..last_idx]),
};
if fsentry.is_dir() {
@@ -316,7 +317,7 @@ impl Formatter {
/// Format path
fn fmt_path(
&self,
fsentry: &Entry,
fsentry: &File,
cur_str: &str,
prefix: &str,
fmt_len: Option<&usize>,
@@ -341,7 +342,7 @@ impl Formatter {
/// Format file permissions
fn fmt_pex(
&self,
fsentry: &Entry,
fsentry: &File,
cur_str: &str,
prefix: &str,
_fmt_len: Option<&usize>,
@@ -376,7 +377,7 @@ impl Formatter {
/// Format file size
fn fmt_size(
&self,
fsentry: &Entry,
fsentry: &File,
cur_str: &str,
prefix: &str,
_fmt_len: Option<&usize>,
@@ -387,6 +388,17 @@ impl Formatter {
let size: ByteSize = ByteSize(fsentry.metadata().size);
// Add to cur str, prefix and the key value
format!("{}{}{:10}", cur_str, prefix, size.to_string())
} else if fsentry.metadata().symlink.is_some() {
let size = ByteSize(
fsentry
.metadata()
.symlink
.as_ref()
.unwrap()
.to_string_lossy()
.len() as u64,
);
format!("{}{}{:10}", cur_str, prefix, size.to_string())
} else {
// Add to cur str, prefix and the key value
format!("{}{} ", cur_str, prefix)
@@ -396,7 +408,7 @@ impl Formatter {
/// Format file symlink (if any)
fn fmt_symlink(
&self,
fsentry: &Entry,
fsentry: &File,
cur_str: &str,
prefix: &str,
fmt_len: Option<&usize>,
@@ -423,7 +435,7 @@ impl Formatter {
/// Format owner user
fn fmt_user(
&self,
fsentry: &Entry,
fsentry: &File,
cur_str: &str,
prefix: &str,
_fmt_len: Option<&usize>,
@@ -451,7 +463,7 @@ impl Formatter {
/// It does nothing, just returns cur_str
fn fmt_fallback(
&self,
_fsentry: &Entry,
_fsentry: &File,
cur_str: &str,
prefix: &str,
_fmt_len: Option<&usize>,
@@ -536,7 +548,7 @@ mod tests {
use super::*;
use pretty_assertions::assert_eq;
use remotefs::fs::{Directory, File, Metadata, UnixPex};
use remotefs::fs::{File, FileType, Metadata, UnixPex};
use std::path::PathBuf;
use std::time::SystemTime;
@@ -546,21 +558,20 @@ mod tests {
let dummy_formatter: Formatter = Formatter::new("");
// Make a dummy entry
let t: SystemTime = SystemTime::now();
let dummy_entry: Entry = Entry::File(File {
name: String::from("bar.txt"),
let dummy_entry = File {
path: PathBuf::from("/bar.txt"),
extension: Some(String::from("txt")),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::File,
size: 8192,
symlink: None,
uid: Some(0),
gid: Some(0),
mode: Some(UnixPex::from(0o644)),
},
});
};
let prefix: String = String::from("h");
let mut callchain: CallChainBlock = CallChainBlock::new(dummy_fmt, prefix, None, None);
assert!(callchain.next_block.is_none());
@@ -588,21 +599,20 @@ mod tests {
let formatter: Formatter = Formatter::default();
// Experiments :D
let t: SystemTime = SystemTime::now();
let entry: Entry = Entry::File(File {
name: String::from("bar.txt"),
let entry = File {
path: PathBuf::from("/bar.txt"),
extension: Some(String::from("txt")),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::File,
size: 8192,
symlink: None,
uid: Some(0),
gid: Some(0),
mode: Some(UnixPex::from(0o644)),
},
});
};
#[cfg(target_family = "unix")]
assert_eq!(
formatter.fmt(&entry),
@@ -620,21 +630,20 @@ mod tests {
)
);
// Elide name
let entry: Entry = Entry::File(File {
name: String::from("piroparoporoperoperupupu.txt"),
path: PathBuf::from("/bar.txt"),
extension: Some(String::from("txt")),
let entry = File {
path: PathBuf::from("/piroparoporoperoperupupu.txt"),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::File,
size: 8192,
symlink: None,
uid: Some(0),
gid: Some(0),
mode: Some(UnixPex::from(0o644)),
},
});
};
#[cfg(target_family = "unix")]
assert_eq!(
formatter.fmt(&entry),
@@ -652,21 +661,20 @@ mod tests {
)
);
// No pex
let entry: Entry = Entry::File(File {
name: String::from("bar.txt"),
let entry = File {
path: PathBuf::from("/bar.txt"),
extension: Some(String::from("txt")),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::File,
size: 8192,
symlink: None,
uid: Some(0),
gid: Some(0),
mode: None,
},
});
};
#[cfg(target_family = "unix")]
assert_eq!(
formatter.fmt(&entry),
@@ -684,21 +692,20 @@ mod tests {
)
);
// No user
let entry: Entry = Entry::File(File {
name: String::from("bar.txt"),
let entry = File {
path: PathBuf::from("/bar.txt"),
extension: Some(String::from("txt")),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::File,
size: 8192,
symlink: None,
uid: None,
gid: Some(0),
mode: None,
},
});
};
#[cfg(target_family = "unix")]
assert_eq!(
formatter.fmt(&entry),
@@ -723,20 +730,20 @@ mod tests {
let formatter: Formatter = Formatter::default();
// Experiments :D
let t: SystemTime = SystemTime::now();
let entry: Entry = Entry::Directory(Directory {
name: String::from("projects"),
let entry = File {
path: PathBuf::from("/home/cvisintin/projects"),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::Directory,
size: 4096,
symlink: None,
uid: Some(0),
gid: Some(0),
mode: Some(UnixPex::from(0o755)),
},
});
};
#[cfg(target_family = "unix")]
assert_eq!(
formatter.fmt(&entry),
@@ -754,20 +761,20 @@ mod tests {
)
);
// No pex, no user
let entry: Entry = Entry::Directory(Directory {
name: String::from("projects"),
let entry = File {
path: PathBuf::from("/home/cvisintin/projects"),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::Directory,
size: 4096,
symlink: None,
uid: None,
gid: Some(0),
mode: None,
},
});
};
#[cfg(target_family = "unix")]
assert_eq!(
formatter.fmt(&entry),
@@ -792,41 +799,41 @@ mod tests {
Formatter::new("{NAME:16} {SYMLINK:12} {GROUP} {USER} {PEX} {SIZE} {ATIME:20:%a %b %d %Y %H:%M} {CTIME:20:%a %b %d %Y %H:%M} {MTIME:20:%a %b %d %Y %H:%M}");
// Directory (with symlink)
let t: SystemTime = SystemTime::now();
let entry: Entry = Entry::Directory(Directory {
name: String::from("projects"),
path: PathBuf::from("/home/cvisintin/project"),
let entry = File {
path: PathBuf::from("/home/cvisintin/projects"),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::Symlink,
size: 4096,
symlink: Some(PathBuf::from("project.info")),
uid: None,
gid: None,
mode: Some(UnixPex::from(0o755)),
},
});
};
assert_eq!(formatter.fmt(&entry), format!(
"projects/ -> project.info 0 0 lrwxr-xr-x {} {} {}",
"projects -> project.info 0 0 lrwxr-xr-x 12 B {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
));
// Directory without symlink
let entry: Entry = Entry::Directory(Directory {
name: String::from("projects"),
path: PathBuf::from("/home/cvisintin/project"),
let entry = File {
path: PathBuf::from("/home/cvisintin/projects"),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::Directory,
size: 4096,
symlink: None,
uid: None,
gid: None,
mode: Some(UnixPex::from(0o755)),
},
});
};
assert_eq!(formatter.fmt(&entry), format!(
"projects/ 0 0 drwxr-xr-x {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
@@ -834,43 +841,41 @@ mod tests {
fmt_time(t, "%a %b %d %Y %H:%M"),
));
// File with symlink
let entry: Entry = Entry::File(File {
name: String::from("bar.txt"),
let entry = File {
path: PathBuf::from("/bar.txt"),
extension: Some(String::from("txt")),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::Symlink,
size: 8192,
symlink: Some(PathBuf::from("project.info")),
uid: None,
gid: None,
mode: Some(UnixPex::from(0o644)),
},
});
};
assert_eq!(formatter.fmt(&entry), format!(
"bar.txt -> project.info 0 0 lrw-r--r-- 8.2 KB {} {} {}",
"bar.txt -> project.info 0 0 lrw-r--r-- 12 B {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
fmt_time(t, "%a %b %d %Y %H:%M"),
));
// File without symlink
let entry: Entry = Entry::File(File {
name: String::from("bar.txt"),
let entry = File {
path: PathBuf::from("/bar.txt"),
extension: Some(String::from("txt")),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::File,
size: 8192,
symlink: None,
uid: None,
gid: None,
mode: Some(UnixPex::from(0o644)),
},
});
};
assert_eq!(formatter.fmt(&entry), format!(
"bar.txt 0 0 -rw-r--r-- 8.2 KB {} {} {}",
fmt_time(t, "%a %b %d %Y %H:%M"),
@@ -883,21 +888,20 @@ mod tests {
#[cfg(target_family = "unix")]
fn should_fmt_path() {
let t: SystemTime = SystemTime::now();
let entry: Entry = Entry::File(File {
name: String::from("bar.txt"),
let entry = File {
path: PathBuf::from("/tmp/a/b/c/bar.txt"),
extension: Some(String::from("txt")),
metadata: Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::Symlink,
size: 8192,
symlink: Some(PathBuf::from("project.info")),
uid: None,
gid: None,
mode: Some(UnixPex::from(0o644)),
},
});
};
let formatter: Formatter = Formatter::new("File path: {PATH}");
assert_eq!(
formatter.fmt(&entry).as_str(),
@@ -915,7 +919,7 @@ mod tests {
/// Dummy formatter, just yelds an 'A' at the end of the current string
fn dummy_fmt(
_fmt: &Formatter,
_entry: &Entry,
_entry: &File,
cur_str: &str,
prefix: &str,
_fmt_len: Option<&usize>,

View File

@@ -31,7 +31,7 @@ mod formatter;
// Locals
use formatter::Formatter;
// Ext
use remotefs::fs::Entry;
use remotefs::fs::File;
use std::cmp::Reverse;
use std::collections::VecDeque;
use std::path::{Path, PathBuf};
@@ -71,8 +71,8 @@ pub struct FileExplorer {
pub(crate) file_sorting: FileSorting, // File sorting criteria
pub(crate) group_dirs: Option<GroupDirs>, // If Some, defines how to group directories
pub(crate) opts: ExplorerOpts, // Explorer options
pub(crate) fmt: Formatter, // Entry formatter
files: Vec<Entry>, // Files in directory
pub(crate) fmt: Formatter, // File formatter
files: Vec<File>, // Files in directory
}
impl Default for FileExplorer {
@@ -109,7 +109,7 @@ impl FileExplorer {
/// Set Explorer files
/// This method will also sort entries based on current options
/// Once all sorting have been performed, index is moved to first valid entry.
pub fn set_files(&mut self, files: Vec<Entry>) {
pub fn set_files(&mut self, files: Vec<File>) {
self.files = files;
// Sort
self.sort();
@@ -131,7 +131,7 @@ impl FileExplorer {
/// Iterate over files
/// Filters are applied based on current options (e.g. hidden files not returned)
pub fn iter_files(&self) -> impl Iterator<Item = &Entry> + '_ {
pub fn iter_files(&self) -> impl Iterator<Item = &File> + '_ {
// Filter
let opts: ExplorerOpts = self.opts;
Box::new(self.files.iter().filter(move |x| {
@@ -146,12 +146,12 @@ impl FileExplorer {
}
/// Iterate all files; doesn't care about options
pub fn iter_files_all(&self) -> impl Iterator<Item = &Entry> + '_ {
pub fn iter_files_all(&self) -> impl Iterator<Item = &File> + '_ {
Box::new(self.files.iter())
}
/// Get file at relative index
pub fn get(&self, idx: usize) -> Option<&Entry> {
pub fn get(&self, idx: usize) -> Option<&File> {
let opts: ExplorerOpts = self.opts;
let filtered = self
.files
@@ -172,7 +172,7 @@ impl FileExplorer {
// Formatting
/// Format a file entry
pub fn fmt_file(&self, entry: &Entry) -> String {
pub fn fmt_file(&self, entry: &File) -> String {
self.fmt.fmt(entry)
}
@@ -222,35 +222,35 @@ impl FileExplorer {
/// Sort explorer files by their name. All names are converted to lowercase
fn sort_files_by_name(&mut self) {
self.files.sort_by_key(|x: &Entry| x.name().to_lowercase());
self.files.sort_by_key(|x: &File| x.name().to_lowercase());
}
/// Sort files by mtime; the newest comes first
fn sort_files_by_mtime(&mut self) {
self.files
.sort_by(|a: &Entry, b: &Entry| b.metadata().mtime.cmp(&a.metadata().mtime));
.sort_by_key(|b: &File| Reverse(b.metadata().modified));
}
/// Sort files by creation time; the newest comes first
fn sort_files_by_creation_time(&mut self) {
self.files
.sort_by_key(|b: &Entry| Reverse(b.metadata().ctime));
.sort_by_key(|b: &File| Reverse(b.metadata().created));
}
/// Sort files by size
fn sort_files_by_size(&mut self) {
self.files
.sort_by_key(|b: &Entry| Reverse(b.metadata().size));
.sort_by_key(|b: &File| Reverse(b.metadata().size));
}
/// Sort files; directories come first
fn sort_files_directories_first(&mut self) {
self.files.sort_by_key(|x: &Entry| x.is_file());
self.files.sort_by_key(|x: &File| !x.is_dir());
}
/// Sort files; directories come last
fn sort_files_directories_last(&mut self) {
self.files.sort_by_key(|x: &Entry| x.is_dir());
self.files.sort_by_key(|x: &File| x.is_dir());
}
/// Enable/disable hidden files
@@ -317,7 +317,7 @@ mod tests {
use crate::utils::fmt::fmt_time;
use pretty_assertions::assert_eq;
use remotefs::fs::{Directory, File, Metadata, UnixPex};
use remotefs::fs::{File, FileType, Metadata, UnixPex};
use std::thread::sleep;
use std::time::{Duration, SystemTime};
@@ -371,8 +371,8 @@ mod tests {
// Create files
explorer.set_files(vec![
make_fs_entry("README.md", false),
make_fs_entry("src/", true),
make_fs_entry(".git/", true),
make_fs_entry("src", true),
make_fs_entry(".git", true),
make_fs_entry("CONTRIBUTING.md", false),
make_fs_entry("codecov.yml", false),
make_fs_entry(".gitignore", false),
@@ -381,7 +381,7 @@ mod tests {
assert!(explorer.get(100).is_none());
//assert_eq!(explorer.count(), 6);
// Verify (files are sorted by name)
assert_eq!(explorer.files.get(0).unwrap().name(), ".git/");
assert_eq!(explorer.files.get(0).unwrap().name(), ".git");
// Iter files (all)
assert_eq!(explorer.iter_files_all().count(), 6);
// Iter files (hidden excluded) (.git, .gitignore are hidden)
@@ -398,7 +398,7 @@ mod tests {
// Create files (files are then sorted by name)
explorer.set_files(vec![
make_fs_entry("README.md", false),
make_fs_entry("src/", true),
make_fs_entry("src", true),
make_fs_entry("CONTRIBUTING.md", false),
make_fs_entry("CODE_OF_CONDUCT.md", false),
make_fs_entry("CHANGELOG.md", false),
@@ -410,39 +410,39 @@ mod tests {
explorer.sort_by(FileSorting::Name);
// First entry should be "Cargo.lock"
assert_eq!(explorer.files.get(0).unwrap().name(), "Cargo.lock");
// Last should be "src/"
assert_eq!(explorer.files.get(8).unwrap().name(), "src/");
// Last should be "src"
assert_eq!(explorer.files.get(8).unwrap().name(), "src");
}
#[test]
fn test_fs_explorer_sort_by_mtime() {
let mut explorer: FileExplorer = FileExplorer::default();
let entry1: Entry = make_fs_entry("README.md", false);
let entry1: File = make_fs_entry("README.md", false);
// Wait 1 sec
sleep(Duration::from_secs(1));
let entry2: Entry = make_fs_entry("CODE_OF_CONDUCT.md", false);
let entry2: File = make_fs_entry("CODE_OF_CONDUCT.md", false);
// Create files (files are then sorted by name)
explorer.set_files(vec![entry1, entry2]);
explorer.sort_by(FileSorting::ModifyTime);
// First entry should be "CODE_OF_CONDUCT.md"
assert_eq!(explorer.files.get(0).unwrap().name(), "CODE_OF_CONDUCT.md");
// Last should be "src/"
// Last should be "src"
assert_eq!(explorer.files.get(1).unwrap().name(), "README.md");
}
#[test]
fn test_fs_explorer_sort_by_creation_time() {
let mut explorer: FileExplorer = FileExplorer::default();
let entry1: Entry = make_fs_entry("README.md", false);
let entry1: File = make_fs_entry("README.md", false);
// Wait 1 sec
sleep(Duration::from_secs(1));
let entry2: Entry = make_fs_entry("CODE_OF_CONDUCT.md", false);
let entry2: File = make_fs_entry("CODE_OF_CONDUCT.md", false);
// Create files (files are then sorted by name)
explorer.set_files(vec![entry1, entry2]);
explorer.sort_by(FileSorting::CreationTime);
// First entry should be "CODE_OF_CONDUCT.md"
assert_eq!(explorer.files.get(0).unwrap().name(), "CODE_OF_CONDUCT.md");
// Last should be "src/"
// Last should be "src"
assert_eq!(explorer.files.get(1).unwrap().name(), "README.md");
}
@@ -452,12 +452,12 @@ mod tests {
// Create files (files are then sorted by name)
explorer.set_files(vec![
make_fs_entry_with_size("README.md", false, 1024),
make_fs_entry_with_size("src/", true, 4096),
make_fs_entry_with_size("src", true, 4096),
make_fs_entry_with_size("CONTRIBUTING.md", false, 256),
]);
explorer.sort_by(FileSorting::Size);
// Directory has size 4096
assert_eq!(explorer.files.get(0).unwrap().name(), "src/");
assert_eq!(explorer.files.get(0).unwrap().name(), "src");
assert_eq!(explorer.files.get(1).unwrap().name(), "README.md");
assert_eq!(explorer.files.get(2).unwrap().name(), "CONTRIBUTING.md");
}
@@ -468,8 +468,8 @@ mod tests {
// Create files (files are then sorted by name)
explorer.set_files(vec![
make_fs_entry("README.md", false),
make_fs_entry("src/", true),
make_fs_entry("docs/", true),
make_fs_entry("src", true),
make_fs_entry("docs", true),
make_fs_entry("CONTRIBUTING.md", false),
make_fs_entry("CODE_OF_CONDUCT.md", false),
make_fs_entry("CHANGELOG.md", false),
@@ -481,8 +481,8 @@ mod tests {
explorer.sort_by(FileSorting::Name);
explorer.group_dirs_by(Some(GroupDirs::First));
// First entry should be "docs"
assert_eq!(explorer.files.get(0).unwrap().name(), "docs/");
assert_eq!(explorer.files.get(1).unwrap().name(), "src/");
assert_eq!(explorer.files.get(0).unwrap().name(), "docs");
assert_eq!(explorer.files.get(1).unwrap().name(), "src");
// 3rd is file first for alphabetical order
assert_eq!(explorer.files.get(2).unwrap().name(), "Cargo.lock");
// Last should be "README.md" (last file for alphabetical ordening)
@@ -495,8 +495,8 @@ mod tests {
// Create files (files are then sorted by name)
explorer.set_files(vec![
make_fs_entry("README.md", false),
make_fs_entry("src/", true),
make_fs_entry("docs/", true),
make_fs_entry("src", true),
make_fs_entry("docs", true),
make_fs_entry("CONTRIBUTING.md", false),
make_fs_entry("CODE_OF_CONDUCT.md", false),
make_fs_entry("CHANGELOG.md", false),
@@ -508,8 +508,8 @@ mod tests {
explorer.sort_by(FileSorting::Name);
explorer.group_dirs_by(Some(GroupDirs::Last));
// Last entry should be "src"
assert_eq!(explorer.files.get(8).unwrap().name(), "docs/");
assert_eq!(explorer.files.get(9).unwrap().name(), "src/");
assert_eq!(explorer.files.get(8).unwrap().name(), "docs");
assert_eq!(explorer.files.get(9).unwrap().name(), "src");
// first is file for alphabetical order
assert_eq!(explorer.files.get(0).unwrap().name(), "Cargo.lock");
// Last in files should be "README.md" (last file for alphabetical ordening)
@@ -521,21 +521,20 @@ mod tests {
let explorer: FileExplorer = FileExplorer::default();
// Create fs entry
let t: SystemTime = SystemTime::now();
let entry: Entry = Entry::File(File {
name: String::from("bar.txt"),
let entry = File {
path: PathBuf::from("/bar.txt"),
extension: Some(String::from("txt")),
metadata: Metadata {
atime: t,
ctime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: FileType::File,
size: 8192,
mtime: t,
symlink: None,
uid: Some(0),
gid: Some(0),
mode: Some(UnixPex::from(0o644)),
},
});
};
#[cfg(target_family = "unix")]
assert_eq!(
explorer.fmt_file(&entry),
@@ -592,68 +591,60 @@ mod tests {
// Create files (files are then sorted by name)
explorer.set_files(vec![
make_fs_entry("CONTRIBUTING.md", false),
make_fs_entry("docs/", true),
make_fs_entry("src/", true),
make_fs_entry("docs", true),
make_fs_entry("src", true),
make_fs_entry("README.md", false),
]);
explorer.del_entry(0);
assert_eq!(explorer.files.len(), 3);
assert_eq!(explorer.files[0].name(), "docs/");
assert_eq!(explorer.files[0].name(), "docs");
explorer.del_entry(5);
assert_eq!(explorer.files.len(), 3);
}
fn make_fs_entry(name: &str, is_dir: bool) -> Entry {
fn make_fs_entry(name: &str, is_dir: bool) -> File {
let t: SystemTime = SystemTime::now();
let metadata = Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: if is_dir {
FileType::Directory
} else {
FileType::File
},
symlink: None,
gid: Some(0),
uid: Some(0),
mode: Some(UnixPex::from(if is_dir { 0o755 } else { 0o644 })),
size: 64,
};
match is_dir {
false => Entry::File(File {
name: name.to_string(),
path: PathBuf::from(name),
extension: None,
metadata,
}),
true => Entry::Directory(Directory {
name: name.to_string(),
path: PathBuf::from(name),
metadata,
}),
File {
path: PathBuf::from(name),
metadata,
}
}
fn make_fs_entry_with_size(name: &str, is_dir: bool, size: usize) -> Entry {
fn make_fs_entry_with_size(name: &str, is_dir: bool, size: usize) -> File {
let t: SystemTime = SystemTime::now();
let metadata = Metadata {
atime: t,
ctime: t,
mtime: t,
accessed: Some(t),
created: Some(t),
modified: Some(t),
file_type: if is_dir {
FileType::Directory
} else {
FileType::File
},
symlink: None,
gid: Some(0),
uid: Some(0),
mode: Some(UnixPex::from(if is_dir { 0o755 } else { 0o644 })),
size: size as u64,
};
match is_dir {
false => Entry::File(File {
name: name.to_string(),
path: PathBuf::from(name),
extension: None,
metadata,
}),
true => Entry::Directory(Directory {
name: name.to_string(),
path: PathBuf::from(name),
metadata,
}),
File {
path: PathBuf::from(name),
metadata,
}
}
}