Compare commits

..

10 Commits

Author SHA1 Message Date
andy.boot 17fe56bfd2 Refactor use of depth 2022-07-13 10:37:42 +01:00
andy.boot fc70f9ba30 Rename variable 2022-07-13 09:38:21 +01:00
andy.boot a00d1f0719 Fix: Allow -n to be used with -d
Allow -n for number_of_lines to be used with -d 'max depth'

Remove depth specific functions, the job is now handled by the mainline

Add depth as a field onto the Node object.
2022-07-13 09:38:21 +01:00
andy.boot c4ea7815f8 Refactor: tweak utils function
Refactor simplify_dir_names to make it more readable
2022-07-01 12:04:31 +01:00
dependabot[bot] afc36a633f Bump regex from 1.5.4 to 1.5.5
Bumps [regex](https://github.com/rust-lang/regex) from 1.5.4 to 1.5.5.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.5.4...1.5.5)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-07 09:00:43 +01:00
unknown 7275b273d4 Fix archive/directory check in platform.rs 2022-05-02 12:11:22 +01:00
andy.boot a3e59f9c25 Update README.md 2022-03-05 22:02:09 +00:00
Adam Stephens 48bf656123 add aarch64 gnu and musl cross targets 2022-02-27 10:09:38 +00:00
andy.boot fabb27908d Increment version 2022-02-26 11:47:06 +00:00
andy.boot 52aeeebe1f Improve help text 2022-02-26 11:47:06 +00:00
11 changed files with 90 additions and 94 deletions
+10 -7
View File
@@ -81,6 +81,8 @@ jobs:
matrix: matrix:
job: job:
# { os, target, cargo-options, features, use-cross, toolchain } # { os, target, cargo-options, features, use-cross, toolchain }
- { os: ubuntu-latest , target: aarch64-unknown-linux-gnu , use-cross: use-cross }
- { os: ubuntu-latest , target: aarch64-unknown-linux-musl , use-cross: use-cross }
- { 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-20.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-20.04 , target: i686-unknown-linux-musl , use-cross: use-cross } - { os: ubuntu-20.04 , target: i686-unknown-linux-musl , use-cross: use-cross }
@@ -99,6 +101,7 @@ jobs:
run: | run: |
case ${{ matrix.job.target }} in case ${{ matrix.job.target }} in
arm-unknown-linux-gnueabihf) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;; arm-unknown-linux-gnueabihf) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install binutils-aarch64-linux-gnu ;;
esac esac
- name: Initialize workflow variables - name: Initialize workflow variables
id: vars id: vars
@@ -134,7 +137,7 @@ jobs:
echo ::set-output name=REF_TAG::${REF_TAG} echo ::set-output name=REF_TAG::${REF_TAG}
echo ::set-output name=REF_SHAS::${REF_SHAS} echo ::set-output name=REF_SHAS::${REF_SHAS}
# parse target # parse target
unset TARGET_ARCH ; case ${{ matrix.job.target }} in arm-unknown-linux-gnueabihf) TARGET_ARCH=arm ;; i686-*) TARGET_ARCH=i686 ;; x86_64-*) TARGET_ARCH=x86_64 ;; esac; unset TARGET_ARCH ; case ${{ matrix.job.target }} in arm-unknown-linux-gnueabihf) TARGET_ARCH=arm ;; aarch-*) TARGET_ARCH=aarch64 ;; i686-*) TARGET_ARCH=i686 ;; x86_64-*) TARGET_ARCH=x86_64 ;; esac;
echo set-output name=TARGET_ARCH::${TARGET_ARCH} echo set-output name=TARGET_ARCH::${TARGET_ARCH}
echo ::set-output name=TARGET_ARCH::${TARGET_ARCH} echo ::set-output name=TARGET_ARCH::${TARGET_ARCH}
unset TARGET_OS ; case ${{ matrix.job.target }} in *-linux-*) TARGET_OS=linux ;; *-apple-*) TARGET_OS=macos ;; *-windows-*) TARGET_OS=windows ;; esac; unset TARGET_OS ; case ${{ matrix.job.target }} in *-linux-*) TARGET_OS=linux ;; *-apple-*) TARGET_OS=macos ;; *-windows-*) TARGET_OS=windows ;; esac;
@@ -166,16 +169,16 @@ jobs:
echo ::set-output name=CARGO_USE_CROSS::${CARGO_USE_CROSS} echo ::set-output name=CARGO_USE_CROSS::${CARGO_USE_CROSS}
# # * `arm` cannot be tested on ubuntu-* hosts (b/c testing is currently primarily done via comparison of target outputs with built-in outputs and the `arm` target is not executable on the host) # # * `arm` cannot be tested on ubuntu-* hosts (b/c testing is currently primarily done via comparison of target outputs with built-in outputs and the `arm` target is not executable on the host)
JOB_DO_TESTING="true" JOB_DO_TESTING="true"
case ${{ matrix.job.target }} in arm-*) unset JOB_DO_TESTING ;; esac; case ${{ matrix.job.target }} in arm-*|aarch64-*) unset JOB_DO_TESTING ;; esac;
echo set-output name=JOB_DO_TESTING::${JOB_DO_TESTING:-<empty>/false} echo set-output name=JOB_DO_TESTING::${JOB_DO_TESTING:-<empty>/false}
echo ::set-output name=JOB_DO_TESTING::${JOB_DO_TESTING} echo ::set-output name=JOB_DO_TESTING::${JOB_DO_TESTING}
# # * test only binary for arm-type targets # # * test only binary for arm-type targets
unset CARGO_TEST_OPTIONS unset CARGO_TEST_OPTIONS
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-*) CARGO_TEST_OPTIONS="--bin ${PROJECT_NAME}" ;; esac; unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-*|aarch64-*) CARGO_TEST_OPTIONS="--bin ${PROJECT_NAME}" ;; esac;
echo set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS} echo set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS} echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
# * strip executable? # * strip executable?
STRIP="strip" ; case ${{ matrix.job.target }} in arm-unknown-linux-gnueabihf) STRIP="arm-linux-gnueabihf-strip" ;; *-pc-windows-msvc) STRIP="" ;; esac; STRIP="strip" ; case ${{ matrix.job.target }} in arm-unknown-linux-gnueabihf) STRIP="arm-linux-gnueabihf-strip" ;; *-pc-windows-msvc) STRIP="" ;; aarch64-unknown-linux-gnu) STRIP="aarch64-linux-gnu-strip" ;; aarch64-unknown-linux-musl) STRIP="" ;;esac;
echo set-output name=STRIP::${STRIP} echo set-output name=STRIP::${STRIP}
echo ::set-output name=STRIP::${STRIP} echo ::set-output name=STRIP::${STRIP}
- name: Create all needed build/work directories - name: Create all needed build/work directories
@@ -210,13 +213,13 @@ jobs:
with: with:
command: install command: install
args: cargo-deb args: cargo-deb
if: ${{ contains(matrix.job.target, 'musl') }} if: matrix.job.target == 'i686-unknown-linux-musl' || matrix.job.target == 'x86_64-unknown-linux-musl'
- name: Build deb - name: Build deb
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
command: deb command: deb
args: --no-build --target=${{ matrix.job.target }} args: --no-build --target=${{ matrix.job.target }}
if: ${{ contains(matrix.job.target, 'musl') }} if: matrix.job.target == 'i686-unknown-linux-musl' || matrix.job.target == 'x86_64-unknown-linux-musl'
- name: Test - name: Test
uses: actions-rs/cargo@v1 uses: actions-rs/cargo@v1
with: with:
@@ -233,7 +236,7 @@ jobs:
with: with:
name: ${{ env.PROJECT_NAME }}-${{ matrix.job.target }}.deb name: ${{ env.PROJECT_NAME }}-${{ matrix.job.target }}.deb
path: target/${{ matrix.job.target }}/debian path: target/${{ matrix.job.target }}/debian
if: ${{ contains(matrix.job.target, 'musl') }} if: matrix.job.target == 'i686-unknown-linux-musl' || matrix.job.target == 'x86_64-unknown-linux-musl'
- name: Package - name: Package
shell: bash shell: bash
run: | run: |
Generated
+2 -2
View File
@@ -340,9 +340,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.5.4" version = "1.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
+1 -1
View File
@@ -32,7 +32,7 @@ Because I want an easy way to see where my disk is being used.
#### Windows: #### Windows:
* Windows GNU version - works * Windows GNU version - works
* Windows MSVC - requires: VCRUNTIME140.dll * Windows MSVC - requires: [VCRUNTIME140.dll](https://docs.microsoft.com/en-gb/cpp/windows/latest-supported-vc-redist?view=msvc-170)
#### Download #### Download
+12 -3
View File
@@ -34,7 +34,7 @@ pub fn walk_it(dirs: HashSet<PathBuf>, walk_data: WalkData) -> (Vec<Node>, bool)
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(d, &permissions_flag, &walk_data); let n = walk(d, &permissions_flag, &walk_data, 0);
match n { match n {
Some(n) => { Some(n) => {
let mut inodes: HashSet<(u64, u64)> = HashSet::new(); let mut inodes: HashSet<(u64, u64)> = HashSet::new();
@@ -73,6 +73,7 @@ fn clean_inodes(
size: x.size + new_children.iter().map(|c| c.size).sum::<u64>(), size: x.size + new_children.iter().map(|c| c.size).sum::<u64>(),
children: new_children, children: new_children,
inode_device: x.inode_device, inode_device: x.inode_device,
depth: x.depth,
}); });
} }
@@ -108,7 +109,12 @@ fn ignore_file(entry: &DirEntry, walk_data: &WalkData) -> bool {
(is_dot_file && walk_data.ignore_hidden) || is_ignored_path (is_dot_file && walk_data.ignore_hidden) || is_ignored_path
} }
fn walk(dir: PathBuf, permissions_flag: &AtomicBool, walk_data: &WalkData) -> Option<Node> { fn walk(
dir: PathBuf,
permissions_flag: &AtomicBool,
walk_data: &WalkData,
depth: usize,
) -> 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()) {
@@ -126,7 +132,7 @@ fn walk(dir: PathBuf, permissions_flag: &AtomicBool, walk_data: &WalkData) -> Op
if !ignore_file(entry, walk_data) { 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(entry.path(), permissions_flag, walk_data); return walk(entry.path(), permissions_flag, walk_data, depth + 1);
} }
return build_node( return build_node(
entry.path(), entry.path(),
@@ -137,6 +143,7 @@ fn walk(dir: PathBuf, permissions_flag: &AtomicBool, walk_data: &WalkData) -> Op
data.is_symlink(), data.is_symlink(),
data.is_file(), data.is_file(),
walk_data.by_filecount, walk_data.by_filecount,
depth + 1,
); );
} }
} }
@@ -158,6 +165,7 @@ fn walk(dir: PathBuf, permissions_flag: &AtomicBool, walk_data: &WalkData) -> Op
false, false,
false, false,
walk_data.by_filecount, walk_data.by_filecount,
depth,
) )
} }
@@ -172,6 +180,7 @@ mod tests {
size: 10, size: 10,
children: vec![], children: vec![],
inode_device: Some((5, 6)), inode_device: Some((5, 6)),
depth: 0,
} }
} }
+5 -5
View File
@@ -84,13 +84,13 @@ impl DrawData<'_> {
} }
// TODO: can we test this? // TODO: can we test this?
fn generate_bar(&self, node: &DisplayNode, level: usize) -> String { fn generate_bar(&self, node: &DisplayNode) -> String {
let chars_in_bar = self.percent_bar.chars().count(); let chars_in_bar = self.percent_bar.chars().count();
let num_bars = chars_in_bar as f32 * self.display_data.percent_size(node); let num_bars = chars_in_bar as f32 * self.display_data.percent_size(node);
let mut num_not_my_bar = (chars_in_bar as i32) - num_bars as i32; let mut num_not_my_bar = (chars_in_bar as i32) - num_bars as i32;
let mut new_bar = "".to_string(); let mut new_bar = "".to_string();
let idx = 5 - min(4, max(1, level)); let idx = 5 - min(4, max(1, node.depth));
for c in self.percent_bar.chars() { for c in self.percent_bar.chars() {
num_not_my_bar -= 1; num_not_my_bar -= 1;
@@ -181,10 +181,8 @@ fn find_longest_dir_name(
} }
fn display_node(node: DisplayNode, draw_data: &DrawData, is_biggest: bool, is_last: bool) { fn display_node(node: DisplayNode, draw_data: &DrawData, is_biggest: bool, is_last: bool) {
// hacky way of working out how deep we are in the tree
let indent = draw_data.get_new_indent(!node.children.is_empty(), is_last); let indent = draw_data.get_new_indent(!node.children.is_empty(), is_last);
let level = ((indent.chars().count() - 1) / 2) - 1; let bar_text = draw_data.generate_bar(&node);
let bar_text = draw_data.generate_bar(&node, level);
let to_print = format_string( let to_print = format_string(
&node, &node,
@@ -398,6 +396,7 @@ mod tests {
let n = DisplayNode { let n = DisplayNode {
name: PathBuf::from("/short"), name: PathBuf::from("/short"),
size: 2_u64.pow(12), // This is 4.0K size: 2_u64.pow(12), // This is 4.0K
depth: 1,
children: vec![], children: vec![],
}; };
let indent = "┌─┴"; let indent = "┌─┴";
@@ -420,6 +419,7 @@ mod tests {
let n = DisplayNode { let n = DisplayNode {
name: PathBuf::from(name), name: PathBuf::from(name),
size: 2_u64.pow(12), // This is 4.0K size: 2_u64.pow(12), // This is 4.0K
depth: 1,
children: vec![], children: vec![],
}; };
let indent = "┌─┴"; let indent = "┌─┴";
+1
View File
@@ -5,6 +5,7 @@ use std::path::PathBuf;
pub struct DisplayNode { pub struct DisplayNode {
pub name: PathBuf, //todo: consider moving to a string? pub name: PathBuf, //todo: consider moving to a string?
pub size: u64, pub size: u64,
pub depth: usize,
pub children: Vec<DisplayNode>, pub children: Vec<DisplayNode>,
} }
+20 -43
View File
@@ -5,18 +5,10 @@ use std::collections::HashMap;
use std::collections::HashSet; use std::collections::HashSet;
use std::path::PathBuf; use std::path::PathBuf;
pub fn get_by_depth(top_level_nodes: Vec<Node>, n: usize) -> Option<DisplayNode> {
if top_level_nodes.is_empty() {
// perhaps change this, bring back Error object?
return None;
}
let root = get_new_root(top_level_nodes);
Some(build_by_depth(&root, n - 1))
}
pub fn get_biggest( pub fn get_biggest(
top_level_nodes: Vec<Node>, top_level_nodes: Vec<Node>,
n: usize, n: usize,
depth: usize,
using_a_filter: bool, using_a_filter: bool,
) -> Option<DisplayNode> { ) -> Option<DisplayNode> {
if top_level_nodes.is_empty() { if top_level_nodes.is_empty() {
@@ -30,14 +22,14 @@ pub fn get_biggest(
let mut allowed_nodes = HashSet::new(); let mut allowed_nodes = HashSet::new();
allowed_nodes.insert(&root.name); allowed_nodes.insert(&root.name);
heap = add_children(using_a_filter, &root, heap); heap = add_children(using_a_filter, &root, depth, heap);
for _ in number_top_level_nodes..n { for _ in number_top_level_nodes..n {
let line = heap.pop(); let line = heap.pop();
match line { match line {
Some(line) => { Some(line) => {
allowed_nodes.insert(&line.name); allowed_nodes.insert(&line.name);
heap = add_children(using_a_filter, line, heap); heap = add_children(using_a_filter, line, depth, heap);
} }
None => break, None => break,
} }
@@ -59,6 +51,7 @@ pub fn get_all_file_types(top_level_nodes: Vec<Node>, n: usize) -> Option<Displa
let remaining = DisplayNode { let remaining = DisplayNode {
name: PathBuf::from("(others)"), name: PathBuf::from("(others)"),
size: rest.iter().map(|a| a.size).sum(), size: rest.iter().map(|a| a.size).sum(),
depth: 1,
children: vec![], children: vec![],
}; };
@@ -70,6 +63,7 @@ pub fn get_all_file_types(top_level_nodes: Vec<Node>, n: usize) -> Option<Displa
let result = DisplayNode { let result = DisplayNode {
name: PathBuf::from("(total)"), name: PathBuf::from("(total)"),
size: displayed.iter().map(|a| a.size).sum(), size: displayed.iter().map(|a| a.size).sum(),
depth: 0,
children: displayed, children: displayed,
}; };
Some(result) Some(result)
@@ -77,17 +71,20 @@ pub fn get_all_file_types(top_level_nodes: Vec<Node>, n: usize) -> Option<Displa
fn add_children<'a>( fn add_children<'a>(
using_a_filter: bool, using_a_filter: bool,
line: &'a Node, file_or_folder: &'a Node,
depth: usize,
mut heap: BinaryHeap<&'a Node>, mut heap: BinaryHeap<&'a Node>,
) -> BinaryHeap<&'a Node> { ) -> BinaryHeap<&'a Node> {
if using_a_filter { if depth > file_or_folder.depth {
line.children.iter().for_each(|c| { if using_a_filter {
if c.name.is_file() || c.size > 0 { file_or_folder.children.iter().for_each(|c| {
heap.push(c) if c.name.is_file() || c.size > 0 {
} heap.push(c)
}); }
} else { });
line.children.iter().for_each(|c| heap.push(c)); } else {
file_or_folder.children.iter().for_each(|c| heap.push(c));
}
} }
heap heap
} }
@@ -103,6 +100,7 @@ fn build_by_all_file_types(top_level_nodes: Vec<Node>, counter: &mut HashMap<Str
let mut display_node = counter.entry(key.clone()).or_insert(DisplayNode { let mut display_node = counter.entry(key.clone()).or_insert(DisplayNode {
name: PathBuf::from(key), name: PathBuf::from(key),
size: 0, size: 0,
depth: node.depth,
children: vec![], children: vec![],
}); });
display_node.size += node.size; display_node.size += node.size;
@@ -111,29 +109,6 @@ fn build_by_all_file_types(top_level_nodes: Vec<Node>, counter: &mut HashMap<Str
} }
} }
fn build_by_depth(node: &Node, depth: usize) -> DisplayNode {
let new_children = {
if depth == 0 {
vec![]
} else {
let mut new_children: Vec<_> = node
.children
.iter()
.map(|c| build_by_depth(c, depth - 1))
.collect();
new_children.sort();
new_children.reverse();
new_children
}
};
DisplayNode {
name: node.name.clone(),
size: node.size,
children: new_children,
}
}
fn get_new_root(top_level_nodes: Vec<Node>) -> Node { fn get_new_root(top_level_nodes: Vec<Node>) -> Node {
if top_level_nodes.len() > 1 { if top_level_nodes.len() > 1 {
let total_size = top_level_nodes.iter().map(|node| node.size).sum(); let total_size = top_level_nodes.iter().map(|node| node.size).sum();
@@ -142,6 +117,7 @@ fn get_new_root(top_level_nodes: Vec<Node>) -> Node {
size: total_size, size: total_size,
children: top_level_nodes, children: top_level_nodes,
inode_device: None, inode_device: None,
depth: 0,
} }
} else { } else {
top_level_nodes.into_iter().next().unwrap() top_level_nodes.into_iter().next().unwrap()
@@ -168,6 +144,7 @@ fn recursive_rebuilder<'a>(
let newnode = DisplayNode { let newnode = DisplayNode {
name: current.name.clone(), name: current.name.clone(),
size: current.size, size: current.size,
depth: current.depth,
children: new_children, children: new_children,
}; };
Some(newnode) Some(newnode)
+29 -25
View File
@@ -10,7 +10,7 @@ use self::display::draw_it;
use clap::{crate_version, Arg}; use clap::{crate_version, Arg};
use clap::{Command, Values}; use clap::{Command, Values};
use dir_walker::{walk_it, WalkData}; use dir_walker::{walk_it, WalkData};
use filter::{get_all_file_types, get_biggest, get_by_depth}; use filter::{get_all_file_types, get_biggest};
use regex::Regex; use regex::Regex;
use std::cmp::max; use std::cmp::max;
use std::path::PathBuf; use std::path::PathBuf;
@@ -99,9 +99,6 @@ fn get_regex_value(maybe_value: Option<Values>) -> Vec<Regex> {
} }
fn main() { fn main() {
let default_height = get_height_of_terminal();
let def_num_str = default_height.to_string();
let options = Command::new("Dust") let options = Command::new("Dust")
.about("Like du but more intuitive") .about("Like du but more intuitive")
.version(crate_version!()) .version(crate_version!())
@@ -112,7 +109,7 @@ fn main() {
.long("depth") .long("depth")
.help("Depth to show") .help("Depth to show")
.takes_value(true) .takes_value(true)
.conflicts_with("number_of_lines"), .default_value(usize::MAX.to_string().as_ref())
) )
.arg( .arg(
Arg::new("number_of_lines") Arg::new("number_of_lines")
@@ -120,7 +117,6 @@ fn main() {
.long("number-of-lines") .long("number-of-lines")
.help("Number of lines of output to show. (Default is terminal_height - 10)") .help("Number of lines of output to show. (Default is terminal_height - 10)")
.takes_value(true) .takes_value(true)
.default_value(def_num_str.as_ref()),
) )
.arg( .arg(
Arg::new("display_full_paths") Arg::new("display_full_paths")
@@ -188,7 +184,6 @@ fn main() {
.multiple_occurrences(true) .multiple_occurrences(true)
.conflicts_with("filter") .conflicts_with("filter")
.conflicts_with("types") .conflicts_with("types")
.conflicts_with("depth")
.help("Exclude filepaths matching this regex. To ignore png files type: -v \"\\.png$\" "), .help("Exclude filepaths matching this regex. To ignore png files type: -v \"\\.png$\" "),
) )
.arg( .arg(
@@ -199,7 +194,6 @@ fn main() {
.number_of_values(1) .number_of_values(1)
.multiple_occurrences(true) .multiple_occurrences(true)
.conflicts_with("types") .conflicts_with("types")
.conflicts_with("depth")
.help("Only include filepaths matching this regex. For png files type: -e \"\\.png$\" "), .help("Only include filepaths matching this regex. For png files type: -e \"\\.png$\" "),
) )
.arg( .arg(
@@ -236,26 +230,36 @@ fn main() {
let filter_regexs = get_regex_value(options.values_of("filter")); let filter_regexs = get_regex_value(options.values_of("filter"));
let invert_filter_regexs = get_regex_value(options.values_of("invert_filter")); let invert_filter_regexs = get_regex_value(options.values_of("invert_filter"));
let number_of_lines = match options.value_of_t("number_of_lines") {
Ok(v) => v,
Err(_) => {
eprintln!("Ignoring bad value for number_of_lines");
default_height
}
};
let terminal_width = match options.value_of_t("width") { let terminal_width = match options.value_of_t("width") {
Ok(v) => v, Ok(v) => v,
Err(_) => get_width_of_terminal(), Err(_) => get_width_of_terminal(),
}; };
let depth = options.value_of("depth").and_then(|depth| { let depth = match options.value_of_t("depth") {
depth Ok(v) => v,
.parse::<usize>() Err(_) => {
.map(|v| v + 1) eprintln!("Ignoring bad value for depth");
.map_err(|_| eprintln!("Ignoring bad value for depth")) usize::MAX
.ok() }
}); };
// If depth is set we set the default number_of_lines to be max
// instead of screen height
let default_height = if depth != usize::MAX {
usize::MAX
} else {
get_height_of_terminal()
};
let number_of_lines = match options.value_of("number_of_lines") {
Some(v) => match v.parse::<usize>() {
Ok(num_lines) => num_lines,
Err(_) => {
eprintln!("Ignoring bad value for number_of_lines");
default_height
}
},
None => default_height,
};
let no_colors = init_color(options.is_present("no_colors")); let no_colors = init_color(options.is_present("no_colors"));
let use_apparent_size = options.is_present("display_apparent_size"); let use_apparent_size = options.is_present("display_apparent_size");
@@ -297,10 +301,10 @@ fn main() {
let tree = { let tree = {
match (depth, summarize_file_types) { match (depth, summarize_file_types) {
(_, true) => get_all_file_types(top_level_nodes, number_of_lines), (_, true) => get_all_file_types(top_level_nodes, number_of_lines),
(Some(depth), _) => get_by_depth(top_level_nodes, depth), (depth, _) => get_biggest(
(_, _) => get_biggest(
top_level_nodes, top_level_nodes,
number_of_lines, number_of_lines,
depth,
options.values_of("filter").is_some() options.values_of("filter").is_some()
|| options.value_of("invert_filter").is_some(), || options.value_of("invert_filter").is_some(),
), ),
+3
View File
@@ -12,6 +12,7 @@ pub struct Node {
pub size: u64, pub size: u64,
pub children: Vec<Node>, pub children: Vec<Node>,
pub inode_device: Option<(u64, u64)>, pub inode_device: Option<(u64, u64)>,
pub depth: usize,
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@@ -24,6 +25,7 @@ pub fn build_node(
is_symlink: bool, is_symlink: bool,
is_file: bool, is_file: bool,
by_filecount: bool, by_filecount: bool,
depth: usize,
) -> Option<Node> { ) -> Option<Node> {
match get_metadata(&dir, use_apparent_size) { match get_metadata(&dir, use_apparent_size) {
Some(data) => { Some(data) => {
@@ -50,6 +52,7 @@ pub fn build_node(
size, size,
children, children,
inode_device, inode_device,
depth,
}) })
} }
None => None, None => None,
+2 -2
View File
@@ -114,8 +114,8 @@ pub fn get_metadata(d: &Path, _use_apparent_size: bool) -> Option<(u64, Option<(
let attr_filtered = md.file_attributes() let attr_filtered = md.file_attributes()
& !(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM); & !(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM);
if attr_filtered == FILE_ATTRIBUTE_ARCHIVE if (attr_filtered & FILE_ATTRIBUTE_ARCHIVE) != 0
|| attr_filtered == FILE_ATTRIBUTE_DIRECTORY || (attr_filtered & FILE_ATTRIBUTE_DIRECTORY) != 0
|| md.file_attributes() == FILE_ATTRIBUTE_NORMAL || md.file_attributes() == FILE_ATTRIBUTE_NORMAL
{ {
Some((md.len(), None)) Some((md.len(), None))
+5 -6
View File
@@ -7,11 +7,10 @@ use regex::Regex;
pub fn simplify_dir_names<P: AsRef<Path>>(filenames: Vec<P>) -> HashSet<PathBuf> { 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()); let mut top_level_names: HashSet<PathBuf> = HashSet::with_capacity(filenames.len());
let mut to_remove: Vec<PathBuf> = Vec::with_capacity(filenames.len());
for t in filenames { for t in filenames {
let top_level_name = normalize_path(t); let top_level_name = normalize_path(t);
let mut can_add = true; let mut can_add = true;
let mut to_remove: Vec<PathBuf> = Vec::new();
for tt in top_level_names.iter() { for tt in top_level_names.iter() {
if is_a_parent_of(&top_level_name, tt) { if is_a_parent_of(&top_level_name, tt) {
@@ -20,14 +19,13 @@ pub fn simplify_dir_names<P: AsRef<Path>>(filenames: Vec<P>) -> HashSet<PathBuf>
can_add = false; can_add = false;
} }
} }
to_remove.sort_unstable(); for r in to_remove {
top_level_names.retain(|tr| to_remove.binary_search(tr).is_err()); top_level_names.remove(&r);
to_remove.clear(); }
if can_add { if can_add {
top_level_names.insert(top_level_name); top_level_names.insert(top_level_name);
} }
} }
top_level_names top_level_names
} }
@@ -94,6 +92,7 @@ mod tests {
fn test_simplify_dir_rm_subdir() { fn test_simplify_dir_rm_subdir() {
let mut correct = HashSet::new(); let mut correct = HashSet::new();
correct.insert(["a", "b"].iter().collect::<PathBuf>()); correct.insert(["a", "b"].iter().collect::<PathBuf>());
assert_eq!(simplify_dir_names(vec!["a/b/c", "a/b", "a/b/d/f"]), correct);
assert_eq!(simplify_dir_names(vec!["a/b", "a/b/c", "a/b/d/f"]), correct); assert_eq!(simplify_dir_names(vec!["a/b", "a/b/c", "a/b/d/f"]), correct);
} }