mirror of
https://github.com/bootandy/dust.git
synced 2026-06-08 11:29:05 +03:00
Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 53af0d486d | |||
| b643abe05e | |||
| 695c9b6747 | |||
| 8e8f18b9bc | |||
| e767be217a | |||
| 9187cb8ad2 | |||
| 873456eb97 | |||
| 4e1180e502 | |||
| 4ea8d9339e | |||
| 82237c6bde | |||
| 109df305a3 | |||
| d03a9796f4 | |||
| 8e591f3dd5 | |||
| 086f11988c | |||
| 52eca1ff78 | |||
| e80c60b027 | |||
| e118814684 | |||
| 1546cf2eba | |||
| 4f06de8044 | |||
| 2ca6fcc9ce | |||
| 278a31971c | |||
| 479e5899c6 | |||
| c4c173e40e | |||
| b8410ee4da | |||
| 0cb0396a84 | |||
| b1fe078e06 | |||
| b3d446bfef | |||
| 34be81c216 | |||
| 342164d357 | |||
| bfa3594fe8 | |||
| 1f120de168 | |||
| c0048b2ae4 | |||
| 402a8f8249 | |||
| 7cc7047b28 | |||
| 1953e107c2 | |||
| f096e82754 | |||
| c3415df4b1 | |||
| 9452049aff | |||
| 09e3c27e70 | |||
| b0bfe654c4 | |||
| 6bc44de495 | |||
| efb455c739 | |||
| 2c58041885 | |||
| c30f31c22c | |||
| 59f2cdfb84 | |||
| 795d91237d | |||
| 26ae050f16 | |||
| 58b395e7ee | |||
| 3beb2b5274 | |||
| 19d938b05e | |||
| d4daa82297 | |||
| 21097578d9 | |||
| 069dc184a9 | |||
| 02fa657128 |
@@ -32,6 +32,12 @@ jobs:
|
|||||||
case ${{ matrix.job.os }} in windows-latest) unset JOB_DO_FORMAT_TESTING ;; esac;
|
case ${{ matrix.job.os }} in windows-latest) unset JOB_DO_FORMAT_TESTING ;; esac;
|
||||||
echo set-output name=JOB_DO_FORMAT_TESTING::${JOB_DO_FORMAT_TESTING:-<empty>/false}
|
echo set-output name=JOB_DO_FORMAT_TESTING::${JOB_DO_FORMAT_TESTING:-<empty>/false}
|
||||||
echo ::set-output name=JOB_DO_FORMAT_TESTING::${JOB_DO_FORMAT_TESTING}
|
echo ::set-output name=JOB_DO_FORMAT_TESTING::${JOB_DO_FORMAT_TESTING}
|
||||||
|
# target-specific options
|
||||||
|
# * CARGO_FEATURES_OPTION
|
||||||
|
CARGO_FEATURES_OPTION='' ;
|
||||||
|
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
|
||||||
|
echo set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
|
||||||
|
echo ::set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
|
||||||
- name: Install `rust` toolchain
|
- name: Install `rust` toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
@@ -50,7 +56,7 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: clippy
|
command: clippy
|
||||||
args: ${{ matrix.job.cargo-options }} --features "${{ matrix.job.features }}" -- -D warnings
|
args: ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} -- -D warnings
|
||||||
|
|
||||||
min_version:
|
min_version:
|
||||||
name: MinSRV # Minimum supported rust version
|
name: MinSRV # Minimum supported rust version
|
||||||
@@ -149,6 +155,11 @@ jobs:
|
|||||||
echo set-output name=DEPLOY::${DEPLOY:-<empty>/false}
|
echo set-output name=DEPLOY::${DEPLOY:-<empty>/false}
|
||||||
echo ::set-output name=DEPLOY::${DEPLOY}
|
echo ::set-output name=DEPLOY::${DEPLOY}
|
||||||
# target-specific options
|
# target-specific options
|
||||||
|
# * CARGO_FEATURES_OPTION
|
||||||
|
CARGO_FEATURES_OPTION='' ;
|
||||||
|
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features "${{ matrix.job.features }}"' ; fi
|
||||||
|
echo set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
|
||||||
|
echo ::set-output name=CARGO_FEATURES_OPTION::${CARGO_FEATURES_OPTION}
|
||||||
# * CARGO_USE_CROSS (truthy)
|
# * CARGO_USE_CROSS (truthy)
|
||||||
CARGO_USE_CROSS='true' ; case '${{ matrix.job.use-cross }}' in ''|0|f|false|n|no) unset CARGO_USE_CROSS ;; esac;
|
CARGO_USE_CROSS='true' ; case '${{ matrix.job.use-cross }}' in ''|0|f|false|n|no) unset CARGO_USE_CROSS ;; esac;
|
||||||
echo set-output name=CARGO_USE_CROSS::${CARGO_USE_CROSS:-<empty>/false}
|
echo set-output name=CARGO_USE_CROSS::${CARGO_USE_CROSS:-<empty>/false}
|
||||||
@@ -193,13 +204,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
||||||
command: build
|
command: build
|
||||||
args: --release --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} --features "${{ matrix.job.features }}"
|
args: --release --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
|
||||||
- name: Test
|
- name: Test
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
||||||
command: test
|
command: test
|
||||||
args: --target=${{ matrix.job.target }} ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} --features "${{ matrix.job.features }}"
|
args: --target=${{ matrix.job.target }} ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
|
||||||
- name: Archive executable artifacts
|
- name: Archive executable artifacts
|
||||||
uses: actions/upload-artifact@master
|
uses: actions/upload-artifact@master
|
||||||
with:
|
with:
|
||||||
|
|||||||
Generated
+226
-328
@@ -1,11 +1,19 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.7.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "ansi_term"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -13,20 +21,19 @@ name = "ansi_term"
|
|||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "assert_cli"
|
name = "assert_cmd"
|
||||||
version = "0.6.3"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"predicates 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wait-timeout 0.2.0 (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]]
|
||||||
@@ -34,54 +41,29 @@ name = "atty"
|
|||||||
version = "0.2.14"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.74 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "0.1.7"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "backtrace"
|
|
||||||
version = "0.3.44"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "backtrace-sys"
|
|
||||||
version = "0.1.32"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "c2-chacha"
|
name = "bstr"
|
||||||
version = "0.2.3"
|
version = "0.2.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cc"
|
|
||||||
version = "1.0.50"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "0.1.10"
|
version = "0.1.10"
|
||||||
@@ -89,7 +71,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.33.0"
|
version = "2.33.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -97,78 +79,25 @@ dependencies = [
|
|||||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "colored"
|
|
||||||
version = "1.9.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam"
|
|
||||||
version = "0.7.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "crossbeam-channel"
|
||||||
version = "0.4.0"
|
version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-deque"
|
|
||||||
version = "0.7.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-epoch"
|
|
||||||
version = "0.8.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "crossbeam-queue"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.7.0"
|
version = "0.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@@ -178,81 +107,80 @@ name = "difference"
|
|||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "doc-comment"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "du-dust"
|
name = "du-dust"
|
||||||
version = "0.5.0"
|
version = "0.5.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"assert_cli 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"assert_cmd 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jwalk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"crossbeam-channel 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ignore 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lscolors 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"num_cpus 1.13.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)",
|
"terminal_size 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"thousands 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "fnv"
|
||||||
version = "1.5.3"
|
version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "environment"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "failure"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"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)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "failure_derive"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"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)",
|
|
||||||
"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)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.74 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "globset"
|
||||||
version = "0.1.6"
|
version = "0.4.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
"aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "hermit-abi"
|
||||||
version = "0.4.5"
|
version = "0.1.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "jwalk"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.74 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ignore"
|
||||||
|
version = "0.4.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"globset 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -262,45 +190,65 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.66"
|
version = "0.2.74"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "log"
|
||||||
version = "0.5.3"
|
version = "0.4.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "lscolors"
|
||||||
version = "1.12.0"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num_cpus"
|
||||||
|
version = "1.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.74 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.6"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "predicates"
|
||||||
version = "1.0.8"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "predicates-core"
|
||||||
version = "1.0.2"
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "predicates-tree"
|
||||||
|
version = "1.0.0"
|
||||||
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)",
|
"predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -309,18 +257,18 @@ version = "0.7.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.74 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand_chacha"
|
name = "rand_chacha"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -340,90 +288,41 @@ dependencies = [
|
|||||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rayon-core"
|
|
||||||
version = "1.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"lazy_static 1.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)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.56"
|
version = "0.1.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "1.3.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
version = "0.5.2"
|
version = "0.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "same-file"
|
||||||
version = "0.1.16"
|
version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc_version"
|
|
||||||
version = "0.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ryu"
|
|
||||||
version = "1.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "scopeguard"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "semver"
|
|
||||||
version = "0.9.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "semver-parser"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde"
|
|
||||||
version = "1.0.104"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_json"
|
|
||||||
version = "1.0.47"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"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)",
|
|
||||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -431,47 +330,26 @@ name = "strsim"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "syn"
|
|
||||||
version = "1.0.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"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)",
|
|
||||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "synstructure"
|
|
||||||
version = "0.12.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
dependencies = [
|
|
||||||
"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)",
|
|
||||||
"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)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.1.0"
|
version = "3.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.74 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
|
"redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "terminal_size"
|
name = "terminal_size"
|
||||||
version = "0.1.10"
|
version = "0.1.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.74 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -479,23 +357,54 @@ name = "textwrap"
|
|||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "thousands"
|
||||||
version = "0.1.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-xid"
|
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vec_map"
|
name = "thread_local"
|
||||||
version = "0.8.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "treeline"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-width"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vec_map"
|
||||||
|
version = "0.8.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wait-timeout"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.74 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "walkdir"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
@@ -504,7 +413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.8"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -518,10 +427,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-util"
|
name = "winapi-util"
|
||||||
version = "0.1.3"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -530,68 +439,57 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
|
"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86"
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
"checksum assert_cli 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a29ab7c0ed62970beb0534d637a8688842506d0ff9157de83286dacd065c8149"
|
"checksum assert_cmd 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c88b9ca26f9c16ec830350d309397e74ee9abdfd8eb1f71cb6ecc71a3fc818da"
|
||||||
"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 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d"
|
||||||
"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 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 bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931"
|
||||||
"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd"
|
|
||||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
|
||||||
"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d"
|
"checksum crossbeam-channel 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6"
|
||||||
"checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e"
|
"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||||
"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c"
|
|
||||||
"checksum crossbeam-deque 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3aa945d63861bfe624b55d153a39684da1e8c0bc8fba932f7ee3a3c16cea3ca"
|
|
||||||
"checksum crossbeam-epoch 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5064ebdbf05ce3cb95e45c8b086f72263f4166b29b97f6baff7ef7fe047b55ac"
|
|
||||||
"checksum crossbeam-queue 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c695eeca1e7173472a32221542ae469b3e9aac3a4fc81f7696bcad82029493db"
|
|
||||||
"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
|
|
||||||
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
||||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
"checksum doc-comment 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
|
||||||
"checksum environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee"
|
"checksum fnv 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
|
|
||||||
"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 globset 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7ad1da430bd7281dde2576f44c84cc3f0f7b475e7202cd503042dff01a8c8120"
|
||||||
"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9"
|
||||||
"checksum jwalk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3dbf0a8f61baee43a2918ff50ac6a2d3b2c105bc08ed53bc298779f1263409"
|
"checksum ignore 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)" = "22dcbf2a4a289528dbef21686354904e1c694ac642610a9bff9e7df730d9ec72"
|
||||||
"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.74 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10"
|
||||||
"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
|
"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||||
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
"checksum lscolors 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d24b894c45c9da468621cdd615a5a79ee5e5523dd4f75c76ebc03d458940c16e"
|
||||||
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||||
"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
|
"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
|
||||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea"
|
||||||
|
"checksum predicates 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96bfead12e90dccead362d62bb2c90a5f6fc4584963645bc7f71a735e0b0735a"
|
||||||
|
"checksum predicates-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06075c3a3e92559ff8929e7a280684489ea27fe44805174c3ebd9328dcb37178"
|
||||||
|
"checksum predicates-tree 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8e63c4859013b38a76eca2414c64911fba30def9e3202ac461a2d22831220124"
|
||||||
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||||
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
|
"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||||
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||||
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||||
"checksum rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
|
"checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||||
"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
|
"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6"
|
||||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8"
|
||||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
"checksum remove_dir_all 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
|
||||||
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
|
|
||||||
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
|
|
||||||
"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 serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
|
|
||||||
"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.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 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 terminal_size 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9a14cd9f8c72704232f0bfc8455c0e861f0ad4eb60cc9ec8a170e231414c1e13"
|
||||||
"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 thousands 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820"
|
||||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
"checksum treeline 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
|
||||||
|
"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
|
||||||
|
"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||||
|
"checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
|
||||||
|
"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||||
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||||
"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80"
|
"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|||||||
+10
-6
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "du-dust"
|
name = "du-dust"
|
||||||
description = "A more intuitive version of du"
|
description = "A more intuitive version of du"
|
||||||
version = "0.5.0"
|
version = "0.5.2"
|
||||||
authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"]
|
authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -23,16 +23,20 @@ path = "src/main.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
ansi_term = "=0.12"
|
ansi_term = "=0.12"
|
||||||
clap = "=2.33"
|
clap = "=2.33"
|
||||||
jwalk = "0.4.0"
|
lscolors = "0.7"
|
||||||
num_cpus = "1.12"
|
num_cpus = "1"
|
||||||
terminal_size = "0.1.10"
|
terminal_size = "0.1"
|
||||||
unicode-width = "0.1.7"
|
unicode-width = "0.1"
|
||||||
|
ignore="0.4"
|
||||||
|
crossbeam-channel = "0.4"
|
||||||
|
walkdir="2.3"
|
||||||
|
thousands = "0.2"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi-util = "0.1"
|
winapi-util = "0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cli = "=0.6"
|
assert_cmd ="1"
|
||||||
tempfile = "=3"
|
tempfile = "=3"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,31 +3,36 @@
|
|||||||
|
|
||||||
# Dust
|
# Dust
|
||||||
|
|
||||||
du + rust = dust. Like du but more intuitive
|
du + rust = dust. Like du but more intuitive.
|
||||||
|
|
||||||
|
# Why
|
||||||
|
|
||||||
|
Because I want an easy way to see where my disk is being used.
|
||||||
|
|
||||||
|
# Demo
|
||||||
|

|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
#### Cargo Install
|
#### Cargo <a href="https://repology.org/project/du-dust/versions"><img src="https://repology.org/badge/vertical-allrepos/du-dust.svg" alt="Packaging status" align="right"></a>
|
||||||
|
|
||||||
* cargo install du-dust
|
* `cargo install du-dust`
|
||||||
|
|
||||||
#### Download Install
|
#### 🍺 Homebrew (Mac OS)
|
||||||
|
|
||||||
* Download linux / mac binary from [Releases](https://github.com/bootandy/dust/releases)
|
* `brew install dust`
|
||||||
* unzip file: tar -xvf _downloaded_file.tar.gz_
|
|
||||||
* move file to executable path: sudo mv dust /usr/local/bin/
|
#### Download
|
||||||
|
|
||||||
|
* Download Linux/Mac binary from [Releases](https://github.com/bootandy/dust/releases)
|
||||||
|
* unzip file: `tar -xvf _downloaded_file.tar.gz`
|
||||||
|
* move file to executable path: `sudo mv dust /usr/local/bin/`
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
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 one 'Did not have permissions message'.
|
||||||
|
|
||||||
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*
|
Dust will list a slightly-less-than-the-terminal-height number of the biggest subdirectories or files and will smartly recurse down the tree to find the larger ones. There is no need for a '-d' flag or a '-h' flag. The largest subdirectories will be colored.
|
||||||
|
|
||||||
## Why?
|
|
||||||
|
|
||||||
du has a number of ways of showing you what it finds, in terms of disk consumption, but really, there are only one or two ways you invoke it: with -h for “human readable” units, like 100G or 89k, or with -b for “bytes”. The former is generally used for a quick survey of a directory with a small number of things in it, and the latter for when you have a bunch and need to sort the output numerically, and you’re obligated to either further pass it into something like awk to turn bytes into the appropriate human-friendly unit like mega or gigabytes, or pipe thru sort and head while remembering the '-h' flag. Then once you have the top offenders, you recurse down into the largest one and repeat the process until you’ve found your cruft or gems and can move on.
|
|
||||||
|
|
||||||
Dust assumes that’s what you wanted to do in the first place, and takes care of tracking the largest offenders in terms of actual size, and showing them to you with human-friendly units and in-context within the filetree.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@@ -37,48 +42,12 @@ Usage: dust <dir>
|
|||||||
Usage: dust <dir> <another_dir> <and_more>
|
Usage: dust <dir> <another_dir> <and_more>
|
||||||
Usage: dust -p <dir> (full-path - does not shorten the path of the subdirectories)
|
Usage: dust -p <dir> (full-path - does not shorten the path of the subdirectories)
|
||||||
Usage: dust -s <dir> (apparent-size - shows the length of the file as opposed to the amount of disk space it uses)
|
Usage: dust -s <dir> (apparent-size - shows the length of the file as opposed to the amount of disk space it uses)
|
||||||
Usage: dust -n 30 <dir> (Shows 30 directories not 20)
|
Usage: dust -n 30 <dir> (shows 30 directories instead of the default)
|
||||||
Usage: dust -d 3 <dir> (Shows 3 levels of subdirectories)
|
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 the 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)
|
Usage: dust -b <dir> (do not show percentages or draw ASCII bars)
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
$ dust target
|
|
||||||
15M ┌── build │ ░█ │ 2%
|
|
||||||
25M ├── deps │ ░█ │ 4%
|
|
||||||
45M ┌─┴ release │ ██ │ 7%
|
|
||||||
84M │ ┌── build │ ▒▒▒▒▒████ │ 13%
|
|
||||||
7.6M │ │ ┌── libsynstructure-f7552412787ad339.rlib│ ▒▒▒▓▓▓▓▓█ │ 1%
|
|
||||||
16M │ │ ├── libfailure_derive-e18365d3e6be2e2c.so│ ▒▒▒▓▓▓▓▓█ │ 2%
|
|
||||||
18M │ │ ├── libsyn-9ad95b745845d5dd.rlib │ ▒▒▒▓▓▓▓▓█ │ 3%
|
|
||||||
19M │ │ ├── libsyn-d4a3458fcb1c592c.rlib │ ▒▒▒▓▓▓▓▓█ │ 3%
|
|
||||||
135M │ ├─┴ deps │ ▒▒▒██████ │ 20%
|
|
||||||
228M │ ┌─┴ debug │ █████████ │ 34%
|
|
||||||
228M ├─┴ rls │ █████████ │ 34%
|
|
||||||
18M │ ┌── dust │ ░░░░░░░░░░░░░░█ │ 3%
|
|
||||||
22M │ ├── dust-a0c31c4633c5fc8b │ ░░░░░░░░░░░░░░█ │ 3%
|
|
||||||
7.4M │ │ ┌── s-fkrj3vfncf-19aj951-1fv3o6tzvr348 │ ░░░░░░░░░░░░░▒█ │ 1%
|
|
||||||
7.4M │ │ ┌─┴ dust-1i3xquz5fns51 │ ░░░░░░░░░░░░░▒█ │ 1%
|
|
||||||
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%
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -3,4 +3,7 @@
|
|||||||
# git tag v0.4.5
|
# git tag v0.4.5
|
||||||
# git push origin v0.4.5
|
# git push origin v0.4.5
|
||||||
|
|
||||||
# cargo publish to put it in crates.io
|
# cargo publish to put it in crates.io
|
||||||
|
|
||||||
|
# To install locally [Do before pushing it]
|
||||||
|
#cargo install --path .
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
+173
-46
@@ -1,17 +1,20 @@
|
|||||||
extern crate ansi_term;
|
extern crate ansi_term;
|
||||||
|
|
||||||
use self::ansi_term::Colour::Fixed;
|
|
||||||
use self::ansi_term::Style;
|
|
||||||
use crate::utils::Node;
|
use crate::utils::Node;
|
||||||
|
|
||||||
|
use self::ansi_term::Colour::Red;
|
||||||
|
use lscolors::{LsColors, Style};
|
||||||
|
|
||||||
use terminal_size::{terminal_size, Height, Width};
|
use terminal_size::{terminal_size, Height, Width};
|
||||||
|
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
use std::fs;
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use thousands::Separable;
|
||||||
|
|
||||||
static UNITS: [char; 4] = ['T', 'G', 'M', 'K'];
|
static UNITS: [char; 4] = ['T', 'G', 'M', 'K'];
|
||||||
static BLOCKS: [char; 5] = ['█', '▓', '▒', '░', ' '];
|
static BLOCKS: [char; 5] = ['█', '▓', '▒', '░', ' '];
|
||||||
@@ -21,8 +24,11 @@ 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 by_filecount: bool,
|
||||||
|
pub num_chars_needed_on_left_most: usize,
|
||||||
pub base_size: u64,
|
pub base_size: u64,
|
||||||
pub longest_string_length: usize,
|
pub longest_string_length: usize,
|
||||||
|
pub ls_colors: LsColors,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DisplayData {
|
impl DisplayData {
|
||||||
@@ -102,13 +108,14 @@ impl DrawData<'_> {
|
|||||||
self.indent.to_string() + chars
|
self.indent.to_string() + chars
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: can we test this?
|
||||||
fn generate_bar(&self, node: &Node, level: usize) -> String {
|
fn generate_bar(&self, node: &Node, level: usize) -> String {
|
||||||
let chars_in_bar = self.percent_bar.chars().count();
|
let chars_in_bar = self.percent_bar.chars().count();
|
||||||
let num_bars = chars_in_bar as f32 * self.display_data.percent_size(node);
|
let num_bars = chars_in_bar as f32 * self.display_data.percent_size(node);
|
||||||
let mut num_not_my_bar = (chars_in_bar as i32) - num_bars as i32;
|
let mut num_not_my_bar = (chars_in_bar as i32) - num_bars as i32;
|
||||||
|
|
||||||
let mut new_bar = "".to_string();
|
let mut new_bar = "".to_string();
|
||||||
let idx = 5 - min(5, max(1, level));
|
let idx = 5 - min(4, max(1, level));
|
||||||
|
|
||||||
for c in self.percent_bar.chars() {
|
for c in self.percent_bar.chars() {
|
||||||
num_not_my_bar -= 1;
|
num_not_my_bar -= 1;
|
||||||
@@ -139,17 +146,26 @@ pub fn draw_it(
|
|||||||
is_reversed: bool,
|
is_reversed: bool,
|
||||||
no_colors: bool,
|
no_colors: bool,
|
||||||
no_percents: bool,
|
no_percents: bool,
|
||||||
|
by_filecount: 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 num_chars_needed_on_left_most = if by_filecount {
|
||||||
|
let max_size = root_node.children.iter().map(|n| n.size).fold(0, max);
|
||||||
|
max_size.separate_with_commas().chars().count()
|
||||||
|
} else {
|
||||||
|
5 // Under normal usage we need 5 chars to display the size of a directory
|
||||||
|
};
|
||||||
|
|
||||||
|
let terminal_width = get_width_of_terminal() as usize - 9 - num_chars_needed_on_left_most;
|
||||||
|
let num_indent_chars = 3;
|
||||||
let longest_string_length = root_node
|
let longest_string_length = root_node
|
||||||
.children
|
.children
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| find_longest_dir_name(&c, " ", !use_full_path))
|
.map(|c| find_longest_dir_name(&c, num_indent_chars, terminal_width, !use_full_path))
|
||||||
.fold(0, max);
|
.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 {
|
let max_bar_length = if no_percents || longest_string_length >= terminal_width as usize {
|
||||||
0
|
0
|
||||||
@@ -157,48 +173,51 @@ pub fn draw_it(
|
|||||||
terminal_width as usize - longest_string_length
|
terminal_width as usize - longest_string_length
|
||||||
};
|
};
|
||||||
|
|
||||||
// handle usize error also add do not show fancy output option
|
let first_size_bar = repeat(BLOCKS[0]).take(max_bar_length).collect::<String>();
|
||||||
let bar_text = repeat(BLOCKS[0]).take(max_bar_length).collect::<String>();
|
|
||||||
|
|
||||||
for c in get_children_from_node(root_node, is_reversed) {
|
for c in get_children_from_node(root_node, is_reversed) {
|
||||||
let display_data = DisplayData {
|
let display_data = DisplayData {
|
||||||
short_paths: !use_full_path,
|
short_paths: !use_full_path,
|
||||||
is_reversed,
|
is_reversed,
|
||||||
colors_on: !no_colors,
|
colors_on: !no_colors,
|
||||||
|
by_filecount,
|
||||||
|
num_chars_needed_on_left_most,
|
||||||
base_size: c.size,
|
base_size: c.size,
|
||||||
longest_string_length,
|
longest_string_length,
|
||||||
|
ls_colors: LsColors::from_env().unwrap_or_default(),
|
||||||
};
|
};
|
||||||
let draw_data = DrawData {
|
let draw_data = DrawData {
|
||||||
indent: "".to_string(),
|
indent: "".to_string(),
|
||||||
percent_bar: bar_text.clone(),
|
percent_bar: first_size_bar.clone(),
|
||||||
display_data: &display_data,
|
display_data: &display_data,
|
||||||
};
|
};
|
||||||
display_node(c, &draw_data, true, true);
|
display_node(c, &draw_data, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can probably pass depth instead of indent here.
|
fn find_longest_dir_name(node: &Node, indent: usize, terminal: usize, long_paths: bool) -> usize {
|
||||||
// It is ugly to feed in ' ' instead of the actual tree characters but we don't need them yet.
|
let printable_name = get_printable_name(&node.name, long_paths);
|
||||||
fn find_longest_dir_name(node: &Node, indent: &str, long_paths: bool) -> usize {
|
let longest = min(
|
||||||
let longest = UnicodeWidthStr::width(&*get_printable_name(&node.name, long_paths, indent));
|
UnicodeWidthStr::width(&*printable_name) + 1 + indent,
|
||||||
|
terminal,
|
||||||
|
);
|
||||||
|
|
||||||
// each none root tree drawing is 2 chars
|
// each none root tree drawing is 2 more chars, hence we increment indent by 2
|
||||||
let full_indent: String = indent.to_string() + " ";
|
|
||||||
node.children
|
node.children
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| find_longest_dir_name(c, &*full_indent, long_paths))
|
.map(|c| find_longest_dir_name(c, indent + 2, terminal, long_paths))
|
||||||
.fold(longest, max)
|
.fold(longest, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_node(node: Node, draw_data: &DrawData, is_biggest: bool, is_last: bool) {
|
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
|
// hacky way of working out how deep we are in the tree
|
||||||
let level = ((indent2.chars().count() - 1) / 2) - 1;
|
let indent = draw_data.get_new_indent(!node.children.is_empty(), is_last);
|
||||||
|
let level = ((indent.chars().count() - 1) / 2) - 1;
|
||||||
let bar_text = draw_data.generate_bar(&node, level);
|
let bar_text = draw_data.generate_bar(&node, level);
|
||||||
|
|
||||||
let to_print = format_string(
|
let to_print = format_string(
|
||||||
&node,
|
&node,
|
||||||
&*indent2,
|
&*indent,
|
||||||
&*bar_text,
|
&*bar_text,
|
||||||
is_biggest,
|
is_biggest,
|
||||||
draw_data.display_data,
|
draw_data.display_data,
|
||||||
@@ -209,7 +228,7 @@ fn display_node(node: Node, draw_data: &DrawData, is_biggest: bool, is_last: boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
let dd = DrawData {
|
let dd = DrawData {
|
||||||
indent: clean_indentation_string(&*indent2),
|
indent: clean_indentation_string(&*indent),
|
||||||
percent_bar: bar_text,
|
percent_bar: bar_text,
|
||||||
display_data: draw_data.display_data,
|
display_data: draw_data.display_data,
|
||||||
};
|
};
|
||||||
@@ -243,7 +262,7 @@ fn clean_indentation_string(s: &str) -> String {
|
|||||||
is
|
is
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_printable_name<P: AsRef<Path>>(dir_name: &P, long_paths: bool, indentation: &str) -> String {
|
fn get_printable_name<P: AsRef<Path>>(dir_name: &P, long_paths: bool) -> String {
|
||||||
let dir_name = dir_name.as_ref();
|
let dir_name = dir_name.as_ref();
|
||||||
let printable_name = {
|
let printable_name = {
|
||||||
if long_paths {
|
if long_paths {
|
||||||
@@ -258,7 +277,33 @@ fn get_printable_name<P: AsRef<Path>>(dir_name: &P, long_paths: bool, indentatio
|
|||||||
dir_name
|
dir_name
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
format!("{} {}", indentation, printable_name.display())
|
printable_name.display().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pad_or_trim_filename(node: &Node, indent: &str, display_data: &DisplayData) -> String {
|
||||||
|
let name = get_printable_name(&node.name, display_data.short_paths);
|
||||||
|
let indent_and_name = format!("{} {}", indent, name);
|
||||||
|
let width = UnicodeWidthStr::width(&*indent_and_name);
|
||||||
|
|
||||||
|
// Add spaces after the filename so we can draw the % used bar chart.
|
||||||
|
let name_and_padding = name
|
||||||
|
+ &(repeat(" ")
|
||||||
|
.take(display_data.longest_string_length - width)
|
||||||
|
.collect::<String>());
|
||||||
|
|
||||||
|
maybe_trim_filename(name_and_padding, display_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_trim_filename(name_in: String, display_data: &DisplayData) -> String {
|
||||||
|
if UnicodeWidthStr::width(&*name_in) > display_data.longest_string_length {
|
||||||
|
let name = name_in
|
||||||
|
.chars()
|
||||||
|
.take(display_data.longest_string_length - 2)
|
||||||
|
.collect::<String>();
|
||||||
|
name + ".."
|
||||||
|
} else {
|
||||||
|
name_in
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn format_string(
|
pub fn format_string(
|
||||||
@@ -268,35 +313,60 @@ pub fn format_string(
|
|||||||
is_biggest: bool,
|
is_biggest: bool,
|
||||||
display_data: &DisplayData,
|
display_data: &DisplayData,
|
||||||
) -> String {
|
) -> String {
|
||||||
let pretty_size = format!("{:>5}", human_readable_number(node.size));
|
let (percents, name_and_padding) = get_name_percent(node, indent, percent_bar, display_data);
|
||||||
|
let pretty_size = get_pretty_size(node, is_biggest, display_data);
|
||||||
|
let pretty_name = get_pretty_name(node, name_and_padding, display_data);
|
||||||
|
format!("{} {} {}{}", pretty_size, indent, pretty_name, percents)
|
||||||
|
}
|
||||||
|
|
||||||
let percent_size = display_data.percent_size(node);
|
fn get_name_percent(
|
||||||
let percent_size_str = format!("{:.0}%", percent_size * 100.0);
|
node: &Node,
|
||||||
|
indent: &str,
|
||||||
let tree_and_path = get_printable_name(&node.name, display_data.short_paths, &*indent);
|
bar_chart: &str,
|
||||||
|
display_data: &DisplayData,
|
||||||
let printable_chars = UnicodeWidthStr::width(&*tree_and_path);
|
) -> (String, String) {
|
||||||
let tree_and_path = tree_and_path
|
if bar_chart != "" {
|
||||||
+ &(repeat(" ")
|
let percent_size_str = format!("{:.0}%", display_data.percent_size(node) * 100.0);
|
||||||
.take(display_data.longest_string_length - printable_chars)
|
let percents = format!("│{} │ {:>4}", bar_chart, percent_size_str);
|
||||||
.collect::<String>());
|
let name_and_padding = pad_or_trim_filename(node, indent, display_data);
|
||||||
|
(percents, name_and_padding)
|
||||||
let percents = if percent_bar != "" {
|
|
||||||
format!("│{} │ {:>4}", percent_bar, percent_size_str)
|
|
||||||
} else {
|
} else {
|
||||||
"".into()
|
let n = get_printable_name(&node.name, display_data.short_paths);
|
||||||
|
let name = maybe_trim_filename(n, display_data);
|
||||||
|
("".into(), name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pretty_size(node: &Node, is_biggest: bool, display_data: &DisplayData) -> String {
|
||||||
|
let output = if display_data.by_filecount {
|
||||||
|
let size_as_str = node.size.separate_with_commas();
|
||||||
|
let spaces_to_add =
|
||||||
|
display_data.num_chars_needed_on_left_most - size_as_str.chars().count();
|
||||||
|
size_as_str + &*repeat(' ').take(spaces_to_add).collect::<String>()
|
||||||
|
} else {
|
||||||
|
format!("{:>5}", human_readable_number(node.size))
|
||||||
};
|
};
|
||||||
|
|
||||||
format!(
|
if is_biggest && display_data.colors_on {
|
||||||
"{} {}{}",
|
format!("{}", Red.paint(output))
|
||||||
if is_biggest && display_data.colors_on {
|
} else {
|
||||||
Fixed(196).paint(pretty_size)
|
output
|
||||||
} else {
|
}
|
||||||
Style::new().paint(pretty_size)
|
}
|
||||||
},
|
|
||||||
tree_and_path,
|
fn get_pretty_name(node: &Node, name_and_padding: String, display_data: &DisplayData) -> String {
|
||||||
percents,
|
if display_data.colors_on {
|
||||||
)
|
let meta_result = fs::metadata(node.name.clone());
|
||||||
|
let directory_color = display_data
|
||||||
|
.ls_colors
|
||||||
|
.style_for_path_with_metadata(node.name.clone(), meta_result.as_ref().ok());
|
||||||
|
let ansi_style = directory_color
|
||||||
|
.map(Style::to_ansi_term_style)
|
||||||
|
.unwrap_or_default();
|
||||||
|
format!("{}", ansi_style.paint(name_and_padding))
|
||||||
|
} else {
|
||||||
|
name_and_padding
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn human_readable_number(size: u64) -> String {
|
fn human_readable_number(size: u64) -> String {
|
||||||
@@ -316,6 +386,63 @@ fn human_readable_number(size: u64) -> String {
|
|||||||
mod tests {
|
mod tests {
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use super::*;
|
use super::*;
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn get_fake_display_data(longest_string_length: usize) -> DisplayData {
|
||||||
|
DisplayData {
|
||||||
|
short_paths: true,
|
||||||
|
is_reversed: false,
|
||||||
|
colors_on: false,
|
||||||
|
by_filecount: false,
|
||||||
|
num_chars_needed_on_left_most: 5,
|
||||||
|
base_size: 1,
|
||||||
|
longest_string_length: longest_string_length,
|
||||||
|
ls_colors: LsColors::from_env().unwrap_or_default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_str() {
|
||||||
|
let n = Node {
|
||||||
|
name: PathBuf::from("/short"),
|
||||||
|
size: 2_u64.pow(12), // This is 4.0K
|
||||||
|
children: vec![],
|
||||||
|
};
|
||||||
|
let indent = "┌─┴";
|
||||||
|
let percent_bar = "";
|
||||||
|
let is_biggest = false;
|
||||||
|
|
||||||
|
let s = format_string(
|
||||||
|
&n,
|
||||||
|
indent,
|
||||||
|
percent_bar,
|
||||||
|
is_biggest,
|
||||||
|
&get_fake_display_data(6),
|
||||||
|
);
|
||||||
|
assert_eq!(s, " 4.0K ┌─┴ short");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_format_str_long_name() {
|
||||||
|
let name = "very_long_name_longer_than_the_eighty_character_limit_very_long_name_this_bit_will_truncate";
|
||||||
|
let n = Node {
|
||||||
|
name: PathBuf::from(name),
|
||||||
|
size: 2_u64.pow(12), // This is 4.0K
|
||||||
|
children: vec![],
|
||||||
|
};
|
||||||
|
let indent = "┌─┴";
|
||||||
|
let percent_bar = "";
|
||||||
|
let is_biggest = false;
|
||||||
|
|
||||||
|
let dd = get_fake_display_data(64);
|
||||||
|
let s = format_string(&n, indent, percent_bar, is_biggest, &dd);
|
||||||
|
assert_eq!(
|
||||||
|
s,
|
||||||
|
" 4.0K ┌─┴ very_long_name_longer_than_the_eighty_character_limit_very_lon.."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_human_readable_number() {
|
fn test_human_readable_number() {
|
||||||
|
|||||||
+57
-46
@@ -1,6 +1,9 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
|
extern crate crossbeam_channel as channel;
|
||||||
|
extern crate ignore;
|
||||||
extern crate unicode_width;
|
extern crate unicode_width;
|
||||||
|
extern crate walkdir;
|
||||||
|
|
||||||
use self::display::draw_it;
|
use self::display::draw_it;
|
||||||
use crate::utils::is_a_parent_of;
|
use crate::utils::is_a_parent_of;
|
||||||
@@ -8,7 +11,7 @@ use clap::{App, AppSettings, Arg};
|
|||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use terminal_size::{terminal_size, Height, Width};
|
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, Node};
|
||||||
|
|
||||||
mod display;
|
mod display;
|
||||||
mod utils;
|
mod utils;
|
||||||
@@ -16,12 +19,29 @@ mod utils;
|
|||||||
static DEFAULT_NUMBER_OF_LINES: usize = 30;
|
static DEFAULT_NUMBER_OF_LINES: usize = 30;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn init_color() {
|
fn init_color(no_color: bool) -> bool {
|
||||||
ansi_term::enable_ansi_support().expect("Couldn't enable color support");
|
// If no color is already set do not print a warning message
|
||||||
|
if no_color {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
// Required for windows 10
|
||||||
|
// Fails to resolve for windows 8 so disable color
|
||||||
|
match ansi_term::enable_ansi_support() {
|
||||||
|
Ok(_) => no_color,
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!(
|
||||||
|
"This version of Windows does not support ANSI colors, setting no_color flag"
|
||||||
|
);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
fn init_color() {}
|
fn init_color(no_color: bool) -> bool {
|
||||||
|
no_color
|
||||||
|
}
|
||||||
|
|
||||||
fn get_height_of_terminal() -> usize {
|
fn get_height_of_terminal() -> usize {
|
||||||
// Windows CI runners detect a terminal height of 0
|
// Windows CI runners detect a terminal height of 0
|
||||||
@@ -33,8 +53,6 @@ fn get_height_of_terminal() -> usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
init_color();
|
|
||||||
|
|
||||||
let default_height = get_height_of_terminal();
|
let default_height = get_height_of_terminal();
|
||||||
let def_num_str = default_height.to_string();
|
let def_num_str = default_height.to_string();
|
||||||
|
|
||||||
@@ -49,13 +67,6 @@ fn main() {
|
|||||||
.help("Depth to show")
|
.help("Depth to show")
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("threads")
|
|
||||||
.short("t")
|
|
||||||
.long("threads")
|
|
||||||
.help("Number of threads to spawn simultaneously")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("number_of_lines")
|
Arg::with_name("number_of_lines")
|
||||||
.short("n")
|
.short("n")
|
||||||
@@ -68,7 +79,7 @@ fn main() {
|
|||||||
Arg::with_name("display_full_paths")
|
Arg::with_name("display_full_paths")
|
||||||
.short("p")
|
.short("p")
|
||||||
.long("full-paths")
|
.long("full-paths")
|
||||||
.help("If set sub directories will not have their path shortened"),
|
.help("Subdirectories will not have their path shortened"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("ignore_directory")
|
Arg::with_name("ignore_directory")
|
||||||
@@ -77,38 +88,51 @@ fn main() {
|
|||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.number_of_values(1)
|
.number_of_values(1)
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
.help("Exclude any file or directory with this name."),
|
.help("Exclude any file or directory with this name"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("limit_filesystem")
|
Arg::with_name("limit_filesystem")
|
||||||
.short("x")
|
.short("x")
|
||||||
.long("limit-filesystem")
|
.long("limit-filesystem")
|
||||||
.help("Only count the files and directories in the same filesystem as the supplied directory"),
|
.help("Only count the files and directories on the same filesystem as the supplied directory"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("display_apparent_size")
|
Arg::with_name("display_apparent_size")
|
||||||
.short("s")
|
.short("s")
|
||||||
.long("apparent-size")
|
.long("apparent-size")
|
||||||
.help("If set will use file length. Otherwise we use blocks"),
|
.help("Use file length instead of blocks"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
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 highest)"),
|
.help("Print tree upside down (biggest highest)"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("no_colors")
|
Arg::with_name("no_colors")
|
||||||
.short("c")
|
.short("c")
|
||||||
.long("no_colors")
|
.long("no-colors")
|
||||||
.help("If applied no colors will be printed (normally largest directories are marked in red"),
|
.help("No colors will be printed (normally largest directories are colored)"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("no_bars")
|
Arg::with_name("no_bars")
|
||||||
.short("b")
|
.short("b")
|
||||||
.long("no_percent_bars")
|
.long("no-percent-bars")
|
||||||
.help("If applied no percent bars or percents will be displayed"),
|
.help("No percent bars or percentages will be displayed"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("by_filecount")
|
||||||
|
.short("f")
|
||||||
|
.long("filecount")
|
||||||
|
.help("Directory 'size' is number of child files/dirs not disk size"),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name("ignore_hidden")
|
||||||
|
.short("i") // Do not use 'h' this is used by 'help'
|
||||||
|
.long("ignore_hidden")
|
||||||
|
.help("Obey .git_ignore rules & Do not display hidden files"),
|
||||||
|
)
|
||||||
|
|
||||||
.arg(Arg::with_name("inputs").multiple(true))
|
.arg(Arg::with_name("inputs").multiple(true))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
@@ -127,27 +151,9 @@ fn main() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let temp_threads = options.value_of("threads").and_then(|threads| {
|
|
||||||
threads
|
|
||||||
.parse::<usize>()
|
|
||||||
.map_err(|_| eprintln!("Ignoring bad value for threads: {:?}", threads))
|
|
||||||
.ok()
|
|
||||||
});
|
|
||||||
// Bug in JWalk
|
|
||||||
// https://github.com/jessegrosjean/jwalk/issues/15
|
|
||||||
// We force it to use 2 threads if there is only 1 cpu
|
|
||||||
// as JWalk breaks if it tries to run on a single cpu
|
|
||||||
let threads = {
|
|
||||||
if temp_threads.is_none() && num_cpus::get() == 1 {
|
|
||||||
Some(2)
|
|
||||||
} else {
|
|
||||||
temp_threads
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let depth = options.value_of("depth").and_then(|depth| {
|
let depth = options.value_of("depth").and_then(|depth| {
|
||||||
depth
|
depth
|
||||||
.parse::<u64>()
|
.parse::<usize>()
|
||||||
.map(|v| v + 1)
|
.map(|v| v + 1)
|
||||||
.map_err(|_| eprintln!("Ignoring bad value for depth"))
|
.map_err(|_| eprintln!("Ignoring bad value for depth"))
|
||||||
.ok()
|
.ok()
|
||||||
@@ -157,12 +163,15 @@ fn main() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let no_colors = init_color(options.is_present("no_colors"));
|
||||||
let use_apparent_size = options.is_present("display_apparent_size");
|
let use_apparent_size = options.is_present("display_apparent_size");
|
||||||
let limit_filesystem = options.is_present("limit_filesystem");
|
let limit_filesystem = options.is_present("limit_filesystem");
|
||||||
let ignore_directories = match options.values_of("ignore_directory") {
|
let ignore_directories = match options.values_of("ignore_directory") {
|
||||||
Some(i) => Some(i.map(PathBuf::from).collect()),
|
Some(i) => Some(i.map(PathBuf::from).collect()),
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
let by_filecount = options.is_present("by_filecount");
|
||||||
|
let show_hidden = !options.is_present("ignore_hidden");
|
||||||
|
|
||||||
let simplified_dirs = simplify_dir_names(target_dirs);
|
let simplified_dirs = simplify_dir_names(target_dirs);
|
||||||
let (permissions, nodes) = get_dir_tree(
|
let (permissions, nodes) = get_dir_tree(
|
||||||
@@ -170,13 +179,14 @@ fn main() {
|
|||||||
&ignore_directories,
|
&ignore_directories,
|
||||||
use_apparent_size,
|
use_apparent_size,
|
||||||
limit_filesystem,
|
limit_filesystem,
|
||||||
threads,
|
by_filecount,
|
||||||
|
show_hidden,
|
||||||
);
|
);
|
||||||
let sorted_data = sort(nodes);
|
let sorted_data = sort(nodes);
|
||||||
let biggest_ones = {
|
let biggest_ones = {
|
||||||
match depth {
|
match depth {
|
||||||
None => find_big_ones(sorted_data, number_of_lines + simplified_dirs.len()),
|
None => find_big_ones(sorted_data, number_of_lines + simplified_dirs.len()),
|
||||||
Some(d) => trim_deep_ones(sorted_data, d, &simplified_dirs),
|
Some(_) => sorted_data,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let tree = build_tree(biggest_ones, depth);
|
let tree = build_tree(biggest_ones, depth);
|
||||||
@@ -185,13 +195,14 @@ fn main() {
|
|||||||
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"),
|
no_colors,
|
||||||
options.is_present("no_bars"),
|
options.is_present("no_bars"),
|
||||||
|
by_filecount,
|
||||||
tree,
|
tree,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_tree(biggest_ones: Vec<(PathBuf, u64)>, depth: Option<u64>) -> Node {
|
fn build_tree(biggest_ones: Vec<(PathBuf, u64)>, depth: Option<usize>) -> Node {
|
||||||
let mut top_parent = Node::default();
|
let mut top_parent = Node::default();
|
||||||
|
|
||||||
// assume sorted order
|
// assume sorted order
|
||||||
@@ -206,7 +217,7 @@ fn build_tree(biggest_ones: Vec<(PathBuf, u64)>, depth: Option<u64>) -> Node {
|
|||||||
top_parent
|
top_parent
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recursively_build_tree(parent_node: &mut Node, new_node: Node, depth: Option<u64>) {
|
fn recursively_build_tree(parent_node: &mut Node, new_node: Node, depth: Option<usize>) {
|
||||||
let new_depth = match depth {
|
let new_depth = match depth {
|
||||||
None => None,
|
None => None,
|
||||||
Some(0) => return,
|
Some(0) => return,
|
||||||
|
|||||||
+136
-160
@@ -1,14 +1,22 @@
|
|||||||
use jwalk::DirEntry;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::iter::FromIterator;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
use jwalk::WalkDir;
|
use channel::Receiver;
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
|
||||||
|
use ignore::{WalkBuilder, WalkState};
|
||||||
|
use std::sync::atomic;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
mod platform;
|
mod platform;
|
||||||
use self::platform::*;
|
use self::platform::*;
|
||||||
|
|
||||||
|
type PathData = (PathBuf, u64, Option<(u64, u64)>);
|
||||||
|
|
||||||
#[derive(Debug, Default, Eq)]
|
#[derive(Debug, Default, Eq)]
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
pub name: PathBuf,
|
pub name: PathBuf,
|
||||||
@@ -41,7 +49,7 @@ impl PartialEq for Node {
|
|||||||
pub fn is_a_parent_of<P: AsRef<Path>>(parent: P, child: P) -> bool {
|
pub fn is_a_parent_of<P: AsRef<Path>>(parent: P, child: P) -> bool {
|
||||||
let parent = parent.as_ref();
|
let parent = parent.as_ref();
|
||||||
let child = child.as_ref();
|
let child = child.as_ref();
|
||||||
(child.starts_with(parent) && !parent.starts_with(child))
|
child.starts_with(parent) && !parent.starts_with(child)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn simplify_dir_names<P: AsRef<Path>>(filenames: Vec<P>) -> HashSet<PathBuf> {
|
pub fn simplify_dir_names<P: AsRef<Path>>(filenames: Vec<P>) -> HashSet<PathBuf> {
|
||||||
@@ -70,43 +78,123 @@ pub fn simplify_dir_names<P: AsRef<Path>>(filenames: Vec<P>) -> HashSet<PathBuf>
|
|||||||
top_level_names
|
top_level_names
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prepare_walk_dir_builder<P: AsRef<Path>>(
|
||||||
|
top_level_names: &HashSet<P>,
|
||||||
|
limit_filesystem: bool,
|
||||||
|
show_hidden: bool,
|
||||||
|
) -> WalkBuilder {
|
||||||
|
let mut it = top_level_names.iter();
|
||||||
|
let mut builder = WalkBuilder::new(it.next().unwrap());
|
||||||
|
builder.follow_links(false);
|
||||||
|
if show_hidden {
|
||||||
|
builder.hidden(false);
|
||||||
|
builder.ignore(false);
|
||||||
|
builder.git_global(false);
|
||||||
|
builder.git_ignore(false);
|
||||||
|
builder.git_exclude(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if limit_filesystem {
|
||||||
|
builder.same_file_system(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for b in it {
|
||||||
|
builder.add(b);
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_dir_tree<P: AsRef<Path>>(
|
pub fn get_dir_tree<P: AsRef<Path>>(
|
||||||
top_level_names: &HashSet<P>,
|
top_level_names: &HashSet<P>,
|
||||||
ignore_directories: &Option<Vec<PathBuf>>,
|
ignore_directories: &Option<Vec<PathBuf>>,
|
||||||
apparent_size: bool,
|
apparent_size: bool,
|
||||||
limit_filesystem: bool,
|
limit_filesystem: bool,
|
||||||
threads: Option<usize>,
|
by_filecount: bool,
|
||||||
|
show_hidden: bool,
|
||||||
) -> (bool, HashMap<PathBuf, u64>) {
|
) -> (bool, HashMap<PathBuf, u64>) {
|
||||||
let mut permissions = 0;
|
let (tx, rx) = channel::bounded::<PathData>(1000);
|
||||||
let mut data: HashMap<PathBuf, u64> = HashMap::new();
|
|
||||||
let restricted_filesystems = if limit_filesystem {
|
|
||||||
get_allowed_filesystems(top_level_names)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
for b in top_level_names.iter() {
|
let permissions_flag = AtomicBool::new(true);
|
||||||
examine_dir(
|
|
||||||
b,
|
let t2 = HashSet::from_iter(top_level_names.iter().map(|p| p.as_ref().to_path_buf()));
|
||||||
apparent_size,
|
|
||||||
&restricted_filesystems,
|
let t = create_reader_thread(rx, t2, apparent_size);
|
||||||
ignore_directories,
|
let walk_dir_builder = prepare_walk_dir_builder(top_level_names, limit_filesystem, show_hidden);
|
||||||
&mut data,
|
|
||||||
&mut permissions,
|
walk_dir_builder.build_parallel().run(|| {
|
||||||
threads,
|
let txc = tx.clone();
|
||||||
);
|
let pf = &permissions_flag;
|
||||||
}
|
Box::new(move |path| {
|
||||||
(permissions == 0, data)
|
match path {
|
||||||
|
Ok(p) => {
|
||||||
|
if let Some(dirs) = ignore_directories {
|
||||||
|
let path = p.path();
|
||||||
|
let parts = path.components().collect::<Vec<std::path::Component>>();
|
||||||
|
for d in dirs {
|
||||||
|
let seq = d.components().collect::<Vec<std::path::Component>>();
|
||||||
|
if parts
|
||||||
|
.windows(seq.len())
|
||||||
|
.any(|window| window.iter().collect::<PathBuf>() == *d)
|
||||||
|
{
|
||||||
|
return WalkState::Continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let maybe_size_and_inode = get_metadata(&p, apparent_size);
|
||||||
|
|
||||||
|
match maybe_size_and_inode {
|
||||||
|
Some(data) => {
|
||||||
|
let (size, inode_device) =
|
||||||
|
if by_filecount { (1, data.1) } else { data };
|
||||||
|
txc.send((p.into_path(), size, inode_device)).unwrap();
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
pf.store(false, atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => {
|
||||||
|
pf.store(false, atomic::Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
WalkState::Continue
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
drop(tx);
|
||||||
|
let data = t.join().unwrap();
|
||||||
|
(permissions_flag.load(atomic::Ordering::SeqCst), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_allowed_filesystems<P: AsRef<Path>>(top_level_names: &HashSet<P>) -> Option<HashSet<u64>> {
|
fn create_reader_thread(
|
||||||
let mut limit_filesystems: HashSet<u64> = HashSet::new();
|
rx: Receiver<PathData>,
|
||||||
for file_name in top_level_names.iter() {
|
top_level_names: HashSet<PathBuf>,
|
||||||
if let Ok(a) = get_filesystem(file_name) {
|
apparent_size: bool,
|
||||||
limit_filesystems.insert(a);
|
) -> JoinHandle<HashMap<PathBuf, u64>> {
|
||||||
|
// Receiver thread
|
||||||
|
thread::spawn(move || {
|
||||||
|
let mut hash: HashMap<PathBuf, u64> = HashMap::new();
|
||||||
|
let mut inodes: HashSet<(u64, u64)> = HashSet::new();
|
||||||
|
|
||||||
|
for dent in rx {
|
||||||
|
let (path, size, maybe_inode_device) = dent;
|
||||||
|
|
||||||
|
if should_ignore_file(apparent_size, &mut inodes, maybe_inode_device) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
for p in path.ancestors() {
|
||||||
|
let s = hash.entry(p.to_path_buf()).or_insert(0);
|
||||||
|
*s += size;
|
||||||
|
|
||||||
|
if top_level_names.contains(p) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
hash
|
||||||
Some(limit_filesystems)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
|
pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
|
||||||
@@ -119,96 +207,23 @@ pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
|
|||||||
path.as_ref().components().collect::<PathBuf>()
|
path.as_ref().components().collect::<PathBuf>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn examine_dir<P: AsRef<Path>>(
|
|
||||||
top_dir: P,
|
|
||||||
apparent_size: bool,
|
|
||||||
filesystems: &Option<HashSet<u64>>,
|
|
||||||
ignore_directories: &Option<Vec<PathBuf>>,
|
|
||||||
data: &mut HashMap<PathBuf, u64>,
|
|
||||||
file_count_no_permission: &mut u64,
|
|
||||||
threads: Option<usize>,
|
|
||||||
) {
|
|
||||||
let top_dir = top_dir.as_ref();
|
|
||||||
let mut inodes: HashSet<(u64, u64)> = HashSet::new();
|
|
||||||
let mut iter = WalkDir::new(top_dir)
|
|
||||||
.preload_metadata(true)
|
|
||||||
.skip_hidden(false);
|
|
||||||
if let Some(threads_to_start) = threads {
|
|
||||||
iter = iter.num_threads(threads_to_start);
|
|
||||||
}
|
|
||||||
'entry: for entry in iter {
|
|
||||||
if let Ok(e) = entry {
|
|
||||||
let maybe_size_and_inode = get_metadata(&e, apparent_size);
|
|
||||||
if let Some(dirs) = ignore_directories {
|
|
||||||
let path = e.path();
|
|
||||||
let parts = path.components().collect::<Vec<std::path::Component>>();
|
|
||||||
for d in dirs {
|
|
||||||
let seq = d.components().collect::<Vec<std::path::Component>>();
|
|
||||||
if parts
|
|
||||||
.windows(seq.len())
|
|
||||||
.any(|window| window.iter().collect::<PathBuf>() == *d)
|
|
||||||
{
|
|
||||||
continue 'entry;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match maybe_size_and_inode {
|
|
||||||
Some((size, inode, device)) => {
|
|
||||||
if !should_ignore_file(apparent_size, filesystems, &mut inodes, inode, device) {
|
|
||||||
process_file_with_size_and_inode(top_dir, data, e, size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => *file_count_no_permission += 1,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*file_count_no_permission += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn should_ignore_file(
|
fn should_ignore_file(
|
||||||
apparent_size: bool,
|
apparent_size: bool,
|
||||||
restricted_filesystems: &Option<HashSet<u64>>,
|
|
||||||
inodes: &mut HashSet<(u64, u64)>,
|
inodes: &mut HashSet<(u64, u64)>,
|
||||||
inode: u64,
|
maybe_inode_device: Option<(u64, u64)>,
|
||||||
device: u64,
|
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Ignore files on different devices (if flag applied)
|
match maybe_inode_device {
|
||||||
if let Some(rs) = restricted_filesystems {
|
None => false,
|
||||||
if !rs.contains(&device) {
|
Some(data) => {
|
||||||
return true;
|
let (inode, device) = data;
|
||||||
}
|
if !apparent_size {
|
||||||
}
|
// Ignore files already visited or symlinked
|
||||||
|
if inodes.contains(&(inode, device)) {
|
||||||
if !apparent_size {
|
return true;
|
||||||
// Ignore files already visited or symlinked
|
}
|
||||||
if inodes.contains(&(inode, device)) {
|
inodes.insert((inode, device));
|
||||||
return true;
|
}
|
||||||
}
|
false
|
||||||
inodes.insert((inode, device));
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn process_file_with_size_and_inode<P: AsRef<Path>>(
|
|
||||||
top_dir: P,
|
|
||||||
data: &mut HashMap<PathBuf, u64>,
|
|
||||||
e: DirEntry,
|
|
||||||
size: u64,
|
|
||||||
) {
|
|
||||||
let top_dir = top_dir.as_ref();
|
|
||||||
// This path and all its parent paths have their counter incremented
|
|
||||||
for path in e.path().ancestors() {
|
|
||||||
// This is required due to bug in Jwalk that adds '/' to all sub dir lists
|
|
||||||
// see: https://github.com/jessegrosjean/jwalk/issues/13
|
|
||||||
if path.to_string_lossy() == "/" && top_dir.to_string_lossy() != "/" {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let s = data.entry(normalize_path(path)).or_insert(0);
|
|
||||||
*s += size;
|
|
||||||
if path.starts_with(top_dir) && top_dir.starts_with(path) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,36 +251,6 @@ pub fn find_big_ones(new_l: Vec<(PathBuf, u64)>, max_to_show: usize) -> Vec<(Pat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn depth_of_path(name: &PathBuf) -> usize {
|
|
||||||
// Filter required as paths can have some odd preliminary
|
|
||||||
// ("Prefix") bits (for example, from windows, "\\?\" or "\\UNC\")
|
|
||||||
name.components()
|
|
||||||
.filter(|&c| match c {
|
|
||||||
std::path::Component::Prefix(_) => false,
|
|
||||||
_ => true,
|
|
||||||
})
|
|
||||||
.count()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn trim_deep_ones(
|
|
||||||
input: Vec<(PathBuf, u64)>,
|
|
||||||
max_depth: u64,
|
|
||||||
top_level_names: &HashSet<PathBuf>,
|
|
||||||
) -> Vec<(PathBuf, u64)> {
|
|
||||||
let mut result: Vec<(PathBuf, u64)> = Vec::with_capacity(input.len() * top_level_names.len());
|
|
||||||
|
|
||||||
for name in top_level_names {
|
|
||||||
let my_max_depth = depth_of_path(name) + max_depth as usize;
|
|
||||||
|
|
||||||
for &(ref k, ref v) in input.iter() {
|
|
||||||
if k.starts_with(name) && depth_of_path(k) <= my_max_depth {
|
|
||||||
result.push((k.clone(), *v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
|
|
||||||
mod tests {
|
mod tests {
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -352,14 +337,14 @@ mod tests {
|
|||||||
let mut files = HashSet::new();
|
let mut files = HashSet::new();
|
||||||
files.insert((10, 20));
|
files.insert((10, 20));
|
||||||
|
|
||||||
assert!(!should_ignore_file(true, &None, &mut files, 0, 0));
|
assert!(!should_ignore_file(true, &mut files, Some((0, 0))));
|
||||||
|
|
||||||
// New file is not known it will be inserted to the hashmp and should not be ignored
|
// New file is not known it will be inserted to the hashmp and should not be ignored
|
||||||
assert!(!should_ignore_file(false, &None, &mut files, 11, 12));
|
assert!(!should_ignore_file(false, &mut files, Some((11, 12))));
|
||||||
assert!(files.contains(&(11, 12)));
|
assert!(files.contains(&(11, 12)));
|
||||||
|
|
||||||
// The same file will be ignored the second time
|
// The same file will be ignored the second time
|
||||||
assert!(should_ignore_file(false, &None, &mut files, 11, 12));
|
assert!(should_ignore_file(false, &mut files, Some((11, 12))));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -367,17 +352,8 @@ mod tests {
|
|||||||
let mut files = HashSet::new();
|
let mut files = HashSet::new();
|
||||||
files.insert((10, 20));
|
files.insert((10, 20));
|
||||||
|
|
||||||
let mut devices = HashSet::new();
|
|
||||||
devices.insert(99);
|
|
||||||
let od = Some(devices);
|
|
||||||
|
|
||||||
// If we are looking at a different device (disk) and the device flag is set
|
|
||||||
// then apparent_size is irrelevant - we ignore files on other devices
|
|
||||||
assert!(should_ignore_file(false, &od, &mut files, 11, 12));
|
|
||||||
assert!(should_ignore_file(true, &od, &mut files, 11, 12));
|
|
||||||
|
|
||||||
// We do not ignore files on the same device
|
// We do not ignore files on the same device
|
||||||
assert!(!should_ignore_file(false, &od, &mut files, 2, 99));
|
assert!(!should_ignore_file(false, &mut files, Some((2, 99))));
|
||||||
assert!(!should_ignore_file(true, &od, &mut files, 2, 99));
|
assert!(!should_ignore_file(true, &mut files, Some((2, 99))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+108
-36
@@ -1,8 +1,6 @@
|
|||||||
use jwalk::DirEntry;
|
use ignore::DirEntry;
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
fn get_block_size() -> u64 {
|
fn get_block_size() -> u64 {
|
||||||
@@ -12,45 +10,119 @@ fn get_block_size() -> u64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_family = "unix")]
|
#[cfg(target_family = "unix")]
|
||||||
pub fn get_metadata(d: &DirEntry, use_apparent_size: bool) -> Option<(u64, u64, u64)> {
|
pub fn get_metadata(d: &DirEntry, use_apparent_size: bool) -> Option<(u64, Option<(u64, u64)>)> {
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
d.metadata.as_ref().unwrap().as_ref().ok().map(|md| {
|
match d.metadata() {
|
||||||
if use_apparent_size {
|
Ok(md) => {
|
||||||
(md.len(), md.ino(), md.dev())
|
if use_apparent_size {
|
||||||
} else {
|
Some((md.len(), Some((md.ino(), md.dev()))))
|
||||||
(md.blocks() * get_block_size(), md.ino(), md.dev())
|
} else {
|
||||||
|
Some((md.blocks() * get_block_size(), Some((md.ino(), md.dev()))))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
Err(_e) => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_family = "windows")]
|
#[cfg(target_family = "windows")]
|
||||||
pub fn get_metadata(d: &DirEntry, _use_apparent_size: bool) -> Option<(u64, u64, u64)> {
|
pub fn get_metadata(d: &DirEntry, _use_apparent_size: bool) -> Option<(u64, Option<(u64, u64)>)> {
|
||||||
use winapi_util::file::information;
|
// On windows opening the file to get size, file ID and volume can be very
|
||||||
|
// expensive because 1) it causes a few system calls, and more importantly 2) it can cause
|
||||||
|
// windows defender to scan the file.
|
||||||
|
// Therefore we try to avoid doing that for common cases, mainly those of
|
||||||
|
// plain files:
|
||||||
|
|
||||||
|
// The idea is to make do with the file size that we get from the OS for
|
||||||
|
// free as part of iterating a folder. Therefore we want to make sure that
|
||||||
|
// it makes sense to use that free size information:
|
||||||
|
|
||||||
|
// Volume boundaries:
|
||||||
|
// The user can ask us not to cross volume boundaries. If the DirEntry is a
|
||||||
|
// plain file and not a reparse point or other non-trivial stuff, we assume
|
||||||
|
// that the file is located on the same volume as the directory that
|
||||||
|
// contains it.
|
||||||
|
|
||||||
|
// File ID:
|
||||||
|
// This optimization does deprive us of access to a file ID. As a
|
||||||
|
// workaround, we just make one up that hopefully does not collide with real
|
||||||
|
// file IDs.
|
||||||
|
// Hard links: Unresolved. We don't get inode/file index, so hard links
|
||||||
|
// count once for each link. Hopefully they are not too commonly in use on
|
||||||
|
// windows.
|
||||||
|
|
||||||
|
// Size:
|
||||||
|
// We assume (naively?) that for the common cases the free size info is the
|
||||||
|
// same as one would get by doing the expensive thing. Sparse, encrypted and
|
||||||
|
// compressed files are not included in the common cases, as one can image
|
||||||
|
// there being more than view on their size.
|
||||||
|
|
||||||
|
// Savings in orders of magnitude in terms of time, io and cpu have been
|
||||||
|
// observed on hdd, windows 10, some 100Ks files taking up some hundreds of
|
||||||
|
// GBs:
|
||||||
|
// Consistently opening the file: 30 minutes.
|
||||||
|
// With this optimization: 8 sec.
|
||||||
|
|
||||||
|
use std::io;
|
||||||
|
use std::path::Path;
|
||||||
use winapi_util::Handle;
|
use winapi_util::Handle;
|
||||||
|
fn handle_from_path_limited<P: AsRef<Path>>(path: P) -> io::Result<Handle> {
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::os::windows::fs::OpenOptionsExt;
|
||||||
|
const FILE_READ_ATTRIBUTES: u32 = 0x0080;
|
||||||
|
|
||||||
let h = Handle::from_path_any(d.path()).ok()?;
|
// So, it seems that it does does have to be that expensive to open
|
||||||
let info = information(&h).ok()?;
|
// files to get their info: Avoiding opening the file with the full
|
||||||
|
// GENERIC_READ is key:
|
||||||
|
|
||||||
Some((
|
// https://docs.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights:
|
||||||
info.file_size(),
|
// "For example, a Windows file object maps the GENERIC_READ bit to the
|
||||||
info.file_index(),
|
// READ_CONTROL and SYNCHRONIZE standard access rights and to the
|
||||||
info.volume_serial_number(),
|
// FILE_READ_DATA, FILE_READ_EA, and FILE_READ_ATTRIBUTES
|
||||||
))
|
// object-specific access rights"
|
||||||
}
|
|
||||||
|
// The flag FILE_READ_DATA seems to be the expensive one, so we'll avoid
|
||||||
#[cfg(target_family = "unix")]
|
// that, and a most of the other ones. Simply because it seems that we
|
||||||
pub fn get_filesystem<P: AsRef<Path>>(file_path: P) -> Result<u64, io::Error> {
|
// don't need them.
|
||||||
use std::os::unix::fs::MetadataExt;
|
|
||||||
let metadata = fs::metadata(file_path)?;
|
let file = OpenOptions::new()
|
||||||
Ok(metadata.dev())
|
.access_mode(FILE_READ_ATTRIBUTES)
|
||||||
}
|
.open(path)?;
|
||||||
|
Ok(Handle::from_file(file))
|
||||||
#[cfg(target_family = "windows")]
|
}
|
||||||
pub fn get_filesystem<P: AsRef<Path>>(file_path: P) -> Result<u64, io::Error> {
|
|
||||||
use winapi_util::file::information;
|
fn get_metadata_expensive(d: &DirEntry) -> Option<(u64, Option<(u64, u64)>)> {
|
||||||
use winapi_util::Handle;
|
use winapi_util::file::information;
|
||||||
|
|
||||||
let h = Handle::from_path_any(file_path)?;
|
let h = handle_from_path_limited(d.path()).ok()?;
|
||||||
let info = information(&h)?;
|
let info = information(&h).ok()?;
|
||||||
Ok(info.volume_serial_number())
|
|
||||||
|
Some((
|
||||||
|
info.file_size(),
|
||||||
|
Some((info.file_index(), info.volume_serial_number())),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::os::windows::fs::MetadataExt;
|
||||||
|
match d.metadata() {
|
||||||
|
Ok(ref md) => {
|
||||||
|
const FILE_ATTRIBUTE_ARCHIVE: u32 = 0x20u32;
|
||||||
|
const FILE_ATTRIBUTE_READONLY: u32 = 0x1u32;
|
||||||
|
const FILE_ATTRIBUTE_HIDDEN: u32 = 0x2u32;
|
||||||
|
const FILE_ATTRIBUTE_SYSTEM: u32 = 0x4u32;
|
||||||
|
const FILE_ATTRIBUTE_NORMAL: u32 = 0x80u32;
|
||||||
|
const FILE_ATTRIBUTE_DIRECTORY: u32 = 0x10u32;
|
||||||
|
|
||||||
|
let attr_filtered = md.file_attributes()
|
||||||
|
& !(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM);
|
||||||
|
if attr_filtered == FILE_ATTRIBUTE_ARCHIVE
|
||||||
|
|| attr_filtered == FILE_ATTRIBUTE_DIRECTORY
|
||||||
|
|| md.file_attributes() == FILE_ATTRIBUTE_NORMAL
|
||||||
|
{
|
||||||
|
Some((md.len(), None))
|
||||||
|
} else {
|
||||||
|
get_metadata_expensive(&d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => get_metadata_expensive(&d),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
hi
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
use assert_cmd::Command;
|
||||||
|
use std::str;
|
||||||
|
use std::sync::Once;
|
||||||
|
|
||||||
|
static INIT: Once = Once::new();
|
||||||
|
|
||||||
|
mod tests_symlinks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This file contains tests that verify the exact output of the command.
|
||||||
|
* This output differs on Linux / Mac so the tests are harder to write and debug
|
||||||
|
* Windows is ignored here because the results vary by host making exact testing impractical
|
||||||
|
*
|
||||||
|
* Despite the above problems, these tests are good as they are the closest to 'the real thing'.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Warning: File sizes differ on both platform and on the format of the disk.
|
||||||
|
/// Copy to /tmp dir - we assume that the formatting of the /tmp partition
|
||||||
|
/// is consistent. If the tests fail your /tmp filesystem probably differs
|
||||||
|
fn copy_test_data(dir: &str) {
|
||||||
|
// First remove the existing directory - just incase it is there and has incorrect data
|
||||||
|
let last_slash = dir.rfind('/').unwrap();
|
||||||
|
let last_part_of_dir = dir.chars().skip(last_slash).collect::<String>();
|
||||||
|
match Command::new("rm")
|
||||||
|
.arg("-rf")
|
||||||
|
.arg("/tmp/".to_owned() + &*last_part_of_dir)
|
||||||
|
.ok()
|
||||||
|
{
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_) => {}
|
||||||
|
};
|
||||||
|
match Command::new("cp").arg("-r").arg(dir).arg("/tmp/").ok() {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Error copying directory {:?}", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initialize() {
|
||||||
|
INIT.call_once(|| {
|
||||||
|
copy_test_data("tests/test_dir");
|
||||||
|
copy_test_data("tests/test_dir2");
|
||||||
|
copy_test_data("tests/test_dir_unicode");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// "windows" result data can vary by host (size seems to be variable by one byte); fix code vs test and re-enable
|
||||||
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
|
#[test]
|
||||||
|
pub fn test_main_basic() {
|
||||||
|
// -c is no color mode - This makes testing much simpler
|
||||||
|
initialize();
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let assert = cmd.arg("-c").arg("/tmp/test_dir/").unwrap().stdout;
|
||||||
|
let output = str::from_utf8(&assert).unwrap();
|
||||||
|
assert!(output.contains(&main_output()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
|
#[test]
|
||||||
|
pub fn test_main_multi_arg() {
|
||||||
|
initialize();
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let assert = cmd
|
||||||
|
.arg("-c")
|
||||||
|
.arg("/tmp/test_dir/many/")
|
||||||
|
.arg("/tmp/test_dir")
|
||||||
|
.arg("/tmp/test_dir")
|
||||||
|
.unwrap()
|
||||||
|
.stdout;
|
||||||
|
let output = str::from_utf8(&assert).unwrap();
|
||||||
|
assert!(output.contains(&main_output()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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%
|
||||||
|
"#
|
||||||
|
.trim()
|
||||||
|
.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%
|
||||||
|
"#
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn main_output() -> String {
|
||||||
|
"windows results vary by host".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
|
#[test]
|
||||||
|
pub fn test_main_long_paths() {
|
||||||
|
initialize();
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let assert = cmd
|
||||||
|
.arg("-c")
|
||||||
|
.arg("-p")
|
||||||
|
.arg("/tmp/test_dir/")
|
||||||
|
.unwrap()
|
||||||
|
.stdout;
|
||||||
|
let output = str::from_utf8(&assert).unwrap();
|
||||||
|
println!("{:?}", output.trim());
|
||||||
|
println!("{:?}", main_output_long_paths().trim());
|
||||||
|
assert!(output.contains(&main_output_long_paths()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn main_output_long_paths() -> String {
|
||||||
|
r#"
|
||||||
|
0B ┌── /tmp/test_dir/many/a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||||
|
4.0K ├── /tmp/test_dir/many/hello_file│█████████████████████████████ │ 100%
|
||||||
|
4.0K ┌─┴ /tmp/test_dir/many │█████████████████████████████ │ 100%
|
||||||
|
4.0K ┌─┴ /tmp/test_dir │█████████████████████████████ │ 100%
|
||||||
|
"#
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn main_output_long_paths() -> String {
|
||||||
|
r#"
|
||||||
|
0B ┌── /tmp/test_dir/many/a_file │ ░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||||
|
4.0K ├── /tmp/test_dir/many/hello_file│ ░░░░░░░░░░██████████ │ 33%
|
||||||
|
8.0K ┌─┴ /tmp/test_dir/many │ ████████████████████ │ 67%
|
||||||
|
12K ┌─┴ /tmp/test_dir │█████████████████████████████ │ 100%
|
||||||
|
"#
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn main_output_long_paths() -> String {
|
||||||
|
"windows results vary by host".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
|
#[test]
|
||||||
|
pub fn test_apparent_size() {
|
||||||
|
initialize();
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let assert = cmd.arg("-c").arg("-s").arg("/tmp/test_dir").unwrap().stdout;
|
||||||
|
let output = str::from_utf8(&assert).unwrap();
|
||||||
|
assert!(output.contains(&output_apparent_size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn output_apparent_size() -> String {
|
||||||
|
r#"
|
||||||
|
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||||
|
6B ├── hello_file│ ░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||||
|
4.0K ┌─┴ many │ █████████████████████████ │ 50%
|
||||||
|
8.0K ┌─┴ test_dir │████████████████████████████████████████████████ │ 100%
|
||||||
|
"#
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn output_apparent_size() -> String {
|
||||||
|
r#"
|
||||||
|
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||||
|
6B ├── hello_file│ ░░░░░░░░░░░░░░░░░░░░░░░░░░██ │ 3%
|
||||||
|
134B ┌─┴ many │ ████████████████████████████ │ 58%
|
||||||
|
230B ┌─┴ test_dir │████████████████████████████████████████████████ │ 100%
|
||||||
|
"#
|
||||||
|
.trim()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn output_apparent_size() -> String {
|
||||||
|
"windows results vary by host".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check against directories and files whos names are substrings of each other
|
||||||
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
|
#[test]
|
||||||
|
pub fn test_substring_of_names_and_long_names() {
|
||||||
|
initialize();
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd.arg("-c").arg("/tmp/test_dir2").unwrap().stdout;
|
||||||
|
let output = str::from_utf8(&output).unwrap();
|
||||||
|
assert!(output.contains(&no_substring_of_names_output()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn no_substring_of_names_output() -> String {
|
||||||
|
"
|
||||||
|
0B ┌── long_dir_name_what_a_very_long_dir_name_what_happens_when_this_g..
|
||||||
|
4.0K ├── dir_name_clash
|
||||||
|
4.0K │ ┌── hello
|
||||||
|
8.0K ├─┴ dir_substring
|
||||||
|
4.0K │ ┌── hello
|
||||||
|
8.0K ├─┴ dir
|
||||||
|
24K ┌─┴ test_dir2
|
||||||
|
"
|
||||||
|
.trim()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn no_substring_of_names_output() -> String {
|
||||||
|
"
|
||||||
|
0B ┌── long_dir_name_what_a_very_long_dir_name_what_happens_when_this_g..
|
||||||
|
4.0K │ ┌── hello
|
||||||
|
4.0K ├─┴ dir_substring
|
||||||
|
4.0K ├── dir_name_clash
|
||||||
|
4.0K │ ┌── hello
|
||||||
|
4.0K ├─┴ dir
|
||||||
|
12K ┌─┴ test_dir2
|
||||||
|
"
|
||||||
|
.trim()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn no_substring_of_names_output() -> String {
|
||||||
|
"PRs".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
|
#[test]
|
||||||
|
pub fn test_unicode_directories() {
|
||||||
|
initialize();
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd.arg("-c").arg("/tmp/test_dir_unicode").unwrap().stdout;
|
||||||
|
let output = str::from_utf8(&output).unwrap();
|
||||||
|
assert!(output.contains(&unicode_dir()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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_dir_unicode │██████████████████████████████████ │ 100%
|
||||||
|
"
|
||||||
|
.trim()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn unicode_dir() -> String {
|
||||||
|
"
|
||||||
|
0B ┌── 👩.unicode │ █ │ 0%
|
||||||
|
0B ├── ラウトは難しいです!.japan│ █ │ 0%
|
||||||
|
0B ┌─┴ test_dir_unicode │ █ │ 0%
|
||||||
|
"
|
||||||
|
.trim()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn unicode_dir() -> String {
|
||||||
|
"".into()
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
use assert_cmd::Command;
|
||||||
|
use std::str;
|
||||||
|
/**
|
||||||
|
* This file contains tests that test a substring of the output using '.contains'
|
||||||
|
*
|
||||||
|
* These tests should be the same cross platform
|
||||||
|
*/
|
||||||
|
|
||||||
|
// We can at least test the file names are there
|
||||||
|
#[test]
|
||||||
|
pub fn test_basic_output() {
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd.arg("tests/test_dir/").unwrap().stdout;
|
||||||
|
let output = str::from_utf8(&output).unwrap();
|
||||||
|
|
||||||
|
assert!(output.contains(" ┌─┴ "));
|
||||||
|
assert!(output.contains("test_dir "));
|
||||||
|
assert!(output.contains(" ┌─┴ "));
|
||||||
|
assert!(output.contains("many "));
|
||||||
|
assert!(output.contains(" ├── "));
|
||||||
|
assert!(output.contains("hello_file"));
|
||||||
|
assert!(output.contains(" ┌── "));
|
||||||
|
assert!(output.contains("a_file "));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_output_no_bars_means_no_excess_spaces() {
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd.arg("-b").arg("tests/test_dir/").unwrap().stdout;
|
||||||
|
let output = str::from_utf8(&output).unwrap();
|
||||||
|
// If bars are not being shown we don't need to pad the output with spaces
|
||||||
|
assert!(output.contains("many"));
|
||||||
|
assert!(!output.contains("many "));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_reverse_flag() {
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd
|
||||||
|
.arg("-c")
|
||||||
|
.arg("-r")
|
||||||
|
.arg("tests/test_dir/")
|
||||||
|
.unwrap()
|
||||||
|
.stdout;
|
||||||
|
let output = str::from_utf8(&output).unwrap();
|
||||||
|
|
||||||
|
assert!(output.contains(" └─┬ test_dir "));
|
||||||
|
assert!(output.contains(" └─┬ many "));
|
||||||
|
assert!(output.contains(" ├── hello_file"));
|
||||||
|
assert!(output.contains(" └── a_file "));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_d_flag_works() {
|
||||||
|
// We should see the top level directory but not the sub dirs / files:
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd
|
||||||
|
.arg("-d")
|
||||||
|
.arg("1")
|
||||||
|
.arg("-s")
|
||||||
|
.arg("tests/test_dir/")
|
||||||
|
.unwrap()
|
||||||
|
.stdout;
|
||||||
|
let output = str::from_utf8(&output).unwrap();
|
||||||
|
assert!(!output.contains("hello_file"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check against directories and files whos names are substrings of each other
|
||||||
|
#[test]
|
||||||
|
pub fn test_ignore_dir() {
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd
|
||||||
|
.arg("-c")
|
||||||
|
.arg("-X")
|
||||||
|
.arg("dir_substring")
|
||||||
|
.arg("tests/test_dir2")
|
||||||
|
.unwrap()
|
||||||
|
.stdout;
|
||||||
|
let output = str::from_utf8(&output).unwrap();
|
||||||
|
assert!(!output.contains("dir_substring"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_with_bad_param() {
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let stderr = cmd.arg("-").unwrap().stderr;
|
||||||
|
let stderr = str::from_utf8(&stderr).unwrap();
|
||||||
|
assert!(stderr.contains("Did not have permissions for all directories"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_hidden_flag() {
|
||||||
|
// Check we can see the hidden file normally
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd
|
||||||
|
.arg("-c")
|
||||||
|
.arg("tests/test_dir_hidden_entries")
|
||||||
|
.unwrap()
|
||||||
|
.stdout;
|
||||||
|
let output = str::from_utf8(&output).unwrap();
|
||||||
|
assert!(output.contains(".hidden_file"));
|
||||||
|
assert!(output.contains("┌─┴ test_dir_hidden_entries"));
|
||||||
|
|
||||||
|
// Check that adding the '-h' flag causes us to not see hidden files
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd
|
||||||
|
.arg("-c")
|
||||||
|
.arg("-i")
|
||||||
|
.arg("tests/test_dir_hidden_entries")
|
||||||
|
.unwrap()
|
||||||
|
.stdout;
|
||||||
|
let output = str::from_utf8(&output).unwrap();
|
||||||
|
assert!(!output.contains(".hidden_file"));
|
||||||
|
assert!(output.contains("┌── test_dir_hidden_entries"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_number_of_files() {
|
||||||
|
// Check we can see the hidden file normally
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd
|
||||||
|
.arg("-c")
|
||||||
|
.arg("-f")
|
||||||
|
.arg("tests/test_dir")
|
||||||
|
.unwrap()
|
||||||
|
.stdout;
|
||||||
|
let output = str::from_utf8(&output).unwrap();
|
||||||
|
assert!(output.contains("1 ┌── hello_file"));
|
||||||
|
assert!(output.contains("1 ├── a_file "));
|
||||||
|
assert!(output.contains("3 ┌─┴ many"));
|
||||||
|
assert!(output.contains("4 ┌─┴ test_dir"));
|
||||||
|
}
|
||||||
-258
@@ -1,259 +1 @@
|
|||||||
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();
|
|
||||||
}
|
|
||||||
|
|||||||
+55
-41
@@ -1,14 +1,42 @@
|
|||||||
|
use assert_cmd::Command;
|
||||||
|
use std::cmp::max;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::panic;
|
use std::panic;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::str;
|
||||||
|
|
||||||
|
use terminal_size::{terminal_size, Height, Width};
|
||||||
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use tempfile::Builder;
|
use tempfile::Builder;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
// File sizes differ on both platform and on the format of the disk.
|
// 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
|
// Windows: `ln` is not usually an available command; creation of symbolic links requires special enhanced permissions
|
||||||
|
|
||||||
|
fn get_width_of_terminal() -> u16 {
|
||||||
|
if let Some((Width(w), Height(_h))) = terminal_size() {
|
||||||
|
max(w, 80)
|
||||||
|
} else {
|
||||||
|
80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mac test runners create tmp files with very long names, hence it may be shortened in the output
|
||||||
|
fn get_file_name(name: String) -> String {
|
||||||
|
let terminal_plus_buffer = (get_width_of_terminal() - 14) as usize;
|
||||||
|
if UnicodeWidthStr::width(&*name) > terminal_plus_buffer {
|
||||||
|
let trimmed_name = name
|
||||||
|
.chars()
|
||||||
|
.take(terminal_plus_buffer - 2)
|
||||||
|
.collect::<String>();
|
||||||
|
trimmed_name + ".."
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn build_temp_file(dir: &TempDir) -> PathBuf {
|
fn build_temp_file(dir: &TempDir) -> PathBuf {
|
||||||
let file_path = dir.path().join("notes.txt");
|
let file_path = dir.path().join("notes.txt");
|
||||||
let mut file = File::create(&file_path).unwrap();
|
let mut file = File::create(&file_path).unwrap();
|
||||||
@@ -33,19 +61,18 @@ pub fn test_soft_sym_link() {
|
|||||||
.output();
|
.output();
|
||||||
assert!(c.is_ok());
|
assert!(c.is_ok());
|
||||||
|
|
||||||
let c = format!(" ┌── {}", link_name_s);
|
let c = format!(" ┌── {}", get_file_name(link_name_s.into()));
|
||||||
let b = format!(" ├── {}", file_path_s);
|
let b = format!(" ├── {}", get_file_name(file_path_s.into()));
|
||||||
let a = format!("─┴ {}", dir_s);
|
let a = format!("─┴ {}", dir_s);
|
||||||
|
|
||||||
assert_cli::Assert::main_binary()
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
.with_args(&["-p", &dir_s])
|
let output = cmd.arg("-p").arg("-c").arg(dir_s).unwrap().stdout;
|
||||||
.stdout()
|
|
||||||
.contains(a.as_str())
|
let output = str::from_utf8(&output).unwrap();
|
||||||
.stdout()
|
|
||||||
.contains(b.as_str())
|
assert!(output.contains(a.as_str()));
|
||||||
.stdout()
|
assert!(output.contains(b.as_str()));
|
||||||
.contains(c.as_str())
|
assert!(output.contains(c.as_str()));
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(target_os = "windows", ignore)]
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
@@ -64,30 +91,18 @@ pub fn test_hard_sym_link() {
|
|||||||
.output();
|
.output();
|
||||||
assert!(c.is_ok());
|
assert!(c.is_ok());
|
||||||
|
|
||||||
let a = format!("─┴ {}", dir_s);
|
let link_output = format!(" ┌── {}", get_file_name(link_name_s.into()));
|
||||||
let b = format!(" ┌── {}", link_name_s);
|
let file_output = format!(" ┌── {}", get_file_name(file_path_s.into()));
|
||||||
let b2 = format!(" ┌── {}", file_path_s);
|
let dirs_output = format!("─┴ {}", dir_s);
|
||||||
|
|
||||||
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
|
let output = cmd.arg("-p").arg("-c").arg(dir_s).unwrap().stdout;
|
||||||
|
|
||||||
// Because this is a hard link the file and hard link look identical. Therefore
|
// Because this is a hard link the file and hard link look identical. Therefore
|
||||||
// we cannot guarantee which version will appear first.
|
// we cannot guarantee which version will appear first.
|
||||||
let result = panic::catch_unwind(|| {
|
let output = str::from_utf8(&output).unwrap();
|
||||||
assert_cli::Assert::main_binary()
|
assert!(output.contains(dirs_output.as_str()));
|
||||||
.with_args(&["-p", dir_s])
|
assert!(output.contains(link_output.as_str()) || output.contains(file_output.as_str()));
|
||||||
.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)]
|
#[cfg_attr(target_os = "windows", ignore)]
|
||||||
@@ -107,13 +122,12 @@ pub fn test_recursive_sym_link() {
|
|||||||
assert!(c.is_ok());
|
assert!(c.is_ok());
|
||||||
|
|
||||||
let a = format!("─┬ {}", dir_s);
|
let a = format!("─┬ {}", dir_s);
|
||||||
let b = format!(" └── {}", link_name_s);
|
let b = format!(" └── {}", get_file_name(link_name_s.into()));
|
||||||
|
|
||||||
assert_cli::Assert::main_binary()
|
let mut cmd = Command::cargo_bin("dust").unwrap();
|
||||||
.with_args(&["-r", "-p", dir_s])
|
let output = cmd.arg("-p").arg("-c").arg("-r").arg(dir_s).unwrap().stdout;
|
||||||
.stdout()
|
|
||||||
.contains(a.as_str())
|
let output = str::from_utf8(&output).unwrap();
|
||||||
.stdout()
|
assert!(output.contains(a.as_str()));
|
||||||
.contains(b.as_str())
|
assert!(output.contains(b.as_str()));
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user