Compare commits

...

15 Commits

Author SHA1 Message Date
andy.boot 07ffd04950 Increment version
This version includes fix for the -f flag
2021-08-05 08:47:47 +01:00
andy.boot dfa574375b clippy: Fix clippy lints
New rustup adds more lints
2021-08-05 08:47:47 +01:00
andy.boot 9de2e7d723 bugfix: Fix crash when using '-f' flag
The old code was subtly different in the way the root node worked. This
changed in the v0.6.0 version when dependencies were removed. The code
to handle file count was never updated

https://github.com/bootandy/dust/issues/162
2021-07-29 08:54:32 +01:00
andy.boot 8fddb24165 Increment version 2021-07-19 14:09:21 +01:00
andy.boot ed3902f07e Rename file: dirwalker -> dir_walker
Felt like this file was missing an '_'
2021-07-16 14:13:12 +01:00
andy.boot f219a752d6 Refactor: Compress arguemnts to one object
Several arguments were passed around the dirwalker file. Compress them
into a single struct.
2021-07-16 14:13:12 +01:00
andy.boot f6e36aba52 Feature: Re-introduce -x flag to limit filesystem
-x flag allows dust to limit itself to the current filesystem
2021-07-16 14:13:12 +01:00
andy.boot c286b8ba97 Revert "README: Remove -x option"
This reverts commit 1d062cf683.
2021-07-16 14:13:12 +01:00
andy.boot 3dad7abfb8 Change size of softlinks to 0
Instead of the size of what they point at
2021-07-16 14:13:12 +01:00
andy.boot 42163abb73 Cargo: Remove num_cpus library. Ran update
Not needed since v0.6.0
Ran cargo update
2021-07-07 18:35:05 +01:00
andy.boot 8e0188c755 README: Update usage examples of dust 2021-07-07 18:35:05 +01:00
andy.boot 555d86206d ci: update versions of ubuntu 2021-06-23 10:05:48 +01:00
andy.boot 02392881c5 Update version 2021-06-23 09:40:58 +01:00
andy.boot 6f1175ef8d README: Add another tool to list of alternatives 2021-06-23 09:40:58 +01:00
andy.boot 1d062cf683 README: Remove -x option
This behaviour was removed in previous commit
2021-06-23 09:40:58 +01:00
12 changed files with 149 additions and 93 deletions
+4 -4
View File
@@ -82,11 +82,11 @@ jobs:
job: job:
# { os, target, cargo-options, features, use-cross, toolchain } # { os, target, cargo-options, features, use-cross, toolchain }
- { os: ubuntu-latest , target: arm-unknown-linux-gnueabihf , use-cross: use-cross } - { os: ubuntu-latest , target: arm-unknown-linux-gnueabihf , use-cross: use-cross }
- { os: ubuntu-18.04 , target: i686-unknown-linux-gnu , use-cross: use-cross } - { os: ubuntu-20.04 , target: i686-unknown-linux-gnu , use-cross: use-cross }
- { os: ubuntu-18.04 , target: i686-unknown-linux-musl , use-cross: use-cross } - { os: ubuntu-20.04 , target: i686-unknown-linux-musl , use-cross: use-cross }
- { os: ubuntu-20.04 , target: x86_64-unknown-linux-gnu , use-cross: use-cross }
- { os: ubuntu-20.04 , target: x86_64-unknown-linux-musl , use-cross: use-cross }
- { os: ubuntu-18.04 , target: x86_64-unknown-linux-gnu , use-cross: use-cross } - { os: ubuntu-18.04 , target: x86_64-unknown-linux-gnu , use-cross: use-cross }
- { os: ubuntu-18.04 , target: x86_64-unknown-linux-musl , use-cross: use-cross }
- { os: ubuntu-16.04 , target: x86_64-unknown-linux-gnu , use-cross: use-cross }
- { os: macos-latest , target: x86_64-apple-darwin } - { os: macos-latest , target: x86_64-apple-darwin }
- { os: windows-latest , target: i686-pc-windows-gnu } - { os: windows-latest , target: i686-pc-windows-gnu }
- { os: windows-latest , target: i686-pc-windows-msvc } - { os: windows-latest , target: i686-pc-windows-msvc }
Generated
+25 -14
View File
@@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.18" version = "0.7.18"
@@ -29,9 +31,9 @@ dependencies = [
[[package]] [[package]]
name = "assert_cmd" name = "assert_cmd"
version = "1.0.5" version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a88b6bd5df287567ffdf4ddf4d33060048e1068308e5f62d81c6f9824a045a48" checksum = "3d20831bd004dda4c7c372c19cdabff369f794a95e955b3f13fe460e3e1ae95f"
dependencies = [ dependencies = [
"bstr", "bstr",
"doc-comment", "doc-comment",
@@ -142,10 +144,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "difference" name = "difflib"
version = "2.0.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]] [[package]]
name = "doc-comment" name = "doc-comment"
@@ -155,13 +157,12 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]] [[package]]
name = "du-dust" name = "du-dust"
version = "0.5.4" version = "0.6.2"
dependencies = [ dependencies = [
"ansi_term 0.12.1", "ansi_term 0.12.1",
"assert_cmd", "assert_cmd",
"clap", "clap",
"lscolors", "lscolors",
"num_cpus",
"rayon", "rayon",
"stfu8", "stfu8",
"tempfile", "tempfile",
@@ -190,13 +191,22 @@ dependencies = [
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.18" version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "itertools"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
dependencies = [
"either",
]
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.4.0"
@@ -205,9 +215,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.97" version = "0.2.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
[[package]] [[package]]
name = "lscolors" name = "lscolors"
@@ -251,11 +261,12 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
[[package]] [[package]]
name = "predicates" name = "predicates"
version = "1.0.8" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49cfaf7fdaa3bfacc6fa3e7054e65148878354a5cfddcf661df4c851f8021df" checksum = "c6e46ca79eb4e21e2ec14430340c71250ab69332abf85521c95d3a8bc336aa76"
dependencies = [ dependencies = [
"difference", "difflib",
"itertools",
"predicates-core", "predicates-core",
] ]
+1 -2
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "du-dust" name = "du-dust"
description = "A more intuitive version of du" description = "A more intuitive version of du"
version = "0.5.4" version = "0.6.2"
authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"] authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"]
edition = "2018" edition = "2018"
@@ -24,7 +24,6 @@ path = "src/main.rs"
ansi_term = "0.12" ansi_term = "0.12"
clap = { version = "=2.33", features = ["wrap_help"] } clap = { version = "=2.33", features = ["wrap_help"] }
lscolors = "0.7" lscolors = "0.7"
num_cpus = "1"
terminal_size = "0.1" terminal_size = "0.1"
unicode-width = "0.1" unicode-width = "0.1"
rayon="1" rayon="1"
+12 -8
View File
@@ -44,14 +44,17 @@ Dust will list a slightly-less-than-the-terminal-height number of the biggest su
Usage: dust Usage: dust
Usage: dust <dir> Usage: dust <dir>
Usage: dust <dir> <another_dir> <and_more> Usage: dust <dir> <another_dir> <and_more>
Usage: dust -p <dir> (full-path - does not shorten the path of the subdirectories) Usage: dust -p (full-path - Show fullpath of the subdirectories)
Usage: dust -s <dir> (apparent-size - shows the length of the file as opposed to the amount of disk space it uses) Usage: dust -s (apparent-size - shows the length of the file as opposed to the amount of disk space it uses)
Usage: dust -n 30 <dir> (shows 30 directories instead of the default) Usage: dust -n 30 (shows 30 directories instead of the default [default is terminal height])
Usage: dust -d 3 <dir> (shows 3 levels of subdirectories) Usage: dust -d 3 (shows 3 levels of subdirectories)
Usage: dust -r <dir> (reverse order of output, with root at the lowest) Usage: dust -r (reverse order of output)
Usage: dust -x <dir> (only show directories on the same filesystem) Usage: dust -X ignore (ignore all files and directories with the name 'ignore')
Usage: dust -X ignore <dir> (ignore all files and directories with the name 'ignore') Usage: dust -x (only show directories on the same filesystem)
Usage: dust -b <dir> (do not show percentages or draw ASCII bars) Usage: dust -b (do not show percentages or draw ASCII bars)
Usage: dust -i (do not show hidden files)
Usage: dust -c (No colors [monochrome])
Usage: dust -f (Count files instead of diskspace)
``` ```
@@ -61,6 +64,7 @@ Usage: dust -b <dir> (do not show percentages or draw ASCII bars)
* [dutree](https://github.com/nachoparker/dutree) * [dutree](https://github.com/nachoparker/dutree)
* [dua](https://github.com/Byron/dua-cli/) * [dua](https://github.com/Byron/dua-cli/)
* [pdu](https://github.com/KSXGitHub/parallel-disk-usage) * [pdu](https://github.com/KSXGitHub/parallel-disk-usage)
* [dirstat-rs](https://github.com/scullionw/dirstat-rs)
* du -d 1 -h | sort -h * du -d 1 -h | sort -h
Note: Apparent-size is calculated slightly differently in dust to gdu. In dust each hard link is counted as using file_length space. In gdu only the first entry is counted. Note: Apparent-size is calculated slightly differently in dust to gdu. In dust each hard link is counted as using file_length space. In gdu only the first entry is counted.
+1 -1
View File
@@ -1,6 +1,6 @@
# ----------- To do a release --------- # ----------- To do a release ---------
# edit version in cargo.toml # edit version in cargo.toml
# tag a commit and push (increment version first): # tag a commit and push (increment version in Cargo.toml first):
# git tag v0.4.5 # git tag v0.4.5
# git push origin v0.4.5 # git push origin v0.4.5
+40 -44
View File
@@ -13,30 +13,27 @@ use std::collections::HashSet;
use crate::node::build_node; use crate::node::build_node;
use std::fs::DirEntry; use std::fs::DirEntry;
pub fn walk_it( use crate::platform::get_metadata;
dirs: HashSet<PathBuf>,
ignore_directories: HashSet<PathBuf>, pub struct WalkData {
use_apparent_size: bool, pub ignore_directories: HashSet<PathBuf>,
by_filecount: bool, pub allowed_filesystems: HashSet<u64>,
ignore_hidden: bool, pub use_apparent_size: bool,
) -> (Vec<Node>, bool) { pub by_filecount: bool,
pub ignore_hidden: bool,
}
pub fn walk_it(dirs: HashSet<PathBuf>, walk_data: WalkData) -> (Vec<Node>, bool) {
let permissions_flag = AtomicBool::new(false); let permissions_flag = AtomicBool::new(false);
let top_level_nodes: Vec<_> = dirs let top_level_nodes: Vec<_> = dirs
.into_iter() .into_iter()
.filter_map(|d| { .filter_map(|d| {
let n = walk( let n = walk(d, &permissions_flag, &walk_data);
d,
&permissions_flag,
&ignore_directories,
use_apparent_size,
by_filecount,
ignore_hidden,
);
match n { match n {
Some(n) => { Some(n) => {
let mut inodes: HashSet<(u64, u64)> = HashSet::new(); let mut inodes: HashSet<(u64, u64)> = HashSet::new();
clean_inodes(n, &mut inodes, use_apparent_size) clean_inodes(n, &mut inodes, walk_data.use_apparent_size)
} }
None => None, None => None,
} }
@@ -74,24 +71,23 @@ fn clean_inodes(
}); });
} }
fn ignore_file( fn ignore_file(entry: &DirEntry, walk_data: &WalkData) -> bool {
entry: &DirEntry,
ignore_hidden: bool,
ignore_directories: &HashSet<PathBuf>,
) -> bool {
let is_dot_file = entry.file_name().to_str().unwrap_or("").starts_with('.'); let is_dot_file = entry.file_name().to_str().unwrap_or("").starts_with('.');
let is_ignored_path = ignore_directories.contains(&entry.path()); let is_ignored_path = walk_data.ignore_directories.contains(&entry.path());
(is_dot_file && ignore_hidden) || is_ignored_path
if !walk_data.allowed_filesystems.is_empty() {
let size_inode_device = get_metadata(&entry.path(), false);
if let Some((_size, Some((_id, dev)))) = size_inode_device {
if !walk_data.allowed_filesystems.contains(&dev) {
return true;
}
}
}
(is_dot_file && walk_data.ignore_hidden) || is_ignored_path
} }
fn walk( fn walk(dir: PathBuf, permissions_flag: &AtomicBool, walk_data: &WalkData) -> Option<Node> {
dir: PathBuf,
permissions_flag: &AtomicBool,
ignore_directories: &HashSet<PathBuf>,
use_apparent_size: bool,
by_filecount: bool,
ignore_hidden: bool,
) -> Option<Node> {
let mut children = vec![]; let mut children = vec![];
if let Ok(entries) = fs::read_dir(dir.clone()) { if let Ok(entries) = fs::read_dir(dir.clone()) {
@@ -104,25 +100,19 @@ fn walk(
// rayon doesn't parallelise as well giving a 3X performance drop // rayon doesn't parallelise as well giving a 3X performance drop
// hence we unravel the recursion a bit // hence we unravel the recursion a bit
// return walk(entry.path(), permissions_flag, ignore_directories, use_apparent_size, by_filecount, ignore_hidden); // return walk(entry.path(), permissions_flag, ignore_directories, allowed_filesystems, use_apparent_size, by_filecount, ignore_hidden);
if !ignore_file(&entry, ignore_hidden, &ignore_directories) { if !ignore_file(entry, walk_data) {
if let Ok(data) = entry.file_type() { if let Ok(data) = entry.file_type() {
if data.is_dir() && !data.is_symlink() { if data.is_dir() && !data.is_symlink() {
return walk( return walk(entry.path(), permissions_flag, walk_data);
entry.path(),
permissions_flag,
ignore_directories,
use_apparent_size,
by_filecount,
ignore_hidden,
);
} }
return build_node( return build_node(
entry.path(), entry.path(),
vec![], vec![],
use_apparent_size, walk_data.use_apparent_size,
by_filecount, data.is_symlink(),
walk_data.by_filecount,
); );
} }
} }
@@ -135,7 +125,13 @@ fn walk(
} else { } else {
permissions_flag.store(true, atomic::Ordering::Relaxed); permissions_flag.store(true, atomic::Ordering::Relaxed);
} }
build_node(dir, children, use_apparent_size, by_filecount) build_node(
dir,
children,
walk_data.use_apparent_size,
false,
walk_data.by_filecount,
)
} }
mod tests { mod tests {
+5 -5
View File
@@ -125,7 +125,7 @@ pub fn draw_it(
let root_node = option_root_node.unwrap(); let root_node = option_root_node.unwrap();
let num_chars_needed_on_left_most = if by_filecount { let num_chars_needed_on_left_most = if by_filecount {
let max_size = root_node.children.iter().map(|n| n.size).fold(0, max); let max_size = root_node.size;
max_size.separate_with_commas().chars().count() max_size.separate_with_commas().chars().count()
} else { } else {
5 // Under normal usage we need 5 chars to display the size of a directory 5 // Under normal usage we need 5 chars to display the size of a directory
@@ -265,9 +265,9 @@ fn pad_or_trim_filename(node: &DisplayNode, indent: &str, display_data: &Display
// Add spaces after the filename so we can draw the % used bar chart. // Add spaces after the filename so we can draw the % used bar chart.
let name_and_padding = name let name_and_padding = name
+ &(repeat(" ") + " "
.take(display_data.longest_string_length - width) .repeat(display_data.longest_string_length - width)
.collect::<String>()); .as_str();
maybe_trim_filename(name_and_padding, display_data) maybe_trim_filename(name_and_padding, display_data)
} }
@@ -320,7 +320,7 @@ fn get_pretty_size(node: &DisplayNode, is_biggest: bool, display_data: &DisplayD
let size_as_str = node.size.separate_with_commas(); let size_as_str = node.size.separate_with_commas();
let spaces_to_add = let spaces_to_add =
display_data.num_chars_needed_on_left_most - size_as_str.chars().count(); display_data.num_chars_needed_on_left_most - size_as_str.chars().count();
size_as_str + &*repeat(' ').take(spaces_to_add).collect::<String>() size_as_str + " ".repeat(spaces_to_add).as_str()
} else { } else {
format!("{:>5}", human_readable_number(node.size)) format!("{:>5}", human_readable_number(node.size))
}; };
+6 -5
View File
@@ -36,11 +36,12 @@ impl DisplayNode {
} }
pub fn get_children_from_node(&self, is_reversed: bool) -> impl Iterator<Item = DisplayNode> { pub fn get_children_from_node(&self, is_reversed: bool) -> impl Iterator<Item = DisplayNode> {
if is_reversed { // we box to avoid the clippy lint warning
let children: Vec<DisplayNode> = self.children.clone().into_iter().rev().collect(); let out: Box<dyn Iterator<Item = DisplayNode>> = if is_reversed {
children.into_iter() Box::new(self.children.clone().into_iter().rev())
} else { } else {
self.children.clone().into_iter() Box::new(self.children.clone().into_iter())
} };
out
} }
} }
+25 -7
View File
@@ -7,14 +7,16 @@ use std::collections::HashSet;
use self::display::draw_it; use self::display::draw_it;
use clap::{App, AppSettings, Arg}; use clap::{App, AppSettings, Arg};
use dirwalker::walk_it; use dir_walker::walk_it;
use dir_walker::WalkData;
use filter::{get_biggest, get_by_depth}; use filter::{get_biggest, get_by_depth};
use std::cmp::max; use std::cmp::max;
use std::path::PathBuf; use std::path::PathBuf;
use terminal_size::{terminal_size, Height, Width}; use terminal_size::{terminal_size, Height, Width};
use utils::get_filesystem_devices;
use utils::simplify_dir_names; use utils::simplify_dir_names;
mod dirwalker; mod dir_walker;
mod display; mod display;
mod display_node; mod display_node;
mod filter; mod filter;
@@ -107,6 +109,12 @@ fn main() {
.multiple(true) .multiple(true)
.help("Exclude any file or directory with this name"), .help("Exclude any file or directory with this name"),
) )
.arg(
Arg::with_name("limit_filesystem")
.short("x")
.long("limit-filesystem")
.help("Only count the files and directories on the same filesystem as the supplied directory"),
)
.arg( .arg(
Arg::with_name("display_apparent_size") Arg::with_name("display_apparent_size")
.short("s") .short("s")
@@ -141,7 +149,7 @@ fn main() {
Arg::with_name("ignore_hidden") Arg::with_name("ignore_hidden")
.short("i") // Do not use 'h' this is used by 'help' .short("i") // Do not use 'h' this is used by 'help'
.long("ignore_hidden") .long("ignore_hidden")
.help("Obey .git_ignore rules & Do not display hidden files"), .help("Do not display hidden files"),
) )
.arg( .arg(
Arg::with_name("width") Arg::with_name("width")
@@ -191,21 +199,31 @@ fn main() {
let by_filecount = options.is_present("by_filecount"); let by_filecount = options.is_present("by_filecount");
let ignore_hidden = options.is_present("ignore_hidden"); let ignore_hidden = options.is_present("ignore_hidden");
let limit_filesystem = options.is_present("limit_filesystem");
let simplified_dirs = simplify_dir_names(target_dirs); let simplified_dirs = simplify_dir_names(target_dirs);
let allowed_filesystems = {
if limit_filesystem {
get_filesystem_devices(simplified_dirs.iter())
} else {
HashSet::new()
}
};
let ignored_full_path: HashSet<PathBuf> = ignore_directories let ignored_full_path: HashSet<PathBuf> = ignore_directories
.into_iter() .into_iter()
.flat_map(|x| simplified_dirs.iter().map(move |d| d.join(x.clone()))) .flat_map(|x| simplified_dirs.iter().map(move |d| d.join(x.clone())))
.collect(); .collect();
let (nodes, errors) = walk_it( let walk_data = WalkData {
simplified_dirs, ignore_directories: ignored_full_path,
ignored_full_path, allowed_filesystems,
use_apparent_size, use_apparent_size,
by_filecount, by_filecount,
ignore_hidden, ignore_hidden,
); };
let (nodes, errors) = walk_it(simplified_dirs, walk_data);
let tree = { let tree = {
match depth { match depth {
+9 -1
View File
@@ -15,11 +15,19 @@ pub fn build_node(
dir: PathBuf, dir: PathBuf,
children: Vec<Node>, children: Vec<Node>,
use_apparent_size: bool, use_apparent_size: bool,
is_symlink: bool,
by_filecount: bool, by_filecount: bool,
) -> Option<Node> { ) -> Option<Node> {
match get_metadata(&dir, use_apparent_size) { match get_metadata(&dir, use_apparent_size) {
Some(data) => { Some(data) => {
let (size, inode_device) = if by_filecount { (1, data.1) } else { data }; let (size, inode_device) = if by_filecount {
(1, data.1)
} else if is_symlink && !use_apparent_size {
(0, None)
} else {
data
};
Some(Node { Some(Node {
name: dir, name: dir,
size, size,
+2 -2
View File
@@ -120,9 +120,9 @@ pub fn get_metadata(d: &Path, _use_apparent_size: bool) -> Option<(u64, Option<(
{ {
Some((md.len(), None)) Some((md.len(), None))
} else { } else {
get_metadata_expensive(&d) get_metadata_expensive(d)
} }
} }
_ => get_metadata_expensive(&d), _ => get_metadata_expensive(d),
} }
} }
+19
View File
@@ -1,6 +1,9 @@
use platform::get_metadata;
use std::collections::HashSet; use std::collections::HashSet;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use crate::platform;
fn is_a_parent_of<P: AsRef<Path>>(parent: P, child: P) -> bool { fn is_a_parent_of<P: AsRef<Path>>(parent: P, child: P) -> bool {
let parent = parent.as_ref(); let parent = parent.as_ref();
let child = child.as_ref(); let child = child.as_ref();
@@ -33,6 +36,22 @@ pub fn simplify_dir_names<P: AsRef<Path>>(filenames: Vec<P>) -> HashSet<PathBuf>
top_level_names top_level_names
} }
pub fn get_filesystem_devices<'a, P: IntoIterator<Item = &'a PathBuf>>(paths: P) -> HashSet<u64> {
// Gets the device ids for the filesystems which are used by the argument paths
paths
.into_iter()
.filter_map(|p| {
let meta = get_metadata(p, false);
if let Some((_size, Some((_id, dev)))) = meta {
Some(dev)
} else {
None
}
})
.collect()
}
pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf { pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
// normalize path ... // normalize path ...
// 1. removing repeated separators // 1. removing repeated separators