|
|
|
@ -91,6 +91,7 @@ pub struct ResolvedNode {
|
|
|
|
|
pub is_file: bool,
|
|
|
|
|
pub is_readonly: bool,
|
|
|
|
|
pub mime_essence: String,
|
|
|
|
|
pub size: u64,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ResolvedNode {
|
|
|
|
@ -100,15 +101,10 @@ impl ResolvedNode {
|
|
|
|
|
.map(|e| e.to_string_lossy().to_string())
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
let maybe_metadata = path.metadata().ok();
|
|
|
|
|
|
|
|
|
|
let is_dir = maybe_metadata.clone().map(|m| m.is_dir()).unwrap_or(false);
|
|
|
|
|
|
|
|
|
|
let is_file = maybe_metadata.clone().map(|m| m.is_file()).unwrap_or(false);
|
|
|
|
|
|
|
|
|
|
let is_readonly = maybe_metadata
|
|
|
|
|
.map(|m| m.permissions().readonly())
|
|
|
|
|
.unwrap_or(false);
|
|
|
|
|
let (is_dir, is_file, is_readonly, size) = path
|
|
|
|
|
.metadata()
|
|
|
|
|
.map(|m| (m.is_dir(), m.is_file(), m.permissions().readonly(), m.len()))
|
|
|
|
|
.unwrap_or((false, false, false, 0));
|
|
|
|
|
|
|
|
|
|
let mime_essence = mime_guess::from_path(&path)
|
|
|
|
|
.first()
|
|
|
|
@ -122,6 +118,7 @@ impl ResolvedNode {
|
|
|
|
|
is_file,
|
|
|
|
|
is_readonly,
|
|
|
|
|
mime_essence,
|
|
|
|
|
size,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -138,6 +135,7 @@ pub struct Node {
|
|
|
|
|
pub is_broken: bool,
|
|
|
|
|
pub is_readonly: bool,
|
|
|
|
|
pub mime_essence: String,
|
|
|
|
|
pub size: u64,
|
|
|
|
|
pub canonical: Option<ResolvedNode>,
|
|
|
|
|
pub symlink: Option<ResolvedNode>,
|
|
|
|
|
}
|
|
|
|
@ -156,25 +154,23 @@ impl Node {
|
|
|
|
|
.map(|e| e.to_string_lossy().to_string())
|
|
|
|
|
.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
let maybe_metadata = path.symlink_metadata().ok();
|
|
|
|
|
|
|
|
|
|
let is_symlink = maybe_metadata
|
|
|
|
|
.clone()
|
|
|
|
|
.map(|m| m.file_type().is_symlink())
|
|
|
|
|
.unwrap_or(false);
|
|
|
|
|
|
|
|
|
|
let (is_broken, maybe_canonical_meta) = path
|
|
|
|
|
.canonicalize()
|
|
|
|
|
.map(|p| (false, Some(ResolvedNode::from(p))))
|
|
|
|
|
.unwrap_or_else(|_| (true, None));
|
|
|
|
|
|
|
|
|
|
let is_dir = maybe_metadata.clone().map(|m| m.is_dir()).unwrap_or(false);
|
|
|
|
|
|
|
|
|
|
let is_file = maybe_metadata.clone().map(|m| m.is_file()).unwrap_or(false);
|
|
|
|
|
|
|
|
|
|
let is_readonly = maybe_metadata
|
|
|
|
|
.map(|m| m.permissions().readonly())
|
|
|
|
|
.unwrap_or(false);
|
|
|
|
|
let (is_symlink, is_dir, is_file, is_readonly, size) = path
|
|
|
|
|
.symlink_metadata()
|
|
|
|
|
.map(|m| {
|
|
|
|
|
(
|
|
|
|
|
m.file_type().is_symlink(),
|
|
|
|
|
m.is_dir(),
|
|
|
|
|
m.is_file(),
|
|
|
|
|
m.permissions().readonly(),
|
|
|
|
|
m.len(),
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or((false, false, false, false, 0));
|
|
|
|
|
|
|
|
|
|
let mime_essence = mime_guess::from_path(&path)
|
|
|
|
|
.first()
|
|
|
|
@ -192,6 +188,7 @@ impl Node {
|
|
|
|
|
is_broken,
|
|
|
|
|
is_readonly,
|
|
|
|
|
mime_essence,
|
|
|
|
|
size,
|
|
|
|
|
canonical: maybe_canonical_meta.clone(),
|
|
|
|
|
symlink: if is_symlink {
|
|
|
|
|
maybe_canonical_meta
|
|
|
|
@ -258,6 +255,7 @@ pub enum NodeSorter {
|
|
|
|
|
ByIsBroken,
|
|
|
|
|
ByIsReadonly,
|
|
|
|
|
ByMimeEssence,
|
|
|
|
|
BySize,
|
|
|
|
|
|
|
|
|
|
ByCanonicalAbsolutePath,
|
|
|
|
|
ByICanonicalAbsolutePath,
|
|
|
|
@ -266,6 +264,7 @@ pub enum NodeSorter {
|
|
|
|
|
ByCanonicalIsFile,
|
|
|
|
|
ByCanonicalIsReadonly,
|
|
|
|
|
ByCanonicalMimeEssence,
|
|
|
|
|
ByCanonicalSize,
|
|
|
|
|
|
|
|
|
|
BySymlinkAbsolutePath,
|
|
|
|
|
ByISymlinkAbsolutePath,
|
|
|
|
@ -274,6 +273,7 @@ pub enum NodeSorter {
|
|
|
|
|
BySymlinkIsFile,
|
|
|
|
|
BySymlinkIsReadonly,
|
|
|
|
|
BySymlinkMimeEssence,
|
|
|
|
|
BySymlinkSize,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Eq, Serialize, Deserialize)]
|
|
|
|
@ -330,6 +330,8 @@ impl NodeSorterApplicable {
|
|
|
|
|
(NodeSorter::ByIsReadonly, true) => b.is_readonly.cmp(&a.is_readonly),
|
|
|
|
|
(NodeSorter::ByMimeEssence, false) => a.mime_essence.cmp(&b.mime_essence),
|
|
|
|
|
(NodeSorter::ByMimeEssence, true) => b.mime_essence.cmp(&a.mime_essence),
|
|
|
|
|
(NodeSorter::BySize, false) => a.size.cmp(&b.size),
|
|
|
|
|
(NodeSorter::BySize, true) => b.size.cmp(&a.size),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalAbsolutePath, false) => natord::compare(
|
|
|
|
|
&a.canonical
|
|
|
|
@ -342,23 +344,23 @@ impl NodeSorterApplicable {
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByICanonicalAbsolutePath, false) => natord::compare_ignore_case(
|
|
|
|
|
&a.canonical
|
|
|
|
|
(NodeSorter::ByCanonicalAbsolutePath, true) => natord::compare(
|
|
|
|
|
&b.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s.absolute_path.clone())
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
&b.canonical
|
|
|
|
|
&a.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s.absolute_path.clone())
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalAbsolutePath, true) => natord::compare(
|
|
|
|
|
&b.canonical
|
|
|
|
|
(NodeSorter::ByICanonicalAbsolutePath, false) => natord::compare_ignore_case(
|
|
|
|
|
&a.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s.absolute_path.clone())
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
&a.canonical
|
|
|
|
|
&b.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s.absolute_path.clone())
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
@ -393,17 +395,29 @@ impl NodeSorterApplicable {
|
|
|
|
|
.map(|s| &s.is_dir)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.is_dir)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalIsDir, true) => b
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.is_dir)
|
|
|
|
|
.cmp(&a.canonical.as_ref().map(|s| &s.is_dir)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalIsFile, false) => a
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.is_file)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.is_file)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalIsFile, true) => b
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.is_file)
|
|
|
|
|
.cmp(&a.canonical.as_ref().map(|s| &s.is_file)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalIsDir, true) => b
|
|
|
|
|
(NodeSorter::ByCanonicalIsReadonly, false) => a
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.is_dir)
|
|
|
|
|
.cmp(&a.canonical.as_ref().map(|s| &s.is_dir)),
|
|
|
|
|
.map(|s| &s.is_readonly)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.is_readonly)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalIsReadonly, true) => b
|
|
|
|
|
.canonical
|
|
|
|
@ -411,11 +425,11 @@ impl NodeSorterApplicable {
|
|
|
|
|
.map(|s| &s.is_readonly)
|
|
|
|
|
.cmp(&a.canonical.as_ref().map(|s| &s.is_readonly)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalIsFile, false) => a
|
|
|
|
|
(NodeSorter::ByCanonicalMimeEssence, false) => a
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.is_file)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.is_file)),
|
|
|
|
|
.map(|s| &s.mime_essence)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.mime_essence)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalMimeEssence, true) => b
|
|
|
|
|
.canonical
|
|
|
|
@ -423,17 +437,17 @@ impl NodeSorterApplicable {
|
|
|
|
|
.map(|s| &s.mime_essence)
|
|
|
|
|
.cmp(&a.canonical.as_ref().map(|s| &s.mime_essence)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalIsReadonly, false) => a
|
|
|
|
|
(NodeSorter::ByCanonicalSize, false) => a
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.is_readonly)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.is_readonly)),
|
|
|
|
|
.map(|s| &s.size)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.size)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByCanonicalMimeEssence, false) => a
|
|
|
|
|
(NodeSorter::ByCanonicalSize, true) => b
|
|
|
|
|
.canonical
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.mime_essence)
|
|
|
|
|
.cmp(&b.canonical.as_ref().map(|s| &s.mime_essence)),
|
|
|
|
|
.map(|s| &s.size)
|
|
|
|
|
.cmp(&a.canonical.as_ref().map(|s| &s.size)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkAbsolutePath, false) => natord::compare(
|
|
|
|
|
&a.symlink
|
|
|
|
@ -446,23 +460,23 @@ impl NodeSorterApplicable {
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::ByISymlinkAbsolutePath, false) => natord::compare_ignore_case(
|
|
|
|
|
&a.symlink
|
|
|
|
|
(NodeSorter::BySymlinkAbsolutePath, true) => natord::compare(
|
|
|
|
|
&b.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s.absolute_path.clone())
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
&b.symlink
|
|
|
|
|
&a.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s.absolute_path.clone())
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkAbsolutePath, true) => natord::compare(
|
|
|
|
|
&b.symlink
|
|
|
|
|
(NodeSorter::ByISymlinkAbsolutePath, false) => natord::compare_ignore_case(
|
|
|
|
|
&a.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s.absolute_path.clone())
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
&a.symlink
|
|
|
|
|
&b.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s.absolute_path.clone())
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
@ -479,17 +493,23 @@ impl NodeSorterApplicable {
|
|
|
|
|
.unwrap_or_default(),
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkExtension, false) => a
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.extension)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.extension)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkExtension, true) => b
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.extension)
|
|
|
|
|
.cmp(&a.symlink.as_ref().map(|s| &s.extension)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkExtension, false) => a
|
|
|
|
|
(NodeSorter::BySymlinkIsDir, false) => a
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.extension)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.extension)),
|
|
|
|
|
.map(|s| &s.is_dir)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.is_dir)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkIsDir, true) => b
|
|
|
|
|
.symlink
|
|
|
|
@ -497,11 +517,11 @@ impl NodeSorterApplicable {
|
|
|
|
|
.map(|s| &s.is_dir)
|
|
|
|
|
.cmp(&a.symlink.as_ref().map(|s| &s.is_dir)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkIsDir, false) => a
|
|
|
|
|
(NodeSorter::BySymlinkIsFile, false) => a
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.is_dir)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.is_dir)),
|
|
|
|
|
.map(|s| &s.is_file)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.is_file)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkIsFile, true) => b
|
|
|
|
|
.symlink
|
|
|
|
@ -509,11 +529,11 @@ impl NodeSorterApplicable {
|
|
|
|
|
.map(|s| &s.is_file)
|
|
|
|
|
.cmp(&a.symlink.as_ref().map(|s| &s.is_file)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkIsFile, false) => a
|
|
|
|
|
(NodeSorter::BySymlinkIsReadonly, false) => a
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.is_file)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.is_file)),
|
|
|
|
|
.map(|s| &s.is_readonly)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.is_readonly)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkIsReadonly, true) => b
|
|
|
|
|
.symlink
|
|
|
|
@ -521,11 +541,11 @@ impl NodeSorterApplicable {
|
|
|
|
|
.map(|s| &s.is_readonly)
|
|
|
|
|
.cmp(&a.symlink.as_ref().map(|s| &s.is_readonly)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkIsReadonly, false) => a
|
|
|
|
|
(NodeSorter::BySymlinkMimeEssence, false) => a
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.is_readonly)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.is_readonly)),
|
|
|
|
|
.map(|s| &s.mime_essence)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.mime_essence)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkMimeEssence, true) => b
|
|
|
|
|
.symlink
|
|
|
|
@ -533,11 +553,17 @@ impl NodeSorterApplicable {
|
|
|
|
|
.map(|s| &s.mime_essence)
|
|
|
|
|
.cmp(&a.symlink.as_ref().map(|s| &s.mime_essence)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkMimeEssence, false) => a
|
|
|
|
|
(NodeSorter::BySymlinkSize, false) => a
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.mime_essence)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.mime_essence)),
|
|
|
|
|
.map(|s| &s.size)
|
|
|
|
|
.cmp(&b.symlink.as_ref().map(|s| &s.size)),
|
|
|
|
|
|
|
|
|
|
(NodeSorter::BySymlinkSize, true) => b
|
|
|
|
|
.symlink
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| &s.size)
|
|
|
|
|
.cmp(&a.symlink.as_ref().map(|s| &s.size)),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|