Compare commits

...

8 Commits

Author SHA1 Message Date
bootandy 2fe3943ed5 Update readme 2018-04-06 21:07:13 +01:00
bootandy b8ad44b7f0 increment version 2018-04-06 20:49:22 +01:00
bootandy 1a34bc3198 Integration tests
Several tests for recursive dirs, hard & soft links.
Tests use the tempfile project.

Personally I find the tests hard to read. Am considering adding a
'--no-color' output option as this will make the tests much more
readable. (Currently we have to call format_string to get the matching
colors and if a test fails the diff is very hard to read).
2018-04-06 20:44:02 +01:00
bootandy 385ddb75e1 Minor code neatening 2018-04-06 20:35:00 +01:00
bootandy 5c6165da8a First integration test
This test needs neatening but it is the first example of a working
integration test
2018-04-05 14:45:04 +01:00
bootandy f39b09e79c increment version (0.2.1 already tagged) 2018-04-05 14:45:04 +01:00
bootandy 778dbb44b3 Remove graying background
Remove background that gets grayer.
1) This looks funny on terminals that aren't black
2) Makes testing easier
2018-04-04 23:12:00 +01:00
bootandy 69c79d5f95 Update readme 2018-04-04 20:21:59 +01:00
7 changed files with 182 additions and 29 deletions
+4 -1
View File
@@ -1,8 +1,11 @@
[package] [package]
name = "dust" name = "dust"
version = "0.2.0" version = "0.2.3"
authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"] authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"]
[dependencies] [dependencies]
ansi_term = "0.11" ansi_term = "0.11"
clap = "2.31" clap = "2.31"
assert_cli = "0.5"
tempfile = "3"
+8
View File
@@ -5,6 +5,10 @@
du + rust = dust. A rust alternative to du du + rust = dust. A rust alternative to du
[Releases](https://github.com/bootandy/dust/releases) [Releases](https://github.com/bootandy/dust/releases)
To install:
* Download linux / mac binary from [Releases](https://github.com/bootandy/dust/releases)
* unzip file: tar -xvf <file>
* copy file to search path: sudo mv dust /usr/local/bin/
Unlike du, dust is meant to give you an instant overview of which directories are using disk space without requiring sort or head. Dust does not count file system blocks; it uses file sizes instead. Dust will print a maximum of 1 'Did not have permissions message'. Unlike du, dust is meant to give you an instant overview of which directories are using disk space without requiring sort or head. Dust does not count file system blocks; it uses file sizes instead. Dust will print a maximum of 1 'Did not have permissions message'.
@@ -40,4 +44,8 @@ djin:git/dust> dust
``` ```
Performance: dust is currently about 4 times slower than du. Performance: dust is currently about 4 times slower than du.
Alternatives:
* [NCDU](https://dev.yorhel.nl/ncdu)
* 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.
+23 -26
View File
@@ -1,8 +1,7 @@
extern crate ansi_term; extern crate ansi_term;
use dust::Node;
use std::cmp;
use self::ansi_term::Colour::Fixed; use self::ansi_term::Colour::Fixed;
use dust::Node;
static UNITS: [char; 4] = ['T', 'G', 'M', 'K']; static UNITS: [char; 4] = ['T', 'G', 'M', 'K'];
@@ -13,7 +12,7 @@ pub fn draw_it(permissions: bool, heads: &Vec<Node>, to_display: &Vec<&Node>) ->
for d in to_display { for d in to_display {
if heads.contains(d) { if heads.contains(d) {
display_node(d, &to_display, true, 1, "") display_node(d, &to_display, true, "")
} }
} }
} }
@@ -22,11 +21,10 @@ fn display_node<S: Into<String>>(
node_to_print: &Node, node_to_print: &Node,
to_display: &Vec<&Node>, to_display: &Vec<&Node>,
is_first: bool, is_first: bool,
depth: u8,
indentation_str: S, indentation_str: S,
) { ) {
let mut is = indentation_str.into(); let mut is = indentation_str.into();
print_this_node(node_to_print, is_first, depth, is.as_ref()); print_this_node(node_to_print, is_first, is.as_ref());
is = is.replace("└─┬", " "); is = is.replace("└─┬", " ");
is = is.replace("└──", " "); is = is.replace("└──", " ");
@@ -71,36 +69,35 @@ fn display_node<S: Into<String>>(
} }
} }
}; };
display_node( display_node(&node, to_display, is_biggest, is.to_string() + tree_chars);
&node,
to_display,
is_biggest,
depth + 1,
is.to_string() + tree_chars,
);
is_biggest = false; is_biggest = false;
} }
} }
} }
} }
fn print_this_node(node_to_print: &Node, is_biggest: bool, depth: u8, indentation_str: &str) { fn print_this_node(node: &Node, is_biggest: bool, indentation: &str) {
let padded_size = format!("{:>5}", human_readable_number(node_to_print.size()),); let pretty_size = format!("{:>5}", human_readable_number(node.size()),);
println!( println!(
"{} {} {}", "{}",
if is_biggest { format_string(node.name(), is_biggest, pretty_size.as_ref(), indentation)
Fixed(196).paint(padded_size) )
} else {
Fixed(7).paint(padded_size)
},
indentation_str,
Fixed(7)
.on(Fixed(cmp::min(8, (depth) as u8) + 231))
.paint(node_to_print.name().to_string())
);
} }
fn human_readable_number(size: u64) -> (String) { pub fn format_string(dir_name: &str, is_biggest: bool, size: &str, indentation: &str) -> String {
format!(
"{} {} {}",
if is_biggest {
Fixed(196).paint(size)
} else {
Fixed(7).paint(size)
},
indentation,
dir_name,
)
}
fn human_readable_number(size: u64) -> String {
for (i, u) in UNITS.iter().enumerate() { for (i, u) in UNITS.iter().enumerate() {
let marker = 1024u64.pow((UNITS.len() - i) as u32); let marker = 1024u64.pow((UNITS.len() - i) as u32);
if size >= marker { if size >= marker {
+6 -2
View File
@@ -1,13 +1,14 @@
#[macro_use] #[macro_use]
extern crate clap; extern crate clap;
extern crate assert_cli;
extern crate dust; extern crate dust;
use self::display::draw_it;
use clap::{App, AppSettings, Arg}; use clap::{App, AppSettings, Arg};
use utils::{find_big_ones, get_dir_tree}; use utils::{find_big_ones, get_dir_tree};
use self::display::draw_it;
mod utils;
mod display; mod display;
mod utils;
static DEFAULT_NUMBER_OF_LINES: &'static str = "15"; static DEFAULT_NUMBER_OF_LINES: &'static str = "15";
@@ -42,3 +43,6 @@ fn main() {
let slice_it = find_big_ones(&node_per_top_level_dir, number_of_lines); let slice_it = find_big_ones(&node_per_top_level_dir, number_of_lines);
draw_it(permissions, &node_per_top_level_dir, &slice_it); draw_it(permissions, &node_per_top_level_dir, &slice_it);
} }
#[cfg(test)]
mod tests;
View File
+1
View File
@@ -0,0 +1 @@
hello
+140
View File
@@ -0,0 +1,140 @@
extern crate ansi_term;
extern crate tempfile;
use self::tempfile::Builder;
use self::tempfile::TempDir;
use super::*;
use display::format_string;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
#[test]
pub fn test_main() {
let r = format!(
"{}
{}
{}
{}",
format_string("src/test_dir", true, " 4.0K", ""),
format_string("src/test_dir/many", true, " 4.0K", "└─┬",),
format_string("src/test_dir/many/hello_file", true, " 4.0K", " ├──",),
format_string("src/test_dir/many/a_file", false, " 0B", " └──",),
);
assert_cli::Assert::main_binary()
.with_args(&["src/test_dir"])
.stdout()
.is(r)
.unwrap();
}
#[test]
pub fn test_apparent_size() {
let r = format!(
"{}",
format_string("src/test_dir/many/hello_file", true, " 6B", " ├──",),
);
assert_cli::Assert::main_binary()
.with_args(&["-s", "src/test_dir"])
.stdout()
.contains(r)
.unwrap();
}
fn build_temp_file(dir: &TempDir) -> (PathBuf) {
let file_path = dir.path().join("notes.txt");
let mut file = File::create(&file_path).unwrap();
writeln!(file, "I am a temp file").unwrap();
file_path
}
#[test]
pub fn test_soft_sym_link() {
let dir = Builder::new().tempdir().unwrap();
let file = build_temp_file(&dir);
let dir_s = dir.path().to_str().unwrap();
let file_path_s = file.to_str().unwrap();
let link_name = dir.path().join("the_link");
let link_name_s = link_name.to_str().unwrap();
let c = Command::new("ln")
.arg("-s")
.arg(file_path_s)
.arg(link_name_s)
.output();
assert!(c.is_ok());
let r = format!(
"{}
{}
{}",
format_string(dir_s, true, " 8.0K", ""),
format_string(file_path_s, true, " 4.0K", "├──",),
format_string(link_name_s, false, " 4.0K", "└──",),
);
assert_cli::Assert::main_binary()
.with_args(&[dir_s])
.stdout()
.contains(r)
.unwrap();
}
// Hard links are ignored as the inode is the same as the file
#[test]
pub fn test_hard_sym_link() {
let dir = Builder::new().tempdir().unwrap();
let file = build_temp_file(&dir);
let dir_s = dir.path().to_str().unwrap();
let file_path_s = file.to_str().unwrap();
let link_name = dir.path().join("the_link");
let link_name_s = link_name.to_str().unwrap();
let c = Command::new("ln")
.arg(file_path_s)
.arg(link_name_s)
.output();
assert!(c.is_ok());
let r = format!(
"{}
{}",
format_string(dir_s, true, " 4.0K", ""),
format_string(file_path_s, true, " 4.0K", "└──")
);
assert_cli::Assert::main_binary()
.with_args(&[dir_s])
.stdout()
.contains(r)
.unwrap();
}
//Check we don't recurse down an infinite symlink tree
#[test]
pub fn test_recursive_sym_link() {
let dir = Builder::new().tempdir().unwrap();
let dir_s = dir.path().to_str().unwrap();
let link_name = dir.path().join("the_link");
let link_name_s = link_name.to_str().unwrap();
let c = Command::new("cd").arg(dir_s).output();
assert!(c.is_ok());
let c = Command::new("ln")
.arg("-s")
.arg(".")
.arg(link_name_s)
.output();
assert!(c.is_ok());
let r = format!("{}", format_string(dir_s, true, " 4.0K", ""));
assert_cli::Assert::main_binary()
.with_args(&[dir_s])
.stdout()
.contains(r)
.unwrap();
}