mirror of
https://github.com/bootandy/dust.git
synced 2025-12-06 04:41:09 -08:00
Compare commits
20 Commits
v0.6.2
...
v0.7.1.alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c2149b431 | ||
|
|
0301c7a058 | ||
|
|
bbed8d7478 | ||
|
|
17e7390e25 | ||
|
|
1cb731533b | ||
|
|
d6c2482150 | ||
|
|
9d2e6d2b36 | ||
|
|
124c19b5c9 | ||
|
|
d8a334df3b | ||
|
|
c485e84145 | ||
|
|
f51e9dd222 | ||
|
|
c25f7d342c | ||
|
|
ca0a93f222 | ||
|
|
9cf260e42b | ||
|
|
87b1f50b39 | ||
|
|
3458c98bd0 | ||
|
|
2ad420d370 | ||
|
|
2047f99c6d | ||
|
|
9bd2f9fc2a | ||
|
|
5116c1c8a1 |
18
.github/workflows/CICD.yml
vendored
18
.github/workflows/CICD.yml
vendored
@@ -205,6 +205,18 @@ jobs:
|
||||
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
||||
command: build
|
||||
args: --release --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
|
||||
- name: Install cargo-deb
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: install
|
||||
args: cargo-deb
|
||||
if: ${{ contains(matrix.job.target, 'musl') }}
|
||||
- name: Build deb
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: deb
|
||||
args: --no-build --target=${{ matrix.job.target }}
|
||||
if: ${{ contains(matrix.job.target, 'musl') }}
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
@@ -216,6 +228,12 @@ jobs:
|
||||
with:
|
||||
name: ${{ env.PROJECT_NAME }}-${{ matrix.job.target }}
|
||||
path: target/${{ matrix.job.target }}/release/${{ env.PROJECT_NAME }}${{ steps.vars.outputs.EXE_suffix }}
|
||||
- name: Archive deb artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ${{ env.PROJECT_NAME }}-${{ matrix.job.target }}.deb
|
||||
path: target/${{ matrix.job.target }}/debian
|
||||
if: ${{ contains(matrix.job.target, 'musl') }}
|
||||
- name: Package
|
||||
shell: bash
|
||||
run: |
|
||||
|
||||
35
Cargo.lock
generated
35
Cargo.lock
generated
@@ -31,9 +31,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "assert_cmd"
|
||||
version = "1.0.7"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d20831bd004dda4c7c372c19cdabff369f794a95e955b3f13fe460e3e1ae95f"
|
||||
checksum = "c98233c6673d8601ab23e77eb38f999c51100d46c5703b17288c57fddf3a1ffe"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"doc-comment",
|
||||
@@ -62,9 +62,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
@@ -111,9 +111,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
|
||||
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"crossbeam-epoch",
|
||||
@@ -157,13 +157,14 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||
|
||||
[[package]]
|
||||
name = "du-dust"
|
||||
version = "0.6.2"
|
||||
version = "0.7.1"
|
||||
dependencies = [
|
||||
"ansi_term 0.12.1",
|
||||
"assert_cmd",
|
||||
"clap",
|
||||
"lscolors",
|
||||
"rayon",
|
||||
"regex",
|
||||
"stfu8",
|
||||
"tempfile",
|
||||
"terminal_size",
|
||||
@@ -215,9 +216,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.98"
|
||||
version = "0.2.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
|
||||
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
||||
|
||||
[[package]]
|
||||
name = "lscolors"
|
||||
@@ -230,9 +231,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.0"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
@@ -261,9 +262,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "2.0.0"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6e46ca79eb4e21e2ec14430340c71250ab69332abf85521c95d3a8bc336aa76"
|
||||
checksum = "c143348f141cc87aab5b950021bac6145d0e5ae754b0591de23244cee42c9308"
|
||||
dependencies = [
|
||||
"difflib",
|
||||
"itertools",
|
||||
@@ -278,9 +279,9 @@ checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15f553275e5721409451eb85e15fd9a860a6e5ab4496eb215987502b5f5391f2"
|
||||
checksum = "d7dd0fd014130206c9352efbdc92be592751b2b9274dff685348341082c6ea3d"
|
||||
dependencies = [
|
||||
"predicates-core",
|
||||
"treeline",
|
||||
@@ -353,9 +354,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
|
||||
checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
17
Cargo.toml
17
Cargo.toml
@@ -1,9 +1,10 @@
|
||||
[package]
|
||||
name = "du-dust"
|
||||
description = "A more intuitive version of du"
|
||||
version = "0.6.2"
|
||||
version = "0.7.1"
|
||||
authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"]
|
||||
edition = "2018"
|
||||
readme = "README.md"
|
||||
|
||||
documentation = "https://github.com/bootandy/dust"
|
||||
homepage = "https://github.com/bootandy/dust"
|
||||
@@ -29,6 +30,7 @@ unicode-width = "0.1"
|
||||
rayon="1"
|
||||
thousands = "0.2"
|
||||
stfu8 = "0.2"
|
||||
regex = "1"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi-util = "0.1"
|
||||
@@ -40,3 +42,16 @@ tempfile = "=3"
|
||||
[[test]]
|
||||
name = "integration"
|
||||
path = "tests/tests.rs"
|
||||
|
||||
[package.metadata.deb]
|
||||
section = "utils"
|
||||
assets = [
|
||||
["target/release/dust", "usr/bin/", "755"],
|
||||
["LICENSE", "usr/share/doc/du-dust/", "644"],
|
||||
["README.md", "usr/share/doc/du-dust/README", "644"],
|
||||
]
|
||||
extended-description = """\
|
||||
Dust is meant to give you an instant overview of which directories are using
|
||||
disk space without requiring sort or head. Dust will print a maximum of one
|
||||
'Did not have permissions message'.
|
||||
"""
|
||||
|
||||
@@ -38,6 +38,8 @@ Dust is meant to give you an instant overview of which directories are using dis
|
||||
|
||||
Dust will list a slightly-less-than-the-terminal-height number of the biggest subdirectories or files and will smartly recurse down the tree to find the larger ones. There is no need for a '-d' flag or a '-h' flag. The largest subdirectories will be colored.
|
||||
|
||||
The different colors on the bars: These represent the combined tree hierarchy & disk usage. The shades of grey are used to indicate which parent folder a subfolder belongs to. For instance, look at the above screenshot. `.steam` is a folder taking 44% of the space. From the `.steam` bar is a light grey line that goes up. All these folders are inside `.steam` so if you delete `.steam` all that stuff will be gone too.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
@@ -55,6 +57,8 @@ 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)
|
||||
Usage: dust -t Group by filetype
|
||||
Usage: dust -e regex Only include files matching this regex (eg dust -e "\.png$" would match png files)
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use std::fs;
|
||||
|
||||
use crate::node::Node;
|
||||
use crate::utils::is_filtered_out_due_to_invert_regex;
|
||||
use crate::utils::is_filtered_out_due_to_regex;
|
||||
use rayon::iter::ParallelBridge;
|
||||
use rayon::prelude::ParallelIterator;
|
||||
use regex::Regex;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use std::sync::atomic;
|
||||
@@ -17,6 +20,8 @@ use crate::platform::get_metadata;
|
||||
|
||||
pub struct WalkData {
|
||||
pub ignore_directories: HashSet<PathBuf>,
|
||||
pub filter_regex: Option<Regex>,
|
||||
pub invert_filter_regex: Option<Regex>,
|
||||
pub allowed_filesystems: HashSet<u64>,
|
||||
pub use_apparent_size: bool,
|
||||
pub by_filecount: bool,
|
||||
@@ -84,6 +89,22 @@ fn ignore_file(entry: &DirEntry, walk_data: &WalkData) -> bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keeping `walk_data.filter_regex.is_some()` is important for performance reasons, it stops unnecessary work
|
||||
if walk_data.filter_regex.is_some()
|
||||
&& entry.path().is_file()
|
||||
&& is_filtered_out_due_to_regex(&walk_data.filter_regex, &entry.path())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if walk_data.invert_filter_regex.is_some()
|
||||
&& entry.path().is_file()
|
||||
&& is_filtered_out_due_to_invert_regex(&walk_data.invert_filter_regex, &entry.path())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
(is_dot_file && walk_data.ignore_hidden) || is_ignored_path
|
||||
}
|
||||
|
||||
@@ -110,8 +131,11 @@ fn walk(dir: PathBuf, permissions_flag: &AtomicBool, walk_data: &WalkData) -> Op
|
||||
return build_node(
|
||||
entry.path(),
|
||||
vec![],
|
||||
&walk_data.filter_regex,
|
||||
&walk_data.invert_filter_regex,
|
||||
walk_data.use_apparent_size,
|
||||
data.is_symlink(),
|
||||
data.is_file(),
|
||||
walk_data.by_filecount,
|
||||
);
|
||||
}
|
||||
@@ -128,8 +152,11 @@ fn walk(dir: PathBuf, permissions_flag: &AtomicBool, walk_data: &WalkData) -> Op
|
||||
build_node(
|
||||
dir,
|
||||
children,
|
||||
&walk_data.filter_regex,
|
||||
&walk_data.invert_filter_regex,
|
||||
walk_data.use_apparent_size,
|
||||
false,
|
||||
false,
|
||||
walk_data.by_filecount,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -107,7 +107,6 @@ impl DrawData<'_> {
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn draw_it(
|
||||
permission_error: bool,
|
||||
use_full_path: bool,
|
||||
is_reversed: bool,
|
||||
no_colors: bool,
|
||||
@@ -116,9 +115,6 @@ pub fn draw_it(
|
||||
by_filecount: bool,
|
||||
option_root_node: Option<DisplayNode>,
|
||||
) {
|
||||
if permission_error {
|
||||
eprintln!("Did not have permissions for all directories");
|
||||
}
|
||||
if option_root_node.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::display_node::DisplayNode;
|
||||
use crate::node::Node;
|
||||
use std::collections::BinaryHeap;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -13,7 +14,11 @@ pub fn get_by_depth(top_level_nodes: Vec<Node>, n: usize) -> Option<DisplayNode>
|
||||
Some(build_by_depth(&root, n - 1))
|
||||
}
|
||||
|
||||
pub fn get_biggest(top_level_nodes: Vec<Node>, n: usize) -> Option<DisplayNode> {
|
||||
pub fn get_biggest(
|
||||
top_level_nodes: Vec<Node>,
|
||||
n: usize,
|
||||
using_a_filter: bool,
|
||||
) -> Option<DisplayNode> {
|
||||
if top_level_nodes.is_empty() {
|
||||
// perhaps change this, bring back Error object?
|
||||
return None;
|
||||
@@ -22,18 +27,17 @@ pub fn get_biggest(top_level_nodes: Vec<Node>, n: usize) -> Option<DisplayNode>
|
||||
let mut heap = BinaryHeap::new();
|
||||
let number_top_level_nodes = top_level_nodes.len();
|
||||
let root = get_new_root(top_level_nodes);
|
||||
|
||||
root.children.iter().for_each(|c| heap.push(c));
|
||||
|
||||
let mut allowed_nodes = HashSet::new();
|
||||
|
||||
allowed_nodes.insert(&root.name);
|
||||
heap = add_children(using_a_filter, &root, heap);
|
||||
|
||||
for _ in number_top_level_nodes..n {
|
||||
let line = heap.pop();
|
||||
match line {
|
||||
Some(line) => {
|
||||
line.children.iter().for_each(|c| heap.push(c));
|
||||
allowed_nodes.insert(&line.name);
|
||||
heap = add_children(using_a_filter, line, heap);
|
||||
}
|
||||
None => break,
|
||||
}
|
||||
@@ -41,6 +45,72 @@ pub fn get_biggest(top_level_nodes: Vec<Node>, n: usize) -> Option<DisplayNode>
|
||||
recursive_rebuilder(&allowed_nodes, &root)
|
||||
}
|
||||
|
||||
pub fn get_all_file_types(top_level_nodes: Vec<Node>, n: usize) -> Option<DisplayNode> {
|
||||
let mut map: HashMap<String, DisplayNode> = HashMap::new();
|
||||
build_by_all_file_types(top_level_nodes, &mut map);
|
||||
let mut by_types: Vec<DisplayNode> = map.into_iter().map(|(_k, v)| v).collect();
|
||||
by_types.sort();
|
||||
by_types.reverse();
|
||||
|
||||
let displayed = if by_types.len() <= n {
|
||||
by_types
|
||||
} else {
|
||||
let (displayed, rest) = by_types.split_at(if n > 1 { n - 1 } else { 1 });
|
||||
let remaining = DisplayNode {
|
||||
name: PathBuf::from("(others)"),
|
||||
size: rest.iter().map(|a| a.size).sum(),
|
||||
children: vec![],
|
||||
};
|
||||
|
||||
let mut displayed = displayed.to_vec();
|
||||
displayed.push(remaining);
|
||||
displayed
|
||||
};
|
||||
|
||||
let result = DisplayNode {
|
||||
name: PathBuf::from("(total)"),
|
||||
size: displayed.iter().map(|a| a.size).sum(),
|
||||
children: displayed,
|
||||
};
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn add_children<'a>(
|
||||
using_a_filter: bool,
|
||||
line: &'a Node,
|
||||
mut heap: BinaryHeap<&'a Node>,
|
||||
) -> BinaryHeap<&'a Node> {
|
||||
if using_a_filter {
|
||||
line.children.iter().for_each(|c| {
|
||||
if c.name.is_file() || c.size > 0 {
|
||||
heap.push(c)
|
||||
}
|
||||
});
|
||||
} else {
|
||||
line.children.iter().for_each(|c| heap.push(c));
|
||||
}
|
||||
heap
|
||||
}
|
||||
|
||||
fn build_by_all_file_types(top_level_nodes: Vec<Node>, counter: &mut HashMap<String, DisplayNode>) {
|
||||
for node in top_level_nodes {
|
||||
if node.name.is_file() {
|
||||
let ext = node.name.extension();
|
||||
let key: String = match ext {
|
||||
Some(e) => ".".to_string() + &e.to_string_lossy(),
|
||||
None => "(no extension)".into(),
|
||||
};
|
||||
let mut display_node = counter.entry(key.clone()).or_insert(DisplayNode {
|
||||
name: PathBuf::from(key),
|
||||
size: 0,
|
||||
children: vec![],
|
||||
});
|
||||
display_node.size += node.size;
|
||||
}
|
||||
build_by_all_file_types(node.children, counter)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_by_depth(node: &Node, depth: usize) -> DisplayNode {
|
||||
let new_children = {
|
||||
if depth == 0 {
|
||||
|
||||
100
src/main.rs
100
src/main.rs
@@ -1,15 +1,18 @@
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate rayon;
|
||||
extern crate regex;
|
||||
extern crate unicode_width;
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::process;
|
||||
|
||||
use self::display::draw_it;
|
||||
use clap::{App, AppSettings, Arg};
|
||||
use dir_walker::walk_it;
|
||||
use dir_walker::WalkData;
|
||||
use filter::{get_biggest, get_by_depth};
|
||||
use filter::{get_all_file_types, get_biggest, get_by_depth};
|
||||
use regex::Regex;
|
||||
use std::cmp::max;
|
||||
use std::path::PathBuf;
|
||||
use terminal_size::{terminal_size, Height, Width};
|
||||
@@ -61,6 +64,7 @@ fn get_height_of_terminal() -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn get_width_of_terminal() -> usize {
|
||||
// Windows CI runners detect a very low terminal width
|
||||
if let Some((Width(w), Height(_h))) = terminal_size() {
|
||||
@@ -70,6 +74,28 @@ fn get_width_of_terminal() -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn get_width_of_terminal() -> usize {
|
||||
if let Some((Width(w), Height(_h))) = terminal_size() {
|
||||
w as usize
|
||||
} else {
|
||||
DEFAULT_TERMINAL_WIDTH
|
||||
}
|
||||
}
|
||||
|
||||
fn get_regex_value(maybe_value: Option<&str>) -> Option<Regex> {
|
||||
match maybe_value {
|
||||
Some(v) => match Regex::new(v) {
|
||||
Ok(r) => Some(r),
|
||||
Err(e) => {
|
||||
eprintln!("Ignoring bad value for regex {:?}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
},
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let default_height = get_height_of_terminal();
|
||||
let def_num_str = default_height.to_string();
|
||||
@@ -148,9 +174,39 @@ fn main() {
|
||||
.arg(
|
||||
Arg::with_name("ignore_hidden")
|
||||
.short("i") // Do not use 'h' this is used by 'help'
|
||||
.long("ignore_hidden")
|
||||
.long("ignore_hidden") //TODO: fix change - -> _
|
||||
.help("Do not display hidden files"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("invert_filter")
|
||||
.short("v")
|
||||
.long("invert-filter")
|
||||
.takes_value(true)
|
||||
.number_of_values(1)
|
||||
.multiple(true)
|
||||
.conflicts_with("filter")
|
||||
.conflicts_with("types")
|
||||
.conflicts_with("depth")
|
||||
.help("Exclude files matching this regex. To ignore png files type: -v \"\\.png$\" "),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("filter")
|
||||
.short("e")
|
||||
.long("filter")
|
||||
.takes_value(true)
|
||||
.number_of_values(1)
|
||||
.multiple(true)
|
||||
.conflicts_with("types")
|
||||
.conflicts_with("depth")
|
||||
.help("Only include files matching this regex. For png files type: -e \"\\.png$\" "),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("types")
|
||||
.short("t")
|
||||
.long("file_types")
|
||||
.conflicts_with("depth")
|
||||
.help("show only these file types"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("width")
|
||||
.short("w")
|
||||
@@ -159,15 +215,18 @@ fn main() {
|
||||
.number_of_values(1)
|
||||
.help("Specify width of output overriding the auto detection of terminal width"),
|
||||
)
|
||||
.arg(Arg::with_name("inputs").multiple(true))
|
||||
.arg(Arg::with_name("inputs").multiple(true).default_value("."))
|
||||
.get_matches();
|
||||
|
||||
let target_dirs = {
|
||||
match options.values_of("inputs") {
|
||||
None => vec!["."],
|
||||
Some(r) => r.collect(),
|
||||
}
|
||||
};
|
||||
let target_dirs = options
|
||||
.values_of("inputs")
|
||||
.expect("Should be a default value here")
|
||||
.collect();
|
||||
|
||||
let summarize_file_types = options.is_present("types");
|
||||
|
||||
let maybe_filter = get_regex_value(options.value_of("filter"));
|
||||
let maybe_invert_filter = get_regex_value(options.value_of("invert_filter"));
|
||||
|
||||
let number_of_lines = match value_t!(options.value_of("number_of_lines"), usize) {
|
||||
Ok(v) => v,
|
||||
@@ -217,23 +276,36 @@ fn main() {
|
||||
|
||||
let walk_data = WalkData {
|
||||
ignore_directories: ignored_full_path,
|
||||
filter_regex: maybe_filter,
|
||||
invert_filter_regex: maybe_invert_filter,
|
||||
allowed_filesystems,
|
||||
use_apparent_size,
|
||||
by_filecount,
|
||||
ignore_hidden,
|
||||
};
|
||||
|
||||
let (nodes, errors) = walk_it(simplified_dirs, walk_data);
|
||||
let (top_level_nodes, has_errors) = walk_it(simplified_dirs, walk_data);
|
||||
|
||||
let tree = {
|
||||
match depth {
|
||||
None => get_biggest(nodes, number_of_lines),
|
||||
Some(depth) => get_by_depth(nodes, depth),
|
||||
match (depth, summarize_file_types) {
|
||||
(_, true) => get_all_file_types(top_level_nodes, number_of_lines),
|
||||
(Some(depth), _) => get_by_depth(top_level_nodes, depth),
|
||||
(_, _) => get_biggest(
|
||||
top_level_nodes,
|
||||
number_of_lines,
|
||||
options.values_of("filter").is_some()
|
||||
|| options.value_of("invert_filter").is_some(),
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
if options.is_present("filter") {
|
||||
println!("Filtering by: {}", options.value_of("filter").unwrap());
|
||||
}
|
||||
if has_errors {
|
||||
eprintln!("Did not have permissions for all directories");
|
||||
}
|
||||
draw_it(
|
||||
errors,
|
||||
options.is_present("display_full_paths"),
|
||||
!options.is_present("reverse"),
|
||||
no_colors,
|
||||
|
||||
27
src/node.rs
27
src/node.rs
@@ -1,5 +1,8 @@
|
||||
use crate::platform::get_metadata;
|
||||
use crate::utils::is_filtered_out_due_to_invert_regex;
|
||||
use crate::utils::is_filtered_out_due_to_regex;
|
||||
|
||||
use regex::Regex;
|
||||
use std::cmp::Ordering;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -11,21 +14,35 @@ pub struct Node {
|
||||
pub inode_device: Option<(u64, u64)>,
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn build_node(
|
||||
dir: PathBuf,
|
||||
children: Vec<Node>,
|
||||
filter_regex: &Option<Regex>,
|
||||
invert_filter_regex: &Option<Regex>,
|
||||
use_apparent_size: bool,
|
||||
is_symlink: bool,
|
||||
is_file: bool,
|
||||
by_filecount: bool,
|
||||
) -> Option<Node> {
|
||||
match get_metadata(&dir, use_apparent_size) {
|
||||
Some(data) => {
|
||||
let (size, inode_device) = if by_filecount {
|
||||
(1, data.1)
|
||||
} else if is_symlink && !use_apparent_size {
|
||||
(0, None)
|
||||
let inode_device = if is_symlink && !use_apparent_size {
|
||||
None
|
||||
} else {
|
||||
data
|
||||
data.1
|
||||
};
|
||||
|
||||
let size = if is_filtered_out_due_to_regex(filter_regex, &dir)
|
||||
|| is_filtered_out_due_to_invert_regex(invert_filter_regex, &dir)
|
||||
|| (is_symlink && !use_apparent_size)
|
||||
|| by_filecount && !is_file
|
||||
{
|
||||
0
|
||||
} else if by_filecount {
|
||||
1
|
||||
} else {
|
||||
data.0
|
||||
};
|
||||
|
||||
Some(Node {
|
||||
|
||||
27
src/utils.rs
27
src/utils.rs
@@ -3,12 +3,7 @@ use std::collections::HashSet;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::platform;
|
||||
|
||||
fn is_a_parent_of<P: AsRef<Path>>(parent: P, child: P) -> bool {
|
||||
let parent = parent.as_ref();
|
||||
let child = child.as_ref();
|
||||
child.starts_with(parent) && !parent.starts_with(child)
|
||||
}
|
||||
use regex::Regex;
|
||||
|
||||
pub fn simplify_dir_names<P: AsRef<Path>>(filenames: Vec<P>) -> HashSet<PathBuf> {
|
||||
let mut top_level_names: HashSet<PathBuf> = HashSet::with_capacity(filenames.len());
|
||||
@@ -62,6 +57,26 @@ pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
|
||||
path.as_ref().components().collect::<PathBuf>()
|
||||
}
|
||||
|
||||
pub fn is_filtered_out_due_to_regex(filter_regex: &Option<Regex>, dir: &Path) -> bool {
|
||||
match filter_regex {
|
||||
Some(fr) => !fr.is_match(&dir.as_os_str().to_string_lossy()),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_filtered_out_due_to_invert_regex(filter_regex: &Option<Regex>, dir: &Path) -> bool {
|
||||
match filter_regex {
|
||||
Some(fr) => fr.is_match(&dir.as_os_str().to_string_lossy()),
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_a_parent_of<P: AsRef<Path>>(parent: P, child: P) -> bool {
|
||||
let parent = parent.as_ref();
|
||||
let child = child.as_ref();
|
||||
child.starts_with(parent) && !parent.starts_with(child)
|
||||
}
|
||||
|
||||
mod tests {
|
||||
#[allow(unused_imports)]
|
||||
use super::*;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use assert_cmd::Command;
|
||||
use std::ffi::OsStr;
|
||||
use std::str;
|
||||
use std::sync::Once;
|
||||
|
||||
@@ -37,7 +38,7 @@ fn copy_test_data(dir: &str) {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn initialize() {
|
||||
fn initialize() {
|
||||
INIT.call_once(|| {
|
||||
copy_test_data("tests/test_dir");
|
||||
copy_test_data("tests/test_dir2");
|
||||
@@ -45,160 +46,101 @@ pub fn initialize() {
|
||||
});
|
||||
}
|
||||
|
||||
fn exact_output_test<T: AsRef<OsStr>>(valid_outputs: Vec<String>, command_args: Vec<T>) {
|
||||
initialize();
|
||||
|
||||
let mut a = &mut Command::cargo_bin("dust").unwrap();
|
||||
for p in command_args {
|
||||
a = a.arg(p);
|
||||
}
|
||||
let output: String = str::from_utf8(&a.unwrap().stdout).unwrap().into();
|
||||
|
||||
assert!(valid_outputs
|
||||
.iter()
|
||||
.fold(false, |sum, i| sum || output.contains(i)));
|
||||
}
|
||||
|
||||
// "windows" result data can vary by host (size seems to be variable by one byte); fix code vs test and re-enable
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_main_basic() {
|
||||
// -c is no color mode - This makes testing much simpler
|
||||
initialize();
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let assert = cmd.arg("-c").arg("/tmp/test_dir/").unwrap().stdout;
|
||||
let output = str::from_utf8(&assert).unwrap();
|
||||
assert!(output.contains(&main_output()));
|
||||
exact_output_test(main_output(), vec!["-c", "/tmp/test_dir/"])
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_main_multi_arg() {
|
||||
initialize();
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let assert = cmd
|
||||
.arg("-c")
|
||||
.arg("/tmp/test_dir/many/")
|
||||
.arg("/tmp/test_dir")
|
||||
.arg("/tmp/test_dir")
|
||||
.unwrap()
|
||||
.stdout;
|
||||
let output = str::from_utf8(&assert).unwrap();
|
||||
assert!(output.contains(&main_output()));
|
||||
let command_args = vec![
|
||||
"-c",
|
||||
"/tmp/test_dir/many/",
|
||||
"/tmp/test_dir",
|
||||
"/tmp/test_dir",
|
||||
];
|
||||
exact_output_test(main_output(), command_args);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn main_output() -> String {
|
||||
r#"
|
||||
fn main_output() -> Vec<String> {
|
||||
// Some linux currently thought to be Manjaro, Arch
|
||||
// Although probably depends on how drive is formatted
|
||||
let mac_and_some_linux = r#"
|
||||
0B ┌── a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
4.0K ├── hello_file│████████████████████████████████████████████████ │ 100%
|
||||
4.0K ┌─┴ many │████████████████████████████████████████████████ │ 100%
|
||||
4.0K ┌─┴ test_dir │████████████████████████████████████████████████ │ 100%
|
||||
"#
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
.to_string();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main_output() -> String {
|
||||
r#"
|
||||
let ubuntu = r#"
|
||||
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
4.0K ├── hello_file│ ░░░░░░░░░░░░░░░░█████████████████ │ 33%
|
||||
8.0K ┌─┴ many │ █████████████████████████████████ │ 67%
|
||||
12K ┌─┴ test_dir │████████████████████████████████████████████████ │ 100%
|
||||
"#
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
.to_string();
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn main_output() -> String {
|
||||
"windows results vary by host".to_string()
|
||||
vec![mac_and_some_linux, ubuntu]
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_main_long_paths() {
|
||||
initialize();
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let assert = cmd
|
||||
.arg("-c")
|
||||
.arg("-p")
|
||||
.arg("/tmp/test_dir/")
|
||||
.unwrap()
|
||||
.stdout;
|
||||
let output = str::from_utf8(&assert).unwrap();
|
||||
assert!(output.contains(&main_output_long_paths()));
|
||||
let command_args = vec!["-c", "-p", "/tmp/test_dir/"];
|
||||
exact_output_test(main_output_long_paths(), command_args);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn main_output_long_paths() -> String {
|
||||
r#"
|
||||
fn main_output_long_paths() -> Vec<String> {
|
||||
let mac_and_some_linux = r#"
|
||||
0B ┌── /tmp/test_dir/many/a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
4.0K ├── /tmp/test_dir/many/hello_file│█████████████████████████████ │ 100%
|
||||
4.0K ┌─┴ /tmp/test_dir/many │█████████████████████████████ │ 100%
|
||||
4.0K ┌─┴ /tmp/test_dir │█████████████████████████████ │ 100%
|
||||
"#
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main_output_long_paths() -> String {
|
||||
r#"
|
||||
.to_string();
|
||||
let ubuntu = r#"
|
||||
0B ┌── /tmp/test_dir/many/a_file │ ░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
4.0K ├── /tmp/test_dir/many/hello_file│ ░░░░░░░░░░██████████ │ 33%
|
||||
8.0K ┌─┴ /tmp/test_dir/many │ ████████████████████ │ 67%
|
||||
12K ┌─┴ /tmp/test_dir │█████████████████████████████ │ 100%
|
||||
"#
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn main_output_long_paths() -> String {
|
||||
"windows results vary by host".to_string()
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_apparent_size() {
|
||||
initialize();
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let assert = cmd.arg("-c").arg("-s").arg("/tmp/test_dir").unwrap().stdout;
|
||||
let output = str::from_utf8(&assert).unwrap();
|
||||
assert!(output.contains(&output_apparent_size()));
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn output_apparent_size() -> String {
|
||||
r#"
|
||||
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
6B ├── hello_file│ ░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
4.0K ┌─┴ many │ █████████████████████████ │ 50%
|
||||
8.0K ┌─┴ test_dir │████████████████████████████████████████████████ │ 100%
|
||||
"#
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn output_apparent_size() -> String {
|
||||
r#"
|
||||
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
6B ├── hello_file│ ░░░░░░░░░░░░░░░░░░░░░░░░░░██ │ 3%
|
||||
134B ┌─┴ many │ ████████████████████████████ │ 58%
|
||||
230B ┌─┴ test_dir │████████████████████████████████████████████████ │ 100%
|
||||
"#
|
||||
.trim()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn output_apparent_size() -> String {
|
||||
"windows results vary by host".to_string()
|
||||
.to_string();
|
||||
vec![mac_and_some_linux, ubuntu]
|
||||
}
|
||||
|
||||
// Check against directories and files whos names are substrings of each other
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_substring_of_names_and_long_names() {
|
||||
initialize();
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd.arg("-c").arg("/tmp/test_dir2").unwrap().stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
assert!(output.contains(&no_substring_of_names_output()));
|
||||
let command_args = vec!["-c", "/tmp/test_dir2"];
|
||||
exact_output_test(no_substring_of_names_output(), command_args);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn no_substring_of_names_output() -> String {
|
||||
"
|
||||
fn no_substring_of_names_output() -> Vec<String> {
|
||||
let ubuntu = "
|
||||
0B ┌── long_dir_name_what_a_very_long_dir_name_what_happens_when_this_g..
|
||||
4.0K ├── dir_name_clash
|
||||
4.0K │ ┌── hello
|
||||
@@ -208,12 +150,9 @@ fn no_substring_of_names_output() -> String {
|
||||
24K ┌─┴ test_dir2
|
||||
"
|
||||
.trim()
|
||||
.into()
|
||||
}
|
||||
.into();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn no_substring_of_names_output() -> String {
|
||||
"
|
||||
let mac_and_some_linux = "
|
||||
0B ┌── long_dir_name_what_a_very_long_dir_name_what_happens_when_this_g..
|
||||
4.0K │ ┌── hello
|
||||
4.0K ├─┴ dir
|
||||
@@ -223,48 +162,33 @@ fn no_substring_of_names_output() -> String {
|
||||
12K ┌─┴ test_dir2
|
||||
"
|
||||
.trim()
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn no_substring_of_names_output() -> String {
|
||||
"PRs".into()
|
||||
.into();
|
||||
vec![mac_and_some_linux, ubuntu]
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_unicode_directories() {
|
||||
initialize();
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd.arg("-c").arg("/tmp/test_dir_unicode").unwrap().stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
assert!(output.contains(&unicode_dir()));
|
||||
let command_args = vec!["-c", "/tmp/test_dir_unicode"];
|
||||
exact_output_test(unicode_dir(), command_args);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn unicode_dir() -> String {
|
||||
fn unicode_dir() -> Vec<String> {
|
||||
// The way unicode & asian characters are rendered on the terminal should make this line up
|
||||
"
|
||||
let ubuntu = "
|
||||
0B ┌── ラウトは難しいです!.japan│ █ │ 0%
|
||||
0B ├── 👩.unicode │ █ │ 0%
|
||||
4.0K ┌─┴ test_dir_unicode │██████████████████████████████████ │ 100%
|
||||
"
|
||||
.trim()
|
||||
.into()
|
||||
}
|
||||
.into();
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn unicode_dir() -> String {
|
||||
"
|
||||
let mac_and_some_linux = "
|
||||
0B ┌── ラウトは難しいです!.japan│ █ │ 0%
|
||||
0B ├── 👩.unicode │ █ │ 0%
|
||||
0B ┌─┴ test_dir_unicode │ █ │ 0%
|
||||
"
|
||||
.trim()
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn unicode_dir() -> String {
|
||||
"".into()
|
||||
.into();
|
||||
vec![mac_and_some_linux, ubuntu]
|
||||
}
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
use assert_cmd::Command;
|
||||
use std::ffi::OsStr;
|
||||
use std::str;
|
||||
|
||||
/**
|
||||
* This file contains tests that test a substring of the output using '.contains'
|
||||
*
|
||||
* These tests should be the same cross platform
|
||||
*/
|
||||
|
||||
fn build_command<T: AsRef<OsStr>>(command_args: Vec<T>) -> String {
|
||||
let mut a = &mut Command::cargo_bin("dust").unwrap();
|
||||
for p in command_args {
|
||||
a = a.arg(p);
|
||||
}
|
||||
str::from_utf8(&a.unwrap().stdout).unwrap().into()
|
||||
}
|
||||
|
||||
// We can at least test the file names are there
|
||||
#[test]
|
||||
pub fn test_basic_output() {
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd.arg("tests/test_dir/").unwrap().stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
let output = build_command(vec!["tests/test_dir/"]);
|
||||
|
||||
assert!(output.contains(" ┌─┴ "));
|
||||
assert!(output.contains("test_dir "));
|
||||
@@ -25,9 +33,7 @@ pub fn test_basic_output() {
|
||||
|
||||
#[test]
|
||||
pub fn test_output_no_bars_means_no_excess_spaces() {
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd.arg("-b").arg("tests/test_dir/").unwrap().stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
let output = build_command(vec!["-b", "tests/test_dir/"]);
|
||||
// If bars are not being shown we don't need to pad the output with spaces
|
||||
assert!(output.contains("many"));
|
||||
assert!(!output.contains("many "));
|
||||
@@ -35,15 +41,7 @@ pub fn test_output_no_bars_means_no_excess_spaces() {
|
||||
|
||||
#[test]
|
||||
pub fn test_reverse_flag() {
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd
|
||||
.arg("-c")
|
||||
.arg("-r")
|
||||
.arg("tests/test_dir/")
|
||||
.unwrap()
|
||||
.stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
|
||||
let output = build_command(vec!["-r", "-c", "tests/test_dir/"]);
|
||||
assert!(output.contains(" └─┬ test_dir "));
|
||||
assert!(output.contains(" └─┬ many "));
|
||||
assert!(output.contains(" ├── hello_file"));
|
||||
@@ -53,15 +51,7 @@ pub fn test_reverse_flag() {
|
||||
#[test]
|
||||
pub fn test_d_flag_works() {
|
||||
// We should see the top level directory but not the sub dirs / files:
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd
|
||||
.arg("-d")
|
||||
.arg("1")
|
||||
.arg("-s")
|
||||
.arg("tests/test_dir/")
|
||||
.unwrap()
|
||||
.stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
let output = build_command(vec!["-d", "1", "tests/test_dir/"]);
|
||||
assert!(!output.contains("hello_file"));
|
||||
}
|
||||
|
||||
@@ -69,31 +59,14 @@ pub fn test_d_flag_works() {
|
||||
pub fn test_d_flag_works_and_still_recurses_down() {
|
||||
// We had a bug where running with '-d 1' would stop at the first directory and the code
|
||||
// would fail to recurse down
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd
|
||||
.arg("-d")
|
||||
.arg("1")
|
||||
.arg("-f")
|
||||
.arg("-c")
|
||||
.arg("tests/test_dir2/")
|
||||
.unwrap()
|
||||
.stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
assert!(output.contains("7 ┌─┴ test_dir2"));
|
||||
let output = build_command(vec!["-d", "1", "-f", "-c", "tests/test_dir2/"]);
|
||||
assert!(output.contains("4 ┌─┴ test_dir2"));
|
||||
}
|
||||
|
||||
// Check against directories and files whos names are substrings of each other
|
||||
#[test]
|
||||
pub fn test_ignore_dir() {
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd
|
||||
.arg("-c")
|
||||
.arg("-X")
|
||||
.arg("dir_substring")
|
||||
.arg("tests/test_dir2")
|
||||
.unwrap()
|
||||
.stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
let output = build_command(vec!["-c", "-X", "dir_substring", "tests/test_dir2/"]);
|
||||
assert!(!output.contains("dir_substring"));
|
||||
}
|
||||
|
||||
@@ -108,25 +81,12 @@ pub fn test_with_bad_param() {
|
||||
#[test]
|
||||
pub fn test_hidden_flag() {
|
||||
// Check we can see the hidden file normally
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd
|
||||
.arg("-c")
|
||||
.arg("tests/test_dir_hidden_entries")
|
||||
.unwrap()
|
||||
.stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
let output = build_command(vec!["-c", "tests/test_dir_hidden_entries/"]);
|
||||
assert!(output.contains(".hidden_file"));
|
||||
assert!(output.contains("┌─┴ test_dir_hidden_entries"));
|
||||
|
||||
// Check that adding the '-h' flag causes us to not see hidden files
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd
|
||||
.arg("-c")
|
||||
.arg("-i")
|
||||
.arg("tests/test_dir_hidden_entries")
|
||||
.unwrap()
|
||||
.stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
let output = build_command(vec!["-c", "-i", "tests/test_dir_hidden_entries/"]);
|
||||
assert!(!output.contains(".hidden_file"));
|
||||
assert!(output.contains("┌── test_dir_hidden_entries"));
|
||||
}
|
||||
@@ -134,16 +94,64 @@ pub fn test_hidden_flag() {
|
||||
#[test]
|
||||
pub fn test_number_of_files() {
|
||||
// Check we can see the hidden file normally
|
||||
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||
let output = cmd
|
||||
.arg("-c")
|
||||
.arg("-f")
|
||||
.arg("tests/test_dir")
|
||||
.unwrap()
|
||||
.stdout;
|
||||
let output = str::from_utf8(&output).unwrap();
|
||||
let output = build_command(vec!["-c", "-f", "tests/test_dir"]);
|
||||
assert!(output.contains("1 ┌── a_file "));
|
||||
assert!(output.contains("1 ├── hello_file"));
|
||||
assert!(output.contains("3 ┌─┴ many"));
|
||||
assert!(output.contains("4 ┌─┴ test_dir"));
|
||||
assert!(output.contains("2 ┌─┴ many"));
|
||||
assert!(output.contains("2 ┌─┴ test_dir"));
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_apparent_size() {
|
||||
// Check the '-s' Flag gives us byte sizes and that it doesn't round up to a block
|
||||
let command_args = vec!["-c", "-s", "/tmp/test_dir"];
|
||||
let output = build_command(command_args);
|
||||
|
||||
let apparent_size1 = "6B ├── hello_file│";
|
||||
let apparent_size2 = "0B ┌── a_file";
|
||||
assert!(output.contains(apparent_size1));
|
||||
assert!(output.contains(apparent_size2));
|
||||
|
||||
let incorrect_apparent_size = "4.0K ├── hello_file";
|
||||
assert!(!output.contains(incorrect_apparent_size));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_show_files_by_type() {
|
||||
// Check we can list files by type
|
||||
let output = build_command(vec!["-c", "-t", "tests"]);
|
||||
assert!(output.contains(" .unicode"));
|
||||
assert!(output.contains(" .japan"));
|
||||
assert!(output.contains(" .rs"));
|
||||
assert!(output.contains(" (no extension)"));
|
||||
assert!(output.contains("┌─┴ (total)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_show_files_by_regex() {
|
||||
// Check we can see '.rs' files in the tests directory
|
||||
let output = build_command(vec!["-c", "-e", "\\.rs$", "tests"]);
|
||||
assert!(output.contains(" ┌─┴ tests"));
|
||||
assert!(!output.contains("0B ┌── tests"));
|
||||
assert!(!output.contains("0B ┌─┴ tests"));
|
||||
|
||||
// Check there are no files named: '.match_nothing' in the tests directory
|
||||
let output = build_command(vec!["-c", "-e", "match_nothing$", "tests"]);
|
||||
assert!(output.contains("0B ┌── tests"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_show_files_by_invert_regex() {
|
||||
let output = build_command(vec!["-c", "-f", "-v", "e", "tests/test_dir2"]);
|
||||
// There are 0 files without 'e' in the name
|
||||
assert!(output.contains("0 ┌── test_dir2"));
|
||||
|
||||
let output = build_command(vec!["-c", "-f", "-v", "a", "tests/test_dir2"]);
|
||||
// There are 2 files without 'a' in the name
|
||||
assert!(output.contains("2 ┌─┴ test_dir2"));
|
||||
|
||||
// There are 4 files in the test_dir2 hierarchy
|
||||
let output = build_command(vec!["-c", "-f", "-v", "match_nothing$", "tests/test_dir2"]);
|
||||
assert!(output.contains("4 ┌─┴ test_dir2"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user