mirror of
https://github.com/bootandy/dust.git
synced 2026-06-08 11:29:05 +03:00
Large redesign
Use the whole width of the terminal assume width of 80 if none found Show percentages in the final column. Show ASCII bars indicating usage of the underlying directories in the space inbetween. Display (height of terminal - 10) entries by default. Reverse the output order so largest is at the bottom. Break up tests. Change older tests to check real output of program.
This commit is contained in:
-83
@@ -1,83 +0,0 @@
|
|||||||
# Based on the "trust" template v0.1.2
|
|
||||||
# https://github.com/japaric/trust/tree/v0.1.2
|
|
||||||
|
|
||||||
# ----------- To do a release ---------
|
|
||||||
# tag a commit and push:
|
|
||||||
# git tag v0.4.0.1
|
|
||||||
# git push origin v0.4.0.1
|
|
||||||
# Remember to do a cargo publish to put it in crates.io
|
|
||||||
|
|
||||||
dist: trusty
|
|
||||||
language: rust
|
|
||||||
services: docker
|
|
||||||
sudo: required
|
|
||||||
|
|
||||||
# TODO Rust builds on stable by default, this can be
|
|
||||||
# overridden on a case by case basis down below.
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
# TODO Update this to match the name of your project.
|
|
||||||
- CRATE_NAME=dust
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
|
|
||||||
# don't need
|
|
||||||
include:
|
|
||||||
# Linux
|
|
||||||
- env: TARGET=x86_64-unknown-linux-gnu
|
|
||||||
|
|
||||||
# OSX
|
|
||||||
- env: TARGET=x86_64-apple-darwin
|
|
||||||
os: osx
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- set -e
|
|
||||||
- rustup self update
|
|
||||||
|
|
||||||
install:
|
|
||||||
- sh ci/install.sh
|
|
||||||
- source ~/.cargo/env || true
|
|
||||||
|
|
||||||
script:
|
|
||||||
- bash ci/script.sh
|
|
||||||
|
|
||||||
after_script: set +e
|
|
||||||
|
|
||||||
before_deploy:
|
|
||||||
- sh ci/before_deploy.sh
|
|
||||||
|
|
||||||
deploy:
|
|
||||||
# TODO update `api_key.secure`
|
|
||||||
# - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
|
|
||||||
# - Encrypt it: `travis encrypt 0123456789012345678901234567890123456789
|
|
||||||
# - Paste the output down here
|
|
||||||
# api_key:
|
|
||||||
# secure: UlU73Td7Bkb2N88ws4YGLWR+4U0IMgiou9QQtMnmpouJFjeUNxtLSPMPODVXP7zq4sKt5HR5B3fX9MW4mKm351fvnQEoihETn06pKiXGnY//SlTPTt67MX9ZOYmd9ohJReMDOZDgqhnGLxfymycGtsLAmdjDZnAl+IMqgg0FMyVFj9Cl9aKxnn12lxQyX4zabHKk8TUKD3By8ZoEUnJMHt3gEtOmbDgS4brcTPeHCzqnYFw73LEnkqvz+JP0XwauJY7Cf8lminKm/klmjCkQji8T9SHI52v1g0Fxpx0ucp2o3vulQrLHXaHvZ6Fr7J0cSXXzaFF3rrGLt4t4jU/+9TZm1+n5k5XuPW4x4NTCC9NmIj/z0/z41t82E9qZhzhtm2Jdsg6H2tNk+C774TYqcmR6GCvfRadfjRp3cA5dh0UwDVjH2MJFxlHDVkl6la0mVVRsCGF3oBKZVk0BDl1womfnmI46o/uU+gLknHN6Ed6PHHPPYDViWd3VKdmHKT7XrkMMUF6HjZUtla689DWIOWZSiV++1dVPcl/1TV+6tTmN4bBtPcLuX7SHRuLp2PI2kATvRMECsa7gZRypW4jKpVn7b2yetX9TVI3i1zR5zkQJ3dPg8sATvYPL53aKH/WsqUg4rzoAlbk9so+++R4bQY69LhV3B511B7EAynoZFdM
|
|
||||||
api_key: $API_KEY
|
|
||||||
file_glob: true
|
|
||||||
file: $CRATE_NAME-$TRAVIS_TAG-$TARGET.*
|
|
||||||
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
|
|
||||||
condition: $TRAVIS_RUST_VERSION = stable
|
|
||||||
tags: true
|
|
||||||
provider: releases
|
|
||||||
skip_cleanup: true
|
|
||||||
|
|
||||||
cache: cargo
|
|
||||||
before_cache:
|
|
||||||
# Travis can't cache files that are not readable by "others"
|
|
||||||
- chmod -R a+r $HOME/.cargo
|
|
||||||
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
# release tags
|
|
||||||
- /^v\d+\.\d+\.\d+.*$/
|
|
||||||
- master
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email:
|
|
||||||
on_success: never
|
|
||||||
Generated
+25
-13
@@ -26,7 +26,7 @@ dependencies = [
|
|||||||
"environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -46,7 +46,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.42"
|
version = "0.3.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -188,6 +188,8 @@ dependencies = [
|
|||||||
"jwalk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"jwalk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"terminal_size 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -206,7 +208,7 @@ name = "failure"
|
|||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -217,7 +219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -241,7 +243,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.4"
|
version = "0.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -416,10 +418,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.44"
|
version = "1.0.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@@ -431,7 +433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.13"
|
version = "1.0.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -446,7 +448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -463,6 +465,15 @@ dependencies = [
|
|||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "terminal_size"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@@ -524,7 +535,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum assert_cli 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a29ab7c0ed62970beb0534d637a8688842506d0ff9157de83286dacd065c8149"
|
"checksum assert_cli 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a29ab7c0ed62970beb0534d637a8688842506d0ff9157de83286dacd065c8149"
|
||||||
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||||
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
|
||||||
"checksum backtrace 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b4b1549d804b6c73f4817df2ba073709e96e426f12987127c48e6745568c350b"
|
"checksum backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e4036b9bf40f3cf16aba72a3d65e8a520fc4bafcdc7079aea8f848c58c5b5536"
|
||||||
"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
|
"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
|
||||||
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||||
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
|
"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
|
||||||
@@ -545,7 +556,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08"
|
"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08"
|
||||||
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||||
"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
|
"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
|
||||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||||
"checksum jwalk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3dbf0a8f61baee43a2918ff50ac6a2d3b2c105bc08ed53bc298779f1263409"
|
"checksum jwalk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3dbf0a8f61baee43a2918ff50ac6a2d3b2c105bc08ed53bc298779f1263409"
|
||||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||||
@@ -569,11 +580,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
||||||
"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7"
|
"checksum serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "15913895b61e0be854afd32fd4163fcd2a3df34142cf2cb961b310ce694cbf90"
|
||||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||||
"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8"
|
"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5"
|
||||||
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
||||||
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||||
|
"checksum terminal_size 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "e25a60e3024df9029a414be05f46318a77c22538861a22170077d0388c0e926e"
|
||||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||||
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ ansi_term = "=0.12"
|
|||||||
clap = "=2.33"
|
clap = "=2.33"
|
||||||
jwalk = "0.4.0"
|
jwalk = "0.4.0"
|
||||||
num_cpus = "1.12"
|
num_cpus = "1.12"
|
||||||
|
terminal_size = "0.1.10"
|
||||||
|
unicode-width = "0.1.7"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi-util = "0.1"
|
winapi-util = "0.1"
|
||||||
@@ -32,3 +34,8 @@ winapi-util = "0.1"
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cli = "=0.6"
|
assert_cli = "=0.6"
|
||||||
tempfile = "=3"
|
tempfile = "=3"
|
||||||
|
|
||||||
|
|
||||||
|
[[test]]
|
||||||
|
name = "integration"
|
||||||
|
path = "tests/tests.rs"
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ du + rust = dust. Like du but more intuitive
|
|||||||
|
|
||||||
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 1 'Did not have permissions message'.
|
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 1 'Did not have permissions message'.
|
||||||
|
|
||||||
Dust will list the 20 biggest sub directories 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 sub directory will have its size shown in *red*
|
Dust will list the terminal height - 10 biggest sub directories 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 sub directory will have its size shown in *red*
|
||||||
|
|
||||||
## Why?
|
## Why?
|
||||||
|
|
||||||
@@ -42,26 +42,43 @@ Usage: dust -d 3 <dir> (Shows 3 levels of subdirectories)
|
|||||||
Usage: dust -r <dir> (Reverse order of output, with root at the lowest)
|
Usage: dust -r <dir> (Reverse order of output, with root at the lowest)
|
||||||
Usage: dust -x <dir> (Only show directories on same filesystem)
|
Usage: dust -x <dir> (Only show directories on same filesystem)
|
||||||
Usage: dust -X ignore <dir> (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 -b <dir> (Do not show percentages or draw the ASCII bars)
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
djin:git/dust> dust
|
$ dust target
|
||||||
1.2G target
|
15M ┌── build │ ░█ │ 2%
|
||||||
622M ├─┬ debug
|
25M ├── deps │ ░█ │ 4%
|
||||||
445M │ ├── deps
|
45M ┌─┴ release │ ██ │ 7%
|
||||||
70M │ ├── incremental
|
84M │ ┌── build │ ▒▒▒▒▒████ │ 13%
|
||||||
56M │ └── build
|
7.6M │ │ ┌── libsynstructure-f7552412787ad339.rlib│ ▒▒▒▓▓▓▓▓█ │ 1%
|
||||||
262M ├─┬ rls
|
16M │ │ ├── libfailure_derive-e18365d3e6be2e2c.so│ ▒▒▒▓▓▓▓▓█ │ 2%
|
||||||
262M │ └─┬ debug
|
18M │ │ ├── libsyn-9ad95b745845d5dd.rlib │ ▒▒▒▓▓▓▓▓█ │ 3%
|
||||||
203M │ ├── deps
|
19M │ │ ├── libsyn-d4a3458fcb1c592c.rlib │ ▒▒▒▓▓▓▓▓█ │ 3%
|
||||||
56M │ └── build
|
135M │ ├─┴ deps │ ▒▒▒██████ │ 20%
|
||||||
165M ├─┬ package
|
228M │ ┌─┴ debug │ █████████ │ 34%
|
||||||
165M │ └─┬ du-dust-0.2.4
|
228M ├─┴ rls │ █████████ │ 34%
|
||||||
165M │ └─┬ target
|
18M │ ┌── dust │ ░░░░░░░░░░░░░░█ │ 3%
|
||||||
165M │ └─┬ debug
|
22M │ ├── dust-a0c31c4633c5fc8b │ ░░░░░░░░░░░░░░█ │ 3%
|
||||||
131M │ └── deps
|
7.4M │ │ ┌── s-fkrj3vfncf-19aj951-1fv3o6tzvr348 │ ░░░░░░░░░░░░░▒█ │ 1%
|
||||||
165M └─┬ release
|
7.4M │ │ ┌─┴ dust-1i3xquz5fns51 │ ░░░░░░░░░░░░░▒█ │ 1%
|
||||||
124M └── deps
|
40M │ ├─┴ incremental │ ░░░░░░░░░░░░░██ │ 6%
|
||||||
|
41M │ ├── build │ ░░░░░░░░░░░░░██ │ 6%
|
||||||
|
7.6M │ │ ┌── libsynstructure-f7552412787ad339.rlib │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 1%
|
||||||
|
8.2M │ │ ├── libserde-ab4b407a415bc8fc.rmeta │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 1%
|
||||||
|
9.4M │ │ ├── libserde-ab4b407a415bc8fc.rlib │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 1%
|
||||||
|
11M │ │ ├── tests_symlinks-bf063461b7be6a99 │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 2%
|
||||||
|
11M │ │ ├── integration-08f999d253e3b70c │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 2%
|
||||||
|
15M │ │ ├── dust-1c6e63725d641738 │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 2%
|
||||||
|
16M │ │ ├── libfailure_derive-e18365d3e6be2e2c.so │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 2%
|
||||||
|
18M │ │ ├── dust-3a419f62b84d73c1 │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 3%
|
||||||
|
18M │ │ ├── dust-2bdf724d4a721d31 │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 3%
|
||||||
|
18M │ │ ├── libsyn-9ad95b745845d5dd.rlib │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 3%
|
||||||
|
23M │ │ ├── libclap-0dedc35af3ef0670.rlib │ ░░░░▒▒▒▒▒▒▒▒▒▒█ │ 3%
|
||||||
|
267M │ ├─┴ deps │ ░░░░███████████ │ 40%
|
||||||
|
392M ├─┴ debug │ ███████████████ │ 59%
|
||||||
|
667M ┌─┴ target │█████████████████████████ │ 100%
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# ----------- To do a release ---------
|
||||||
|
# tag a commit and push:
|
||||||
|
# git tag v0.4.5
|
||||||
|
# git push origin v0.4.5
|
||||||
|
|
||||||
|
# cargo publish to put it in crates.io
|
||||||
+187
-73
@@ -4,34 +4,32 @@ use self::ansi_term::Colour::Fixed;
|
|||||||
use self::ansi_term::Style;
|
use self::ansi_term::Style;
|
||||||
use crate::utils::Node;
|
use crate::utils::Node;
|
||||||
|
|
||||||
|
use terminal_size::{terminal_size, Height, Width};
|
||||||
|
|
||||||
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
|
use std::cmp::max;
|
||||||
|
use std::cmp::min;
|
||||||
|
use std::iter::repeat;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
static UNITS: [char; 4] = ['T', 'G', 'M', 'K'];
|
static UNITS: [char; 4] = ['T', 'G', 'M', 'K'];
|
||||||
|
static BLOCKS: [char; 5] = ['█', '▓', '▒', '░', ' '];
|
||||||
|
static DEFAULT_TERMINAL_WIDTH: u16 = 80;
|
||||||
|
|
||||||
pub struct DisplayData {
|
pub struct DisplayData {
|
||||||
pub short_paths: bool,
|
pub short_paths: bool,
|
||||||
pub is_reversed: bool,
|
pub is_reversed: bool,
|
||||||
pub colors_on: bool,
|
pub colors_on: bool,
|
||||||
|
pub base_size: u64,
|
||||||
|
pub longest_string_length: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayData {
|
impl DisplayData {
|
||||||
fn get_first_chars(&self) -> &str {
|
|
||||||
if self.is_reversed {
|
|
||||||
"─┴"
|
|
||||||
} else {
|
|
||||||
"─┬"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::collapsible_if)]
|
#[allow(clippy::collapsible_if)]
|
||||||
fn get_tree_chars(
|
fn get_tree_chars(&self, was_i_last: bool, has_children: bool) -> &'static str {
|
||||||
&self,
|
|
||||||
num_siblings: u64,
|
|
||||||
max_siblings: u64,
|
|
||||||
has_children: bool,
|
|
||||||
) -> &'static str {
|
|
||||||
if self.is_reversed {
|
if self.is_reversed {
|
||||||
if num_siblings == max_siblings - 1 {
|
if was_i_last {
|
||||||
if has_children {
|
if has_children {
|
||||||
"┌─┴"
|
"┌─┴"
|
||||||
} else {
|
} else {
|
||||||
@@ -43,7 +41,7 @@ impl DisplayData {
|
|||||||
"├──"
|
"├──"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if num_siblings == 0 {
|
if was_i_last {
|
||||||
if has_children {
|
if has_children {
|
||||||
"└─┬"
|
"└─┬"
|
||||||
} else {
|
} else {
|
||||||
@@ -57,22 +55,82 @@ impl DisplayData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_biggest(&self, num_siblings: u64, max_siblings: u64) -> bool {
|
fn is_biggest(&self, num_siblings: usize, max_siblings: u64) -> bool {
|
||||||
if self.is_reversed {
|
if self.is_reversed {
|
||||||
num_siblings == 0
|
num_siblings == (max_siblings - 1) as usize
|
||||||
} else {
|
} else {
|
||||||
num_siblings == max_siblings - 1
|
num_siblings == 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_children_from_node(&self, node: Node) -> impl Iterator<Item = Node> {
|
fn is_last(&self, num_siblings: usize, max_siblings: u64) -> bool {
|
||||||
if self.is_reversed {
|
if self.is_reversed {
|
||||||
let n: Vec<Node> = node.children.into_iter().rev().map(|a| a).collect();
|
num_siblings == 0
|
||||||
n.into_iter()
|
|
||||||
} else {
|
} else {
|
||||||
node.children.into_iter()
|
num_siblings == (max_siblings - 1) as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn percent_size(&self, node: &Node) -> f32 {
|
||||||
|
let result = node.size as f32 / self.base_size as f32;
|
||||||
|
if result.is_normal() {
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_children_from_node(node: Node, is_reversed: bool) -> impl Iterator<Item = Node> {
|
||||||
|
if is_reversed {
|
||||||
|
let n: Vec<Node> = node.children.into_iter().rev().map(|a| a).collect();
|
||||||
|
n.into_iter()
|
||||||
|
} else {
|
||||||
|
node.children.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DrawData<'a> {
|
||||||
|
indent: String,
|
||||||
|
percent_bar: String,
|
||||||
|
display_data: &'a DisplayData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DrawData<'_> {
|
||||||
|
fn get_new_indent(&self, has_children: bool, was_i_last: bool) -> String {
|
||||||
|
let chars = self.display_data.get_tree_chars(was_i_last, has_children);
|
||||||
|
self.indent.to_string() + chars
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_bar(&self, node: &Node, level: usize) -> String {
|
||||||
|
let chars_in_bar = self.percent_bar.chars().count();
|
||||||
|
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 new_bar = "".to_string();
|
||||||
|
let idx = 5 - min(5, max(1, level));
|
||||||
|
|
||||||
|
for c in self.percent_bar.chars() {
|
||||||
|
num_not_my_bar -= 1;
|
||||||
|
if num_not_my_bar <= 0 {
|
||||||
|
new_bar.push(BLOCKS[0]);
|
||||||
|
} else if c == BLOCKS[0] {
|
||||||
|
new_bar.push(BLOCKS[idx]);
|
||||||
|
} else {
|
||||||
|
new_bar.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_width_of_terminal() -> u16 {
|
||||||
|
// Windows CI runners detect a very low terminal width
|
||||||
|
if let Some((Width(w), Height(_h))) = terminal_size() {
|
||||||
|
max(w, DEFAULT_TERMINAL_WIDTH)
|
||||||
|
} else {
|
||||||
|
DEFAULT_TERMINAL_WIDTH
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_it(
|
pub fn draw_it(
|
||||||
@@ -80,44 +138,91 @@ pub fn draw_it(
|
|||||||
use_full_path: bool,
|
use_full_path: bool,
|
||||||
is_reversed: bool,
|
is_reversed: bool,
|
||||||
no_colors: bool,
|
no_colors: bool,
|
||||||
|
no_percents: bool,
|
||||||
root_node: Node,
|
root_node: Node,
|
||||||
) {
|
) {
|
||||||
if !permissions {
|
if !permissions {
|
||||||
eprintln!("Did not have permissions for all directories");
|
eprintln!("Did not have permissions for all directories");
|
||||||
}
|
}
|
||||||
let display_data = DisplayData {
|
let longest_string_length = root_node
|
||||||
short_paths: !use_full_path,
|
.children
|
||||||
is_reversed,
|
.iter()
|
||||||
colors_on: !no_colors,
|
.map(|c| find_longest_dir_name(&c, " ", !use_full_path))
|
||||||
|
.fold(0, max);
|
||||||
|
let terminal_width = get_width_of_terminal() - 16;
|
||||||
|
|
||||||
|
let max_bar_length = if no_percents || longest_string_length >= terminal_width as usize {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
terminal_width as usize - longest_string_length
|
||||||
};
|
};
|
||||||
|
|
||||||
for c in display_data.get_children_from_node(root_node) {
|
// handle usize error also add do not show fancy output option
|
||||||
let first_tree_chars = display_data.get_first_chars();
|
let bar_text = repeat(BLOCKS[0]).take(max_bar_length).collect::<String>();
|
||||||
display_node(c, true, first_tree_chars, &display_data)
|
|
||||||
|
for c in get_children_from_node(root_node, is_reversed) {
|
||||||
|
let display_data = DisplayData {
|
||||||
|
short_paths: !use_full_path,
|
||||||
|
is_reversed,
|
||||||
|
colors_on: !no_colors,
|
||||||
|
base_size: c.size,
|
||||||
|
longest_string_length,
|
||||||
|
};
|
||||||
|
let draw_data = DrawData {
|
||||||
|
indent: "".to_string(),
|
||||||
|
percent_bar: bar_text.clone(),
|
||||||
|
display_data: &display_data,
|
||||||
|
};
|
||||||
|
display_node(c, &draw_data, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_node(node: Node, is_biggest: bool, indent: &str, display_data: &DisplayData) {
|
// We can probably pass depth instead of indent here.
|
||||||
let mut num_siblings = node.children.len() as u64;
|
// It is ugly to feed in ' ' instead of the actual tree characters but we don't need them yet.
|
||||||
let max_sibling = num_siblings;
|
fn find_longest_dir_name(node: &Node, indent: &str, long_paths: bool) -> usize {
|
||||||
let new_indent = clean_indentation_string(indent);
|
let longest = UnicodeWidthStr::width(&*get_printable_name(&node.name, long_paths, indent));
|
||||||
let name = node.name.clone();
|
|
||||||
let size = node.size;
|
|
||||||
|
|
||||||
if !display_data.is_reversed {
|
// each none root tree drawing is 2 chars
|
||||||
print_this_node(&name, size, is_biggest, display_data, indent);
|
let full_indent: String = indent.to_string() + " ";
|
||||||
|
node.children
|
||||||
|
.iter()
|
||||||
|
.map(|c| find_longest_dir_name(c, &*full_indent, long_paths))
|
||||||
|
.fold(longest, max)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_node(node: Node, draw_data: &DrawData, is_biggest: bool, is_last: bool) {
|
||||||
|
let indent2 = draw_data.get_new_indent(!node.children.is_empty(), is_last);
|
||||||
|
// hacky way of working out how deep we are in the tree
|
||||||
|
let level = ((indent2.chars().count() - 1) / 2) - 1;
|
||||||
|
let bar_text = draw_data.generate_bar(&node, level);
|
||||||
|
|
||||||
|
let to_print = format_string(
|
||||||
|
&node,
|
||||||
|
&*indent2,
|
||||||
|
&*bar_text,
|
||||||
|
is_biggest,
|
||||||
|
draw_data.display_data,
|
||||||
|
);
|
||||||
|
|
||||||
|
if !draw_data.display_data.is_reversed {
|
||||||
|
println!("{}", to_print)
|
||||||
}
|
}
|
||||||
|
|
||||||
for c in display_data.get_children_from_node(node) {
|
let dd = DrawData {
|
||||||
num_siblings -= 1;
|
indent: clean_indentation_string(&*indent2),
|
||||||
let chars = display_data.get_tree_chars(num_siblings, max_sibling, !c.children.is_empty());
|
percent_bar: bar_text,
|
||||||
let is_biggest = display_data.is_biggest(num_siblings, max_sibling);
|
display_data: draw_data.display_data,
|
||||||
let full_indent = new_indent.clone() + chars;
|
};
|
||||||
display_node(c, is_biggest, &*full_indent, display_data)
|
let num_siblings = node.children.len() as u64;
|
||||||
|
|
||||||
|
for (count, c) in get_children_from_node(node, draw_data.display_data.is_reversed).enumerate() {
|
||||||
|
let is_biggest = dd.display_data.is_biggest(count, num_siblings);
|
||||||
|
let was_i_last = dd.display_data.is_last(count, num_siblings);
|
||||||
|
display_node(c, &dd, is_biggest, was_i_last);
|
||||||
}
|
}
|
||||||
|
|
||||||
if display_data.is_reversed {
|
if draw_data.display_data.is_reversed {
|
||||||
print_this_node(&name, size, is_biggest, display_data, indent);
|
println!("{}", to_print)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,30 +243,10 @@ fn clean_indentation_string(s: &str) -> String {
|
|||||||
is
|
is
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_this_node<P: AsRef<Path>>(
|
fn get_printable_name<P: AsRef<Path>>(dir_name: &P, long_paths: bool, indentation: &str) -> String {
|
||||||
name: P,
|
|
||||||
size: u64,
|
|
||||||
is_biggest: bool,
|
|
||||||
display_data: &DisplayData,
|
|
||||||
indentation: &str,
|
|
||||||
) {
|
|
||||||
let pretty_size = format!("{:>5}", human_readable_number(size),);
|
|
||||||
println!(
|
|
||||||
"{}",
|
|
||||||
format_string(name, is_biggest, display_data, &*pretty_size, indentation)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn format_string<P: AsRef<Path>>(
|
|
||||||
dir_name: P,
|
|
||||||
is_biggest: bool,
|
|
||||||
display_data: &DisplayData,
|
|
||||||
size: &str,
|
|
||||||
indentation: &str,
|
|
||||||
) -> String {
|
|
||||||
let dir_name = dir_name.as_ref();
|
let dir_name = dir_name.as_ref();
|
||||||
let printable_name = {
|
let printable_name = {
|
||||||
if display_data.short_paths {
|
if long_paths {
|
||||||
match dir_name.parent() {
|
match dir_name.parent() {
|
||||||
Some(prefix) => match dir_name.strip_prefix(prefix) {
|
Some(prefix) => match dir_name.strip_prefix(prefix) {
|
||||||
Ok(base) => base,
|
Ok(base) => base,
|
||||||
@@ -173,15 +258,44 @@ pub fn format_string<P: AsRef<Path>>(
|
|||||||
dir_name
|
dir_name
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
format!("{} {}", indentation, printable_name.display())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format_string(
|
||||||
|
node: &Node,
|
||||||
|
indent: &str,
|
||||||
|
percent_bar: &str,
|
||||||
|
is_biggest: bool,
|
||||||
|
display_data: &DisplayData,
|
||||||
|
) -> String {
|
||||||
|
let pretty_size = format!("{:>5}", human_readable_number(node.size));
|
||||||
|
|
||||||
|
let percent_size = display_data.percent_size(node);
|
||||||
|
let percent_size_str = format!("{:.0}%", percent_size * 100.0);
|
||||||
|
|
||||||
|
let tree_and_path = get_printable_name(&node.name, display_data.short_paths, &*indent);
|
||||||
|
|
||||||
|
let printable_chars = UnicodeWidthStr::width(&*tree_and_path);
|
||||||
|
let tree_and_path = tree_and_path
|
||||||
|
+ &(repeat(" ")
|
||||||
|
.take(display_data.longest_string_length - printable_chars)
|
||||||
|
.collect::<String>());
|
||||||
|
|
||||||
|
let percents = if percent_bar != "" {
|
||||||
|
format!("│{} │ {:>4}", percent_bar, percent_size_str)
|
||||||
|
} else {
|
||||||
|
"".into()
|
||||||
|
};
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"{} {} {}",
|
"{} {}{}",
|
||||||
if is_biggest && display_data.colors_on {
|
if is_biggest && display_data.colors_on {
|
||||||
Fixed(196).paint(size)
|
Fixed(196).paint(pretty_size)
|
||||||
} else {
|
} else {
|
||||||
Style::new().paint(size)
|
Style::new().paint(pretty_size)
|
||||||
},
|
},
|
||||||
indentation,
|
tree_and_path,
|
||||||
printable_name.display(),
|
percents,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+28
-9
@@ -1,16 +1,19 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
|
extern crate unicode_width;
|
||||||
|
|
||||||
use self::display::draw_it;
|
use self::display::draw_it;
|
||||||
use crate::utils::is_a_parent_of;
|
use crate::utils::is_a_parent_of;
|
||||||
use clap::{App, AppSettings, Arg};
|
use clap::{App, AppSettings, Arg};
|
||||||
|
use std::cmp::max;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use terminal_size::{terminal_size, Height, Width};
|
||||||
use utils::{find_big_ones, get_dir_tree, simplify_dir_names, sort, trim_deep_ones, Node};
|
use utils::{find_big_ones, get_dir_tree, simplify_dir_names, sort, trim_deep_ones, Node};
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
static DEFAULT_NUMBER_OF_LINES: usize = 20;
|
static DEFAULT_NUMBER_OF_LINES: usize = 30;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn init_color() {
|
fn init_color() {
|
||||||
@@ -20,9 +23,21 @@ fn init_color() {
|
|||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
fn init_color() {}
|
fn init_color() {}
|
||||||
|
|
||||||
|
fn get_height_of_terminal() -> usize {
|
||||||
|
// Windows CI runners detect a terminal height of 0
|
||||||
|
if let Some((Width(_w), Height(h))) = terminal_size() {
|
||||||
|
max(h as usize, DEFAULT_NUMBER_OF_LINES) - 10
|
||||||
|
} else {
|
||||||
|
DEFAULT_NUMBER_OF_LINES - 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
init_color();
|
init_color();
|
||||||
let def_num_str = DEFAULT_NUMBER_OF_LINES.to_string();
|
|
||||||
|
let default_height = get_height_of_terminal();
|
||||||
|
let def_num_str = default_height.to_string();
|
||||||
|
|
||||||
let options = App::new("Dust")
|
let options = App::new("Dust")
|
||||||
.about("Like du but more intuitive")
|
.about("Like du but more intuitive")
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
@@ -80,7 +95,7 @@ fn main() {
|
|||||||
Arg::with_name("reverse")
|
Arg::with_name("reverse")
|
||||||
.short("r")
|
.short("r")
|
||||||
.long("reverse")
|
.long("reverse")
|
||||||
.help("If applied tree will be printed upside down (biggest lowest)"),
|
.help("If applied tree will be printed upside down (biggest highest)"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("no_colors")
|
Arg::with_name("no_colors")
|
||||||
@@ -88,6 +103,12 @@ fn main() {
|
|||||||
.long("no_colors")
|
.long("no_colors")
|
||||||
.help("If applied no colors will be printed (normally largest directories are marked in red"),
|
.help("If applied no colors will be printed (normally largest directories are marked in red"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("no_bars")
|
||||||
|
.short("b")
|
||||||
|
.long("no_percent_bars")
|
||||||
|
.help("If applied no percent bars or percents will be displayed"),
|
||||||
|
)
|
||||||
.arg(Arg::with_name("inputs").multiple(true))
|
.arg(Arg::with_name("inputs").multiple(true))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
@@ -102,7 +123,7 @@ fn main() {
|
|||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
eprintln!("Ignoring bad value for number_of_lines");
|
eprintln!("Ignoring bad value for number_of_lines");
|
||||||
DEFAULT_NUMBER_OF_LINES
|
default_height
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -131,7 +152,7 @@ fn main() {
|
|||||||
.map_err(|_| eprintln!("Ignoring bad value for depth"))
|
.map_err(|_| eprintln!("Ignoring bad value for depth"))
|
||||||
.ok()
|
.ok()
|
||||||
});
|
});
|
||||||
if options.is_present("depth") && number_of_lines != DEFAULT_NUMBER_OF_LINES {
|
if options.is_present("depth") && number_of_lines != default_height {
|
||||||
eprintln!("Use either -n or -d. Not both");
|
eprintln!("Use either -n or -d. Not both");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -163,8 +184,9 @@ fn main() {
|
|||||||
draw_it(
|
draw_it(
|
||||||
permissions,
|
permissions,
|
||||||
options.is_present("display_full_paths"),
|
options.is_present("display_full_paths"),
|
||||||
options.is_present("reverse"),
|
!options.is_present("reverse"),
|
||||||
options.is_present("no_colors"),
|
options.is_present("no_colors"),
|
||||||
|
options.is_present("no_bars"),
|
||||||
tree,
|
tree,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -200,6 +222,3 @@ fn recursively_build_tree(parent_node: &mut Node, new_node: Node, depth: Option<
|
|||||||
parent_node.children.push(new_node);
|
parent_node.children.push(new_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests;
|
|
||||||
|
|||||||
-412
@@ -1,412 +0,0 @@
|
|||||||
use super::*;
|
|
||||||
|
|
||||||
use crate::display::DisplayData;
|
|
||||||
use display::format_string;
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::panic;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::process::Command;
|
|
||||||
use tempfile::Builder;
|
|
||||||
use tempfile::TempDir;
|
|
||||||
|
|
||||||
// fix! [rivy; 2020-22-01] "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() {
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["src/test_dir"])
|
|
||||||
.stdout()
|
|
||||||
.is(main_output(true).as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix! [rivy; 2020-22-01] "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_long_paths() {
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-p", "src/test_dir"])
|
|
||||||
.stdout()
|
|
||||||
.is(main_output(false).as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix! [rivy; 2020-22-01] "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_multi_arg() {
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["src/test_dir/many/", "src/test_dir/", "src/test_dir"])
|
|
||||||
.stdout()
|
|
||||||
.is(main_output(true).as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
fn main_output(short_paths: bool) -> String {
|
|
||||||
let d = DisplayData {
|
|
||||||
short_paths,
|
|
||||||
is_reversed: false,
|
|
||||||
colors_on: true,
|
|
||||||
};
|
|
||||||
format!(
|
|
||||||
"{}
|
|
||||||
{}
|
|
||||||
{}
|
|
||||||
{}",
|
|
||||||
format_string("src/test_dir", true, &d, " 4.0K", "─┬"),
|
|
||||||
format_string("src/test_dir/many", true, &d, " 4.0K", " └─┬",),
|
|
||||||
format_string("src/test_dir/many/hello_file", true, &d, " 4.0K", " ├──",),
|
|
||||||
format_string("src/test_dir/many/a_file", false, &d, " 0B", " └──",),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn main_output(short_paths: bool) -> String {
|
|
||||||
let d = DisplayData {
|
|
||||||
short_paths,
|
|
||||||
is_reversed: false,
|
|
||||||
colors_on: true,
|
|
||||||
};
|
|
||||||
format!(
|
|
||||||
"{}
|
|
||||||
{}
|
|
||||||
{}
|
|
||||||
{}",
|
|
||||||
format_string("src/test_dir", true, &d, " 12K", "─┬"),
|
|
||||||
format_string("src/test_dir/many", true, &d, " 8.0K", " └─┬",),
|
|
||||||
format_string("src/test_dir/many/hello_file", true, &d, " 4.0K", " ├──",),
|
|
||||||
format_string("src/test_dir/many/a_file", false, &d, " 0B", " └──",),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn main_output(short_paths: bool) -> String {
|
|
||||||
let d = DisplayData {
|
|
||||||
short_paths,
|
|
||||||
is_reversed: false,
|
|
||||||
colors_on: true,
|
|
||||||
};
|
|
||||||
format!(
|
|
||||||
"{}
|
|
||||||
{}
|
|
||||||
{}
|
|
||||||
{}",
|
|
||||||
format_string("src/test_dir", true, &d, " 6B", "─┬"),
|
|
||||||
format_string("src/test_dir\\many", true, &d, " 6B", " └─┬",),
|
|
||||||
format_string(
|
|
||||||
"src/test_dir\\many\\hello_file",
|
|
||||||
true,
|
|
||||||
&d,
|
|
||||||
" 6B",
|
|
||||||
" ├──",
|
|
||||||
),
|
|
||||||
format_string("src/test_dir\\many\\a_file", false, &d, " 0B", " └──",),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix! [rivy; 2020-22-01] "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_no_color_flag() {
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-c", "src/test_dir/"])
|
|
||||||
.stdout()
|
|
||||||
.is(no_color_flag_output().as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
fn no_color_flag_output() -> String {
|
|
||||||
"
|
|
||||||
4.0K ─┬ test_dir
|
|
||||||
4.0K └─┬ many
|
|
||||||
4.0K ├── hello_file
|
|
||||||
0B └── a_file
|
|
||||||
"
|
|
||||||
.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn no_color_flag_output() -> String {
|
|
||||||
"
|
|
||||||
12K ─┬ test_dir
|
|
||||||
8.0K └─┬ many
|
|
||||||
4.0K ├── hello_file
|
|
||||||
0B └── a_file
|
|
||||||
"
|
|
||||||
.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn no_color_flag_output() -> String {
|
|
||||||
"
|
|
||||||
6B ─┬ test_dir
|
|
||||||
6B └─┬ many
|
|
||||||
6B ├── hello_file
|
|
||||||
0B └── a_file
|
|
||||||
"
|
|
||||||
.to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix! [rivy; 2020-22-01] "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_apparent_size() {
|
|
||||||
let d = DisplayData {
|
|
||||||
short_paths: true,
|
|
||||||
is_reversed: false,
|
|
||||||
colors_on: true,
|
|
||||||
};
|
|
||||||
let r = format!(
|
|
||||||
"{}",
|
|
||||||
format_string("src/test_dir/many/hello_file", true, &d, " 6B", " ├──",),
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-s", "src/test_dir"])
|
|
||||||
.stdout()
|
|
||||||
.contains(r.as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_reverse_flag() {
|
|
||||||
// variable names the same length make the output easier to read
|
|
||||||
let a = " ┌── a_file";
|
|
||||||
let b = " ├── hello_file";
|
|
||||||
let c = " ┌─┴ many";
|
|
||||||
let d = " ─┴ test_dir";
|
|
||||||
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-r", "src/test_dir"])
|
|
||||||
.stdout()
|
|
||||||
.contains(a)
|
|
||||||
.stdout()
|
|
||||||
.contains(b)
|
|
||||||
.stdout()
|
|
||||||
.contains(c)
|
|
||||||
.stdout()
|
|
||||||
.contains(d)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_d_flag_works() {
|
|
||||||
// We should see the top level directory but not the sub dirs / files:
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-d", "1", "-s", "src/test_dir"])
|
|
||||||
.stdout()
|
|
||||||
.doesnt_contain("hello_file")
|
|
||||||
.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
|
|
||||||
}
|
|
||||||
|
|
||||||
// fix! [rivy; 2020-01-22] possible on "windows"?; `ln` is not usually an available command; creation of symbolic links requires special enhanced permissions
|
|
||||||
// ... ref: <https://superuser.com/questions/343074/directory-junction-vs-directory-symbolic-link> @@ <https://archive.is/gpTLE>
|
|
||||||
#[cfg_attr(target_os = "windows", ignore)]
|
|
||||||
#[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 a = format!(" ─┬ {}", dir_s);
|
|
||||||
let b = format!(" ├── {}", file_path_s);
|
|
||||||
let c = format!(" └── {}", link_name_s);
|
|
||||||
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-p", &dir_s])
|
|
||||||
.stdout()
|
|
||||||
.contains(a.as_str())
|
|
||||||
.stdout()
|
|
||||||
.contains(b.as_str())
|
|
||||||
.stdout()
|
|
||||||
.contains(c.as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hard links are ignored as the inode is the same as the file
|
|
||||||
// fix! [rivy; 2020-01-22] may fail on "usual" windows hosts as `ln` is not usually an available command
|
|
||||||
#[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 a = format!(" ─┬ {}", dir_s);
|
|
||||||
let b = format!(" └── {}", link_name_s);
|
|
||||||
let b2 = format!(" └── {}", file_path_s);
|
|
||||||
|
|
||||||
// Because this is a hard link the file and hard link look identical. Therefore
|
|
||||||
// we cannot guarantee which version will appear first.
|
|
||||||
let result = panic::catch_unwind(|| {
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-p", dir_s])
|
|
||||||
.stdout()
|
|
||||||
.contains(a.as_str())
|
|
||||||
.stdout()
|
|
||||||
.contains(b.as_str())
|
|
||||||
.unwrap();
|
|
||||||
});
|
|
||||||
if result.is_err() {
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-p", dir_s])
|
|
||||||
.stdout()
|
|
||||||
.contains(a.as_str())
|
|
||||||
.stdout()
|
|
||||||
.contains(b2.as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check we don't recurse down an infinite symlink tree
|
|
||||||
// fix! [rivy; 2020-01-22] possible on "windows"?; `ln` is not usually an available command; creation of symbolic links requires special enhanced permissions
|
|
||||||
// ... ref: <https://superuser.com/questions/343074/directory-junction-vs-directory-symbolic-link> @@ <https://archive.is/gpTLE>
|
|
||||||
#[cfg_attr(target_os = "windows", ignore)]
|
|
||||||
#[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("ln")
|
|
||||||
.arg("-s")
|
|
||||||
.arg(dir_s)
|
|
||||||
.arg(link_name_s)
|
|
||||||
.output();
|
|
||||||
assert!(c.is_ok());
|
|
||||||
|
|
||||||
let a = format!(" ─┬ {}", dir_s);
|
|
||||||
let b = format!(" └── {}", link_name_s);
|
|
||||||
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-p", dir_s])
|
|
||||||
.stdout()
|
|
||||||
.contains(a.as_str())
|
|
||||||
.stdout()
|
|
||||||
.contains(b.as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check against directories and files whos names are substrings of each other
|
|
||||||
// fix! [rivy; 2020-22-01] "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_substring_of_names() {
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-c", "src/test_dir2"])
|
|
||||||
.stdout()
|
|
||||||
.is(no_substring_of_names_output().as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn no_substring_of_names_output() -> String {
|
|
||||||
"
|
|
||||||
24K ─┬ test_dir2
|
|
||||||
8.0K ├─┬ dir
|
|
||||||
4.0K │ └── hello
|
|
||||||
8.0K ├─┬ dir_substring
|
|
||||||
4.0K │ └── hello
|
|
||||||
4.0K └── dir_name_clash
|
|
||||||
"
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
fn no_substring_of_names_output() -> String {
|
|
||||||
"
|
|
||||||
12K ─┬ test_dir2
|
|
||||||
4.0K ├─┬ dir
|
|
||||||
4.0K │ └── hello
|
|
||||||
4.0K ├── dir_name_clash
|
|
||||||
4.0K └─┬ dir_substring
|
|
||||||
4.0K └── hello
|
|
||||||
"
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn no_substring_of_names_output() -> String {
|
|
||||||
"
|
|
||||||
16B ─┬ test_dir2
|
|
||||||
6B ├─┬ dir_substring
|
|
||||||
6B │ └── hello
|
|
||||||
5B ├─┬ dir
|
|
||||||
5B │ └── hello
|
|
||||||
5B └── dir_name_clash
|
|
||||||
"
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check against directories and files whos names are substrings of each other
|
|
||||||
#[test]
|
|
||||||
pub fn test_ignore_dir() {
|
|
||||||
assert_cli::Assert::main_binary()
|
|
||||||
.with_args(&["-c", "-X", "dir_substring", "src/test_dir2"])
|
|
||||||
.stdout()
|
|
||||||
.is(ignore_dir_output().as_str())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
fn ignore_dir_output() -> String {
|
|
||||||
"
|
|
||||||
16K ─┬ test_dir2
|
|
||||||
8.0K ├─┬ dir
|
|
||||||
4.0K │ └── hello
|
|
||||||
4.0K └── dir_name_clash
|
|
||||||
"
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
fn ignore_dir_output() -> String {
|
|
||||||
"
|
|
||||||
8.0K ─┬ test_dir2
|
|
||||||
4.0K ├─┬ dir
|
|
||||||
4.0K │ └── hello
|
|
||||||
4.0K └── dir_name_clash
|
|
||||||
"
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn ignore_dir_output() -> String {
|
|
||||||
"
|
|
||||||
10B ─┬ test_dir2
|
|
||||||
5B ├─┬ dir
|
|
||||||
5B │ └── hello
|
|
||||||
5B └── dir_name_clash
|
|
||||||
"
|
|
||||||
.into()
|
|
||||||
}
|
|
||||||
+259
@@ -0,0 +1,259 @@
|
|||||||
|
mod tests_symlinks;
|
||||||
|
|
||||||
|
// File sizes differ on both platform and on the format of the disk.
|
||||||
|
// We can at least test the file names are there
|
||||||
|
#[test]
|
||||||
|
pub fn test_basic_output() {
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["src/test_dir/"])
|
||||||
|
.stdout()
|
||||||
|
.contains(" ┌─┴ test_dir ")
|
||||||
|
.stdout()
|
||||||
|
.contains(" ┌─┴ many ")
|
||||||
|
.stdout()
|
||||||
|
.contains(" ├── hello_file")
|
||||||
|
.stdout()
|
||||||
|
.contains(" ┌── a_file ")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix! [rivy; 2020-22-01] "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
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-c", "src/test_dir"])
|
||||||
|
.stdout()
|
||||||
|
.is(main_output().as_str())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix! [rivy; 2020-22-01] "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_multi_arg() {
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-c", "src/test_dir/many/", "src/test_dir/", "src/test_dir"])
|
||||||
|
.stdout()
|
||||||
|
.is(main_output().as_str())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn main_output() -> String {
|
||||||
|
r#"
|
||||||
|
0B ┌── a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||||
|
4.0K ├── hello_file│██████████████████████████████████████████████ │ 100%
|
||||||
|
4.0K ┌─┴ many │██████████████████████████████████████████████ │ 100%
|
||||||
|
4.0K ┌─┴ test_dir │██████████████████████████████████████████████ │ 100%
|
||||||
|
"#
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn main_output() -> String {
|
||||||
|
r#"
|
||||||
|
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||||
|
4.0K ├── hello_file│ ░░░░░░░░░░░░░░░████████████████ │ 33%
|
||||||
|
8.0K ┌─┴ many │ ███████████████████████████████ │ 67%
|
||||||
|
12K ┌─┴ test_dir │██████████████████████████████████████████████ │ 100%
|
||||||
|
"#
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn main_output() -> String {
|
||||||
|
"PRs welcome".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix! [rivy; 2020-22-01] "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_long_paths() {
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-c", "-p", "src/test_dir"])
|
||||||
|
.stdout()
|
||||||
|
.is(main_output_long_paths().as_str())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn main_output_long_paths() -> String {
|
||||||
|
r#"
|
||||||
|
0B ┌── src/test_dir/many/a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||||
|
4.0K ├── src/test_dir/many/hello_file│████████████████████████████ │ 100%
|
||||||
|
4.0K ┌─┴ src/test_dir/many │████████████████████████████ │ 100%
|
||||||
|
4.0K ┌─┴ src/test_dir │████████████████████████████ │ 100%
|
||||||
|
"#
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn main_output_long_paths() -> String {
|
||||||
|
r#"
|
||||||
|
0B ┌── src/test_dir/many/a_file │ ░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||||
|
4.0K ├── src/test_dir/many/hello_file│ ░░░░░░░░░██████████ │ 33%
|
||||||
|
8.0K ┌─┴ src/test_dir/many │ ███████████████████ │ 67%
|
||||||
|
12K ┌─┴ src/test_dir │████████████████████████████ │ 100%
|
||||||
|
"#
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn main_output_long_paths() -> String {
|
||||||
|
"PRs welcome".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix! [rivy; 2020-22-01] "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_apparent_size() {
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-c", "-s", "src/test_dir"])
|
||||||
|
.stdout()
|
||||||
|
.is(output_apparent_size().as_str())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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%
|
||||||
|
"#
|
||||||
|
.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%
|
||||||
|
"#
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn output_apparent_size() -> String {
|
||||||
|
"".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_reverse_flag() {
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-c", "-r", "src/test_dir/"])
|
||||||
|
.stdout()
|
||||||
|
.contains(" └─┬ test_dir ")
|
||||||
|
.stdout()
|
||||||
|
.contains(" └─┬ many ")
|
||||||
|
.stdout()
|
||||||
|
.contains(" ├── hello_file")
|
||||||
|
.stdout()
|
||||||
|
.contains(" └── a_file ")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_d_flag_works() {
|
||||||
|
// We should see the top level directory but not the sub dirs / files:
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-d", "1", "-s", "src/test_dir"])
|
||||||
|
.stdout()
|
||||||
|
.doesnt_contain("hello_file")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check against directories and files whos names are substrings of each other
|
||||||
|
// fix! [rivy; 2020-22-01] "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_substring_of_names() {
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-c", "src/test_dir2"])
|
||||||
|
.stdout()
|
||||||
|
.is(no_substring_of_names_output().as_str())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn no_substring_of_names_output() -> String {
|
||||||
|
"
|
||||||
|
4.0K ┌── dir_name_clash│ ████████ │ 17%
|
||||||
|
4.0K │ ┌── hello │ ░░░░░░░████████ │ 17%
|
||||||
|
8.0K ├─┴ dir_substring │ ███████████████ │ 33%
|
||||||
|
4.0K │ ┌── hello │ ░░░░░░░████████ │ 17%
|
||||||
|
8.0K ├─┴ dir │ ███████████████ │ 33%
|
||||||
|
24K ┌─┴ test_dir2 │████████████████████████████████████████████ │ 100%
|
||||||
|
"
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn no_substring_of_names_output() -> String {
|
||||||
|
"
|
||||||
|
4.0K ┌── hello │ ███████████████ │ 33%
|
||||||
|
4.0K ┌─┴ dir_substring │ ███████████████ │ 33%
|
||||||
|
4.0K ├── dir_name_clash│ ███████████████ │ 33%
|
||||||
|
4.0K │ ┌── hello │ ███████████████ │ 33%
|
||||||
|
4.0K ├─┴ dir │ ███████████████ │ 33%
|
||||||
|
12K ┌─┴ test_dir2 │████████████████████████████████████████████ │ 100%
|
||||||
|
"
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn no_substring_of_names_output() -> String {
|
||||||
|
"PRs".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix! [rivy; 2020-22-01] "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_unicode_directories() {
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-c", "src/test_dir3"])
|
||||||
|
.stdout()
|
||||||
|
.is(unicode_dir().as_str())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn unicode_dir() -> String {
|
||||||
|
// The way unicode & asian characters are rendered on the terminal should make this line up
|
||||||
|
"
|
||||||
|
0B ┌── 👩.unicode │ █ │ 0%
|
||||||
|
0B ├── ラウトは難しいです!.japan│ █ │ 0%
|
||||||
|
4.0K ┌─┴ test_dir3 │████████████████████████████████ │ 100%
|
||||||
|
"
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn unicode_dir() -> String {
|
||||||
|
"
|
||||||
|
0B ┌── 👩.unicode │ █ │ 0%
|
||||||
|
0B ├── ラウトは難しいです!.japan│ █ │ 0%
|
||||||
|
0B ┌─┴ test_dir3 │ █ │ 0%
|
||||||
|
"
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn unicode_dir() -> String {
|
||||||
|
"".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check against directories and files whos names are substrings of each other
|
||||||
|
#[test]
|
||||||
|
pub fn test_ignore_dir() {
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-c", "-X", "dir_substring", "src/test_dir2"])
|
||||||
|
.stdout()
|
||||||
|
.doesnt_contain("dir_substring")
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::panic;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
use tempfile::Builder;
|
||||||
|
use tempfile::TempDir;
|
||||||
|
|
||||||
|
// File sizes differ on both platform and on the format of the disk.
|
||||||
|
// Windows: `ln` is not usually an available command; creation of symbolic links requires special enhanced permissions
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
|
#[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 c = format!(" ┌── {}", link_name_s);
|
||||||
|
let b = format!(" ├── {}", file_path_s);
|
||||||
|
let a = format!("─┴ {}", dir_s);
|
||||||
|
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-p", &dir_s])
|
||||||
|
.stdout()
|
||||||
|
.contains(a.as_str())
|
||||||
|
.stdout()
|
||||||
|
.contains(b.as_str())
|
||||||
|
.stdout()
|
||||||
|
.contains(c.as_str())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
|
#[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 a = format!("─┴ {}", dir_s);
|
||||||
|
let b = format!(" ┌── {}", link_name_s);
|
||||||
|
let b2 = format!(" ┌── {}", file_path_s);
|
||||||
|
|
||||||
|
// Because this is a hard link the file and hard link look identical. Therefore
|
||||||
|
// we cannot guarantee which version will appear first.
|
||||||
|
let result = panic::catch_unwind(|| {
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-p", dir_s])
|
||||||
|
.stdout()
|
||||||
|
.contains(a.as_str())
|
||||||
|
.stdout()
|
||||||
|
.contains(b.as_str())
|
||||||
|
.unwrap();
|
||||||
|
});
|
||||||
|
if result.is_err() {
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-p", dir_s])
|
||||||
|
.stdout()
|
||||||
|
.contains(a.as_str())
|
||||||
|
.stdout()
|
||||||
|
.contains(b2.as_str())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
|
#[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("ln")
|
||||||
|
.arg("-s")
|
||||||
|
.arg(dir_s)
|
||||||
|
.arg(link_name_s)
|
||||||
|
.output();
|
||||||
|
assert!(c.is_ok());
|
||||||
|
|
||||||
|
let a = format!("─┬ {}", dir_s);
|
||||||
|
let b = format!(" └── {}", link_name_s);
|
||||||
|
|
||||||
|
assert_cli::Assert::main_binary()
|
||||||
|
.with_args(&["-r", "-p", dir_s])
|
||||||
|
.stdout()
|
||||||
|
.contains(a.as_str())
|
||||||
|
.stdout()
|
||||||
|
.contains(b.as_str())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user