|
|
|
@ -33,11 +33,16 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
|
|
|
pub const TEMPLATE_TABLE_ROW: &str = "TEMPLATE_TABLE_ROW";
|
|
|
|
|
pub const UNSUPPORTED_STR: &str = "???";
|
|
|
|
|
|
|
|
|
|
fn to_humansize(size: u64) -> String {
|
|
|
|
|
fn to_human_size(size: u64) -> String {
|
|
|
|
|
size.file_size(options::CONVENTIONAL)
|
|
|
|
|
.unwrap_or_else(|_| format!("{} B", size))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn to_human_timestamp(t: Option<DateTime<Local>>) -> String {
|
|
|
|
|
t.map(|l: DateTime<Local>| l.format("%y-%m-%d %H:%M:%S").to_string())
|
|
|
|
|
.unwrap_or_default()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn mime_essence(path: &Path, is_dir: bool) -> String {
|
|
|
|
|
if is_dir {
|
|
|
|
|
String::from("inode/directory")
|
|
|
|
@ -49,12 +54,6 @@ fn mime_essence(path: &Path, is_dir: bool) -> String {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn to_human_modified(modified: Option<DateTime<Local>>) -> String {
|
|
|
|
|
modified.map_or("".to_string(), |l: DateTime<Local>| {
|
|
|
|
|
l.format("%b %d %R").to_string()
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct Pipe {
|
|
|
|
|
pub path: String,
|
|
|
|
@ -116,8 +115,10 @@ pub struct ResolvedNode {
|
|
|
|
|
pub mime_essence: String,
|
|
|
|
|
pub size: u64,
|
|
|
|
|
pub human_size: String,
|
|
|
|
|
pub last_modified: Option<DateTime<Local>>,
|
|
|
|
|
pub human_modified: String,
|
|
|
|
|
pub created: Option<i64>,
|
|
|
|
|
pub human_created: String,
|
|
|
|
|
pub last_modified: Option<i64>,
|
|
|
|
|
pub human_last_modified: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ResolvedNode {
|
|
|
|
@ -127,7 +128,7 @@ impl ResolvedNode {
|
|
|
|
|
.map(|e| e.to_string_lossy().to_string())
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
let (is_dir, is_file, is_readonly, size, last_modified) = path
|
|
|
|
|
let (is_dir, is_file, is_readonly, size, created, last_modified) = path
|
|
|
|
|
.metadata()
|
|
|
|
|
.map(|m| {
|
|
|
|
|
(
|
|
|
|
@ -135,16 +136,16 @@ impl ResolvedNode {
|
|
|
|
|
m.is_file(),
|
|
|
|
|
m.permissions().readonly(),
|
|
|
|
|
m.len(),
|
|
|
|
|
m.modified()
|
|
|
|
|
.map(|md| Some(md.into()))
|
|
|
|
|
.unwrap_or_else(|_| None),
|
|
|
|
|
m.created().ok().map(From::from),
|
|
|
|
|
m.modified().ok().map(From::from),
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or((false, false, false, 0, None));
|
|
|
|
|
.unwrap_or((false, false, false, 0, None, None));
|
|
|
|
|
|
|
|
|
|
let human_modified = to_human_modified(last_modified);
|
|
|
|
|
let human_last_modified = to_human_timestamp(last_modified);
|
|
|
|
|
let human_created = to_human_timestamp(created);
|
|
|
|
|
let mime_essence = mime_essence(&path, is_dir);
|
|
|
|
|
let human_size = to_humansize(size);
|
|
|
|
|
let human_size = to_human_size(size);
|
|
|
|
|
|
|
|
|
|
Self {
|
|
|
|
|
absolute_path: path.to_string_lossy().to_string(),
|
|
|
|
@ -155,8 +156,10 @@ impl ResolvedNode {
|
|
|
|
|
mime_essence,
|
|
|
|
|
size,
|
|
|
|
|
human_size,
|
|
|
|
|
last_modified,
|
|
|
|
|
human_modified,
|
|
|
|
|
created: created.map(|t| t.timestamp()),
|
|
|
|
|
human_created,
|
|
|
|
|
last_modified: last_modified.map(|t| t.timestamp()),
|
|
|
|
|
human_last_modified,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -178,8 +181,10 @@ pub struct Node {
|
|
|
|
|
pub permissions: Permissions,
|
|
|
|
|
pub canonical: Option<ResolvedNode>,
|
|
|
|
|
pub symlink: Option<ResolvedNode>,
|
|
|
|
|
pub last_modified: Option<DateTime<Local>>,
|
|
|
|
|
pub human_modified: String,
|
|
|
|
|
pub created: Option<i64>,
|
|
|
|
|
pub human_created: String,
|
|
|
|
|
pub last_modified: Option<i64>,
|
|
|
|
|
pub human_last_modified: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Node {
|
|
|
|
@ -208,6 +213,7 @@ impl Node {
|
|
|
|
|
is_readonly,
|
|
|
|
|
size,
|
|
|
|
|
permissions,
|
|
|
|
|
created,
|
|
|
|
|
last_modified,
|
|
|
|
|
) = path
|
|
|
|
|
.symlink_metadata()
|
|
|
|
@ -219,18 +225,27 @@ impl Node {
|
|
|
|
|
m.permissions().readonly(),
|
|
|
|
|
m.len(),
|
|
|
|
|
Permissions::from(&m),
|
|
|
|
|
m.modified()
|
|
|
|
|
.map(|md| Some(md.into()))
|
|
|
|
|
.unwrap_or_else(|_| None),
|
|
|
|
|
m.created().ok().map(From::from),
|
|
|
|
|
m.modified().ok().map(From::from),
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_else(|_| {
|
|
|
|
|
(false, false, false, false, 0, Permissions::default(), None)
|
|
|
|
|
(
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
false,
|
|
|
|
|
0,
|
|
|
|
|
Permissions::default(),
|
|
|
|
|
None,
|
|
|
|
|
None,
|
|
|
|
|
)
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let human_modified = to_human_modified(last_modified);
|
|
|
|
|
let human_created = to_human_timestamp(created);
|
|
|
|
|
let human_last_modified = to_human_timestamp(last_modified);
|
|
|
|
|
let mime_essence = mime_essence(&path, is_dir);
|
|
|
|
|
let human_size = to_humansize(size);
|
|
|
|
|
let human_size = to_human_size(size);
|
|
|
|
|
|
|
|
|
|
Self {
|
|
|
|
|
parent,
|
|
|
|
@ -252,8 +267,10 @@ impl Node {
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
},
|
|
|
|
|
last_modified,
|
|
|
|
|
human_modified,
|
|
|
|
|
created: created.map(|t| t.timestamp()),
|
|
|
|
|
human_created,
|
|
|
|
|
last_modified: last_modified.map(|t| t.timestamp()),
|
|
|
|
|
human_last_modified,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -316,6 +333,8 @@ pub enum NodeSorter {
|
|
|
|
|
ByIsBroken,
|
|
|
|
|
ByIsReadonly,
|
|
|
|
|
ByMimeEssence,
|
|
|
|
|
ByCreated,
|
|
|
|
|
ByLastModified,
|
|
|
|
|
BySize,
|
|
|
|
|
|
|
|
|
|
ByCanonicalAbsolutePath,
|
|
|
|
@ -325,6 +344,8 @@ pub enum NodeSorter {
|
|
|
|
|
ByCanonicalIsFile,
|
|
|
|
|
ByCanonicalIsReadonly,
|
|
|
|
|
ByCanonicalMimeEssence,
|
|
|
|
|
ByCanonicalCreated,
|
|
|
|
|
ByCanonicalLastModified,
|
|
|
|
|
ByCanonicalSize,
|
|
|
|
|
|
|
|
|
|
BySymlinkAbsolutePath,
|
|
|
|
@ -334,6 +355,8 @@ pub enum NodeSorter {
|
|
|
|
|
BySymlinkIsFile,
|
|
|
|
|
BySymlinkIsReadonly,
|
|
|
|
|
BySymlinkMimeEssence,
|
|
|
|
|
BySymlinkCreated,
|
|
|
|
|
BySymlinkLastModified,
|
|
|
|
|
BySymlinkSize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -378,6 +401,8 @@ impl NodeSorterApplicable {
|
|
|
|
|
NodeSorter::ByIsBroken => a.is_broken.cmp(&b.is_broken),
|
|
|
|
|
NodeSorter::ByIsReadonly => a.is_readonly.cmp(&b.is_readonly),
|
|
|
|
|
NodeSorter::ByMimeEssence => a.mime_essence.cmp(&b.mime_essence),
|
|
|
|
|
NodeSorter::ByCreated => a.created.cmp(&b.created),
|
|
|
|
|
NodeSorter::ByLastModified => a.last_modified.cmp(&b.last_modified),
|
|
|
|
|
NodeSorter::BySize => a.size.cmp(&b.size),
|
|
|
|
|
|
|
|
|
|
NodeSorter::ByCanonicalAbsolutePath => natord::compare(
|
|
|
|
@ -434,6 +459,18 @@ impl NodeSorterApplicable {
|
|
|
|
|
.map(|s| &s.mime_essence)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.mime_essence)),
|
|
|
|
|
|
|
|
|
|
NodeSorter::ByCanonicalCreated => a
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.created)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.created)),
|
|
|
|
|
|
|
|
|
|
NodeSorter::ByCanonicalLastModified => a
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.last_modified)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.last_modified)),
|
|
|
|
|
|
|
|
|
|
NodeSorter::ByCanonicalSize => a
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
@ -492,6 +529,18 @@ impl NodeSorterApplicable {
|
|
|
|
|
.map(|s| &s.mime_essence)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.mime_essence)),
|
|
|
|
|
|
|
|
|
|
NodeSorter::BySymlinkCreated => a
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.created)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.created)),
|
|
|
|
|
|
|
|
|
|
NodeSorter::BySymlinkLastModified => a
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.last_modified)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.last_modified)),
|
|
|
|
|
|
|
|
|
|
NodeSorter::BySymlinkSize => a
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|