Compare commits

...

9 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
bootandy 61ab0e8f96 Simplify build.
Just build mac and linux.
Remove appveyor file which was designed for windows.
2018-04-03 20:54:53 +01:00
9 changed files with 184 additions and 130 deletions
-8
View File
@@ -19,17 +19,9 @@ matrix:
# don't need # don't need
include: include:
# Linux # Linux
- env: TARGET=aarch64-unknown-linux-gnu
- env: TARGET=arm-unknown-linux-gnueabi
- env: TARGET=armv7-unknown-linux-gnueabihf
- env: TARGET=i686-unknown-linux-gnu
- env: TARGET=i686-unknown-linux-musl
- env: TARGET=x86_64-unknown-linux-gnu - env: TARGET=x86_64-unknown-linux-gnu
- env: TARGET=x86_64-unknown-linux-musl
# OSX # OSX
- env: TARGET=i686-apple-darwin
os: osx
- env: TARGET=x86_64-apple-darwin - env: TARGET=x86_64-apple-darwin
os: osx os: osx
+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"
+10
View File
@@ -4,6 +4,12 @@
# Dust # Dust
du + rust = dust. A rust alternative to du du + rust = dust. A rust alternative to du
[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'.
@@ -38,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.
-93
View File
@@ -1,93 +0,0 @@
# Based on the "trust" template v0.1.2
# https://github.com/japaric/trust/tree/v0.1.2
environment:
global:
# TODO This is the Rust channel that build jobs will use by default but can be
# overridden on a case by case basis down below
RUST_VERSION: stable
# TODO Update this to match the name of your project.
CRATE_NAME: dust
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
# don't need
matrix:
# MinGW
- TARGET: i686-pc-windows-gnu
- TARGET: x86_64-pc-windows-gnu
# MSVC
- TARGET: i686-pc-windows-msvc
- TARGET: x86_64-pc-windows-msvc
# Testing other channels
- TARGET: x86_64-pc-windows-gnu
RUST_VERSION: nightly
- TARGET: x86_64-pc-windows-msvc
RUST_VERSION: nightly
install:
- ps: >-
If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') {
$Env:PATH += ';C:\msys64\mingw64\bin'
} ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') {
$Env:PATH += ';C:\msys64\mingw32\bin'
}
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
- rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION%
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
- rustc -Vv
- cargo -V
# TODO This is the "test phase", tweak it as you see fit
test_script:
# we don't run the "test phase" when doing deploys
- if [%APPVEYOR_REPO_TAG%]==[false] (
cargo build --target %TARGET% &&
cargo build --target %TARGET% --release &&
cargo test --target %TARGET% &&
cargo test --target %TARGET% --release &&
cargo run --target %TARGET% &&
cargo run --target %TARGET% --release
)
before_deploy:
# TODO Update this to build the artifacts that matter to you
- cargo rustc --target %TARGET% --release --bin hello -- -C lto
- ps: ci\before_deploy.ps1
deploy:
artifact: /.*\.zip/
# TODO update `auth_token.secure`
# - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
# - Encrypt it. Go to https://ci.appveyor.com/tools/encrypt
# - Paste the output down here
auth_token:
secure: UlU73Td7Bkb2N88ws4YGLWR+4U0IMgiou9QQtMnmpouJFjeUNxtLSPMPODVXP7zq4sKt5HR5B3fX9MW4mKm351fvnQEoihETn06pKiXGnY//SlTPTt67MX9ZOYmd9ohJReMDOZDgqhnGLxfymycGtsLAmdjDZnAl+IMqgg0FMyVFj9Cl9aKxnn12lxQyX4zabHKk8TUKD3By8ZoEUnJMHt3gEtOmbDgS4brcTPeHCzqnYFw73LEnkqvz+JP0XwauJY7Cf8lminKm/klmjCkQji8T9SHI52v1g0Fxpx0ucp2o3vulQrLHXaHvZ6Fr7J0cSXXzaFF3rrGLt4t4jU/+9TZm1+n5k5XuPW4x4NTCC9NmIj/z0/z41t82E9qZhzhtm2Jdsg6H2tNk+C774TYqcmR6GCvfRadfjRp3cA5dh0UwDVjH2MJFxlHDVkl6la0mVVRsCGF3oBKZVk0BDl1womfnmI46o/uU+gLknHN6Ed6PHHPPYDViWd3VKdmHKT7XrkMMUF6HjZUtla689DWIOWZSiV++1dVPcl/1TV+6tTmN4bBtPcLuX7SHRuLp2PI2kATvRMECsa7gZRypW4jKpVn7b2yetX9TVI3i1zR5zkQJ3dPg8sATvYPL53aKH/WsqUg4rzoAlbk9so+++R4bQY69LhV3B511B7EAynoZFdM
description: ''
on:
# TODO Here you can pick which targets will generate binary releases
# In this example, there are some targets that are tested using the stable
# and nightly channels. This condition makes sure there is only one release
# for such targets and that's generated using the stable channel
RUST_VERSION: stable
appveyor_repo_tag: true
provider: GitHub
cache:
- C:\Users\appveyor\.cargo\registry
- target
branches:
only:
# Release tags
- /^v\d+\.\d+\.\d+.*$/
- master
notifications:
- provider: Email
on_build_success: false
# Building is done in the test phase, so we disable Appveyor's build phase.
build: false
+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();
}