mirror of
https://github.com/bootandy/dust.git
synced 2025-12-07 05:10:40 -08:00
Compare commits
143 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc0e376c88 | ||
|
|
d7c602a2d2 | ||
|
|
603e6be7eb | ||
|
|
efa469e12f | ||
|
|
657858df16 | ||
|
|
a8d700d530 | ||
|
|
c408d8887d | ||
|
|
be2250d241 | ||
|
|
b6aa1378de | ||
|
|
2082141dfc | ||
|
|
8a9b5e889d | ||
|
|
871b7e90d8 | ||
|
|
edf300893c | ||
|
|
a3d8fc00e1 | ||
|
|
9d4531d48b | ||
|
|
75e419e7ed | ||
|
|
4a62fc5726 | ||
|
|
d2b959fdcf | ||
|
|
36ebb1b2b0 | ||
|
|
e126a01096 | ||
|
|
7a38a26593 | ||
|
|
1af6e1f757 | ||
|
|
affafcc5f2 | ||
|
|
26ef8c3e59 | ||
|
|
0898ee6bf0 | ||
|
|
5ac168868e | ||
|
|
684994ee11 | ||
|
|
416ad517fe | ||
|
|
7c34389aea | ||
|
|
18510130d8 | ||
|
|
0bf8c914b7 | ||
|
|
95888d5f31 | ||
|
|
5d195e27cb | ||
|
|
0c7b05fec9 | ||
|
|
bc895879e6 | ||
|
|
31f01c061a | ||
|
|
17894e723c | ||
|
|
6141ddddea | ||
|
|
352c0f7d90 | ||
|
|
842a8ec673 | ||
|
|
d97edba041 | ||
|
|
f64e0094f1 | ||
|
|
3d2477e554 | ||
|
|
350d695f7c | ||
|
|
f8b8b8a788 | ||
|
|
b9c27f9838 | ||
|
|
5541df6a73 | ||
|
|
bdc3d404ef | ||
|
|
f395a7d768 | ||
|
|
a36eec6cae | ||
|
|
38938e005e | ||
|
|
da61b15715 | ||
|
|
0b22d0a977 | ||
|
|
356d14ac0f | ||
|
|
311bc45388 | ||
|
|
ef66fb3938 | ||
|
|
b934445e04 | ||
|
|
a6839c020f | ||
|
|
7e47d5b47a | ||
|
|
6a65570f3f | ||
|
|
a4ca78dbe4 | ||
|
|
bfbe8a57ae | ||
|
|
b4b73e45f3 | ||
|
|
78119aba0f | ||
|
|
5535478fe8 | ||
|
|
7ba91a4a22 | ||
|
|
79416fd5fc | ||
|
|
b66523cff3 | ||
|
|
19a41aa382 | ||
|
|
62ac9b623a | ||
|
|
bf28d42483 | ||
|
|
f8ce6c97bf | ||
|
|
86b3cccaf6 | ||
|
|
3c920431fa | ||
|
|
a1ece05af5 | ||
|
|
cef2c588b7 | ||
|
|
7d8e498238 | ||
|
|
53c7a69dcb | ||
|
|
9a9cbefd3d | ||
|
|
224a2c6f25 | ||
|
|
99003cbba9 | ||
|
|
c83803b440 | ||
|
|
a41862d799 | ||
|
|
6ab46d8471 | ||
|
|
c727eb2d11 | ||
|
|
0effaa7fd7 | ||
|
|
25c50f88c4 | ||
|
|
0c19a66432 | ||
|
|
4cffc4370b | ||
|
|
db6c8a019d | ||
|
|
e03094a4fa | ||
|
|
1d9a56e025 | ||
|
|
ec2d9e19d4 | ||
|
|
9fbfcb275a | ||
|
|
1c60d1e2ac | ||
|
|
fd35734a94 | ||
|
|
c6f4ace2b6 | ||
|
|
d46b63fad8 | ||
|
|
872a49bb7d | ||
|
|
04c6c204c3 | ||
|
|
7ac01e8166 | ||
|
|
2f7a88e8dc | ||
|
|
2ca2cebdad | ||
|
|
80338f4731 | ||
|
|
d327bd2e68 | ||
|
|
7db6cf2f32 | ||
|
|
76d0762c97 | ||
|
|
6e03dd77e6 | ||
|
|
4906e9efda | ||
|
|
876609f2cb | ||
|
|
12775db94b | ||
|
|
bfaf5ee173 | ||
|
|
fd68330815 | ||
|
|
0bf4ebf554 | ||
|
|
cab24f58d5 | ||
|
|
b1b933d851 | ||
|
|
6a86e8befd | ||
|
|
3fb91a6c29 | ||
|
|
51561994c5 | ||
|
|
ce0e14bf00 | ||
|
|
dd75ec4aa7 | ||
|
|
65cd42736a | ||
|
|
4792e97177 | ||
|
|
3e9f09e339 | ||
|
|
dba465a094 | ||
|
|
25d1ee7b43 | ||
|
|
2556885622 | ||
|
|
8c088a7026 | ||
|
|
39db8b86fd | ||
|
|
c5830c5d00 | ||
|
|
b68c450710 | ||
|
|
6e2e5761d8 | ||
|
|
6842526d2c | ||
|
|
4ac85d7dc9 | ||
|
|
8170a07886 | ||
|
|
0f1f823736 | ||
|
|
e6c777fb8b | ||
|
|
0bded9698a | ||
|
|
c7f0ea59f0 | ||
|
|
6d62cfb9ae | ||
|
|
803934d84b | ||
|
|
24c97ef92f | ||
|
|
270edf0a76 |
286
.github/workflows/CICD.yml
vendored
Normal file
286
.github/workflows/CICD.yml
vendored
Normal file
@@ -0,0 +1,286 @@
|
||||
name: CICD
|
||||
|
||||
# spell-checker:ignore CICD CODECOV MSVC MacOS Peltoche SHAs buildable clippy esac fakeroot gnueabihf halium libssl mkdir musl popd printf pushd rustfmt softprops toolchain
|
||||
|
||||
env:
|
||||
PROJECT_NAME: dust
|
||||
PROJECT_DESC: "du + rust = dust"
|
||||
PROJECT_AUTH: "bootandy"
|
||||
RUST_MIN_SRV: "1.31.0"
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
style:
|
||||
name: Style
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
- { os: ubuntu-latest }
|
||||
- { os: macos-latest }
|
||||
- { os: windows-latest }
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
# 'windows-latest' `cargo fmt` is bugged for this project (see reasons @ GH:rust-lang/rustfmt #3324, #3590, #3688 ; waiting for repair)
|
||||
JOB_DO_FORMAT_TESTING="true"
|
||||
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}
|
||||
- name: Install `rust` toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
components: rustfmt, clippy
|
||||
- name: "`fmt` testing"
|
||||
if: steps.vars.outputs.JOB_DO_FORMAT_TESTING
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
- name: "`clippy` testing"
|
||||
if: success() || failure() # run regardless of prior step ("`fmt` testing") success/failure
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: clippy
|
||||
args: ${{ matrix.job.cargo-options }} --features "${{ matrix.job.features }}" -- -D warnings
|
||||
|
||||
min_version:
|
||||
name: MinSRV # Minimum supported rust version
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install `rust` toolchain (v${{ env.RUST_MIN_SRV }})
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ env.RUST_MIN_SRV }}
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
job:
|
||||
# { os, target, cargo-options, features, use-cross, toolchain }
|
||||
- { os: ubuntu-latest , target: arm-unknown-linux-gnueabihf , use-cross: use-cross }
|
||||
- { os: ubuntu-18.04 , target: i686-unknown-linux-gnu , use-cross: use-cross }
|
||||
- { os: ubuntu-18.04 , target: i686-unknown-linux-musl , use-cross: use-cross }
|
||||
- { os: ubuntu-18.04 , target: x86_64-unknown-linux-gnu , use-cross: use-cross }
|
||||
- { os: ubuntu-18.04 , target: x86_64-unknown-linux-musl , use-cross: use-cross }
|
||||
- { os: ubuntu-16.04 , target: x86_64-unknown-linux-gnu , use-cross: use-cross }
|
||||
- { os: macos-latest , target: x86_64-apple-darwin }
|
||||
- { os: windows-latest , target: i686-pc-windows-gnu }
|
||||
- { os: windows-latest , target: i686-pc-windows-msvc }
|
||||
- { os: windows-latest , target: x86_64-pc-windows-gnu } ## !maint: [rivy; 2020-01-21] may break due to rust bug; follow possible solution from GH:rust-lang/rust#47048 (refs: GH:rust-lang/rust#47048 , GH:rust-lang/rust#53454 , GH:bike-barn/hermit#172 )
|
||||
- { os: windows-latest , target: x86_64-pc-windows-msvc }
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Install any prerequisites
|
||||
shell: bash
|
||||
run: |
|
||||
case ${{ matrix.job.target }} in
|
||||
arm-unknown-linux-gnueabihf) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
|
||||
esac
|
||||
- name: Initialize workflow variables
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
# toolchain
|
||||
TOOLCHAIN="stable" ## default to "stable" toolchain
|
||||
# * specify alternate TOOLCHAIN for *-pc-windows-gnu targets; gnu targets on Windows are broken for the standard *-pc-windows-msvc toolchain (refs: <https://github.com/rust-lang/rust/issues/47048>, <https://github.com/rust-lang/rust/issues/53454>, <https://github.com/rust-lang/cargo/issues/6754>)
|
||||
case ${{ matrix.job.target }} in *-pc-windows-gnu) TOOLCHAIN="stable-${{ matrix.job.target }}" ;; esac;
|
||||
# * use requested TOOLCHAIN if specified
|
||||
if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi
|
||||
echo set-output name=TOOLCHAIN::${TOOLCHAIN}
|
||||
echo ::set-output name=TOOLCHAIN::${TOOLCHAIN}
|
||||
# staging directory
|
||||
STAGING='_staging'
|
||||
echo set-output name=STAGING::${STAGING}
|
||||
echo ::set-output name=STAGING::${STAGING}
|
||||
# determine EXE suffix
|
||||
EXE_suffix="" ; case ${{ matrix.job.target }} in *-pc-windows-*) EXE_suffix=".exe" ;; esac;
|
||||
echo set-output name=EXE_suffix::${EXE_suffix}
|
||||
echo ::set-output name=EXE_suffix::${EXE_suffix}
|
||||
# parse commit reference info
|
||||
REF_NAME=${GITHUB_REF#refs/*/}
|
||||
unset REF_BRANCH ; case ${GITHUB_REF} in refs/heads/*) REF_BRANCH=${GITHUB_REF#refs/heads/} ;; esac;
|
||||
unset REF_TAG ; case ${GITHUB_REF} in refs/tags/*) REF_TAG=${GITHUB_REF#refs/tags/} ;; esac;
|
||||
REF_SHAS=${GITHUB_SHA:0:8}
|
||||
echo set-output name=REF_NAME::${REF_NAME}
|
||||
echo set-output name=REF_BRANCH::${REF_BRANCH}
|
||||
echo set-output name=REF_TAG::${REF_TAG}
|
||||
echo set-output name=REF_SHAS::${REF_SHAS}
|
||||
echo ::set-output name=REF_NAME::${REF_NAME}
|
||||
echo ::set-output name=REF_BRANCH::${REF_BRANCH}
|
||||
echo ::set-output name=REF_TAG::${REF_TAG}
|
||||
echo ::set-output name=REF_SHAS::${REF_SHAS}
|
||||
# parse target
|
||||
unset TARGET_ARCH ; case ${{ matrix.job.target }} in arm-unknown-linux-gnueabihf) TARGET_ARCH=arm ;; i686-*) TARGET_ARCH=i686 ;; x86_64-*) TARGET_ARCH=x86_64 ;; esac;
|
||||
echo set-output name=TARGET_ARCH::${TARGET_ARCH}
|
||||
echo ::set-output name=TARGET_ARCH::${TARGET_ARCH}
|
||||
unset TARGET_OS ; case ${{ matrix.job.target }} in *-linux-*) TARGET_OS=linux ;; *-apple-*) TARGET_OS=macos ;; *-windows-*) TARGET_OS=windows ;; esac;
|
||||
echo set-output name=TARGET_OS::${TARGET_OS}
|
||||
echo ::set-output name=TARGET_OS::${TARGET_OS}
|
||||
# package name
|
||||
PKG_suffix=".tar.gz" ; case ${{ matrix.job.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
|
||||
PKG_BASENAME=${PROJECT_NAME}-${REF_TAG:-$REF_SHAS}-${{ matrix.job.target }}
|
||||
PKG_NAME=${PKG_BASENAME}${PKG_suffix}
|
||||
echo set-output name=PKG_suffix::${PKG_suffix}
|
||||
echo set-output name=PKG_BASENAME::${PKG_BASENAME}
|
||||
echo set-output name=PKG_NAME::${PKG_NAME}
|
||||
echo ::set-output name=PKG_suffix::${PKG_suffix}
|
||||
echo ::set-output name=PKG_BASENAME::${PKG_BASENAME}
|
||||
echo ::set-output name=PKG_NAME::${PKG_NAME}
|
||||
# deployable tag? (ie, leading "vM" or "M"; M == version number)
|
||||
unset DEPLOY ; if [[ $REF_TAG =~ ^[vV]?[0-9].* ]]; then DEPLOY='true' ; fi
|
||||
echo set-output name=DEPLOY::${DEPLOY:-<empty>/false}
|
||||
echo ::set-output name=DEPLOY::${DEPLOY}
|
||||
# target-specific options
|
||||
# * CARGO_USE_CROSS (truthy)
|
||||
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}
|
||||
# # * `arm` cannot be tested on ubuntu-* hosts (b/c testing is currently primarily done via comparison of target outputs with built-in outputs and the `arm` target is not executable on the host)
|
||||
JOB_DO_TESTING="true"
|
||||
case ${{ matrix.job.target }} in arm-*) unset JOB_DO_TESTING ;; esac;
|
||||
echo set-output name=JOB_DO_TESTING::${JOB_DO_TESTING:-<empty>/false}
|
||||
echo ::set-output name=JOB_DO_TESTING::${JOB_DO_TESTING}
|
||||
# # * test only binary for arm-type targets
|
||||
unset CARGO_TEST_OPTIONS
|
||||
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-*) CARGO_TEST_OPTIONS="--bin ${PROJECT_NAME}" ;; esac;
|
||||
echo set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
|
||||
echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
|
||||
# * strip executable?
|
||||
STRIP="strip" ; case ${{ matrix.job.target }} in arm-unknown-linux-gnueabihf) STRIP="arm-linux-gnueabihf-strip" ;; *-pc-windows-msvc) STRIP="" ;; esac;
|
||||
echo set-output name=STRIP::${STRIP}
|
||||
echo ::set-output name=STRIP::${STRIP}
|
||||
- name: Create all needed build/work directories
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p '${{ steps.vars.outputs.STAGING }}'
|
||||
mkdir -p '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}'
|
||||
- name: rust toolchain ~ install
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: ${{ steps.vars.outputs.TOOLCHAIN }}
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
- name: Info
|
||||
shell: bash
|
||||
run: |
|
||||
gcc --version || true
|
||||
rustup -V
|
||||
rustup toolchain list
|
||||
rustup default
|
||||
cargo -V
|
||||
rustc -V
|
||||
- name: Build
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
||||
command: build
|
||||
args: --release --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} --features "${{ matrix.job.features }}"
|
||||
- name: Test
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
use-cross: ${{ steps.vars.outputs.CARGO_USE_CROSS }}
|
||||
command: test
|
||||
args: --target=${{ matrix.job.target }} ${{ steps.vars.outputs.CARGO_TEST_OPTIONS}} ${{ matrix.job.cargo-options }} --features "${{ matrix.job.features }}"
|
||||
- name: Archive executable artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: ${{ env.PROJECT_NAME }}-${{ matrix.job.target }}
|
||||
path: target/${{ matrix.job.target }}/release/${{ env.PROJECT_NAME }}${{ steps.vars.outputs.EXE_suffix }}
|
||||
- name: Package
|
||||
shell: bash
|
||||
run: |
|
||||
# binary
|
||||
cp 'target/${{ matrix.job.target }}/release/${{ env.PROJECT_NAME }}${{ steps.vars.outputs.EXE_suffix }}' '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/'
|
||||
# `strip` binary (if needed)
|
||||
if [ -n "${{ steps.vars.outputs.STRIP }}" ]; then "${{ steps.vars.outputs.STRIP }}" '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/${{ env.PROJECT_NAME }}${{ steps.vars.outputs.EXE_suffix }}' ; fi
|
||||
# README and LICENSE
|
||||
cp README.md '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/'
|
||||
cp LICENSE '${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_BASENAME }}/'
|
||||
# base compressed package
|
||||
pushd '${{ steps.vars.outputs.STAGING }}/' >/dev/null
|
||||
case ${{ matrix.job.target }} in
|
||||
*-pc-windows-*) 7z -y a '${{ steps.vars.outputs.PKG_NAME }}' '${{ steps.vars.outputs.PKG_BASENAME }}'/* | tail -2 ;;
|
||||
*) tar czf '${{ steps.vars.outputs.PKG_NAME }}' '${{ steps.vars.outputs.PKG_BASENAME }}'/* ;;
|
||||
esac;
|
||||
popd >/dev/null
|
||||
- name: Publish
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: steps.vars.outputs.DEPLOY
|
||||
with:
|
||||
files: |
|
||||
${{ steps.vars.outputs.STAGING }}/${{ steps.vars.outputs.PKG_NAME }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
## fix! [rivy; 2020-22-01] `cargo tarpaulin` is unable to test this repo at the moment; alternate recipe or another testing framework?
|
||||
# coverage:
|
||||
# name: Code Coverage
|
||||
# runs-on: ${{ matrix.job.os }}
|
||||
# strategy:
|
||||
# fail-fast: true
|
||||
# matrix:
|
||||
# # job: [ { os: ubuntu-latest }, { os: macos-latest }, { os: windows-latest } ]
|
||||
# job: [ { os: ubuntu-latest } ] ## cargo-tarpaulin is currently only available on linux
|
||||
# steps:
|
||||
# - uses: actions/checkout@v1
|
||||
# # - name: Reattach HEAD ## may be needed for accurate code coverage info
|
||||
# # run: git checkout ${{ github.head_ref }}
|
||||
# - name: Initialize workflow variables
|
||||
# id: vars
|
||||
# shell: bash
|
||||
# run: |
|
||||
# # staging directory
|
||||
# STAGING='_staging'
|
||||
# echo set-output name=STAGING::${STAGING}
|
||||
# echo ::set-output name=STAGING::${STAGING}
|
||||
# # check for CODECOV_TOKEN availability (work-around for inaccessible 'secrets' object for 'if'; see <https://github.community/t5/GitHub-Actions/jobs-lt-job-id-gt-if-does-not-work-with-env-secrets/m-p/38549>)
|
||||
# unset HAS_CODECOV_TOKEN
|
||||
# if [ -n $CODECOV_TOKEN ]; then HAS_CODECOV_TOKEN='true' ; fi
|
||||
# echo set-output name=HAS_CODECOV_TOKEN::${HAS_CODECOV_TOKEN}
|
||||
# echo ::set-output name=HAS_CODECOV_TOKEN::${HAS_CODECOV_TOKEN}
|
||||
# env:
|
||||
# CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
|
||||
# - name: Create all needed build/work directories
|
||||
# shell: bash
|
||||
# run: |
|
||||
# mkdir -p '${{ steps.vars.outputs.STAGING }}/work'
|
||||
# - name: Install required packages
|
||||
# run: |
|
||||
# sudo apt-get -y install libssl-dev
|
||||
# pushd '${{ steps.vars.outputs.STAGING }}/work' >/dev/null
|
||||
# wget --no-verbose https://github.com/xd009642/tarpaulin/releases/download/0.9.3/cargo-tarpaulin-0.9.3-travis.tar.gz
|
||||
# tar xf cargo-tarpaulin-0.9.3-travis.tar.gz
|
||||
# cp cargo-tarpaulin "$(dirname -- "$(which cargo)")"/
|
||||
# popd >/dev/null
|
||||
# - name: Generate coverage
|
||||
# run: |
|
||||
# cargo tarpaulin --out Xml
|
||||
# - name: Upload coverage results (CodeCov.io)
|
||||
# # CODECOV_TOKEN (aka, "Repository Upload Token" for REPO from CodeCov.io) ## set via REPO/Settings/Secrets
|
||||
# # if: secrets.CODECOV_TOKEN (not supported {yet?}; see <https://github.community/t5/GitHub-Actions/jobs-lt-job-id-gt-if-does-not-work-with-env-secrets/m-p/38549>)
|
||||
# if: steps.vars.outputs.HAS_CODECOV_TOKEN
|
||||
# run: |
|
||||
# # CodeCov.io
|
||||
# cargo tarpaulin --out Xml
|
||||
# bash <(curl -s https://codecov.io/bash)
|
||||
# env:
|
||||
# CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}"
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -5,3 +5,5 @@
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
*.swp
|
||||
.vscode/*
|
||||
*.idea/*
|
||||
76
.travis.yml
76
.travis.yml
@@ -1,76 +0,0 @@
|
||||
# Based on the "trust" template v0.1.2
|
||||
# https://github.com/japaric/trust/tree/v0.1.2
|
||||
|
||||
dist: trusty
|
||||
language: rust
|
||||
services: docker
|
||||
sudo: required
|
||||
|
||||
# TODO Rust builds on stable by default, this can be
|
||||
# overridden on a case by case basis down below.
|
||||
|
||||
env:
|
||||
global:
|
||||
# TODO Update this to match the name of your project.
|
||||
- CRATE_NAME=dust
|
||||
|
||||
matrix:
|
||||
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
|
||||
# don't need
|
||||
include:
|
||||
# Linux
|
||||
- env: TARGET=x86_64-unknown-linux-gnu
|
||||
|
||||
# OSX
|
||||
- env: TARGET=x86_64-apple-darwin
|
||||
os: osx
|
||||
|
||||
before_install:
|
||||
- set -e
|
||||
- rustup self update
|
||||
|
||||
install:
|
||||
- sh ci/install.sh
|
||||
- source ~/.cargo/env || true
|
||||
|
||||
script:
|
||||
- bash ci/script.sh
|
||||
|
||||
after_script: set +e
|
||||
|
||||
before_deploy:
|
||||
- sh ci/before_deploy.sh
|
||||
|
||||
deploy:
|
||||
# TODO update `api_key.secure`
|
||||
# - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
|
||||
# - Encrypt it: `travis encrypt 0123456789012345678901234567890123456789
|
||||
# - Paste the output down here
|
||||
api_key:
|
||||
secure: UlU73Td7Bkb2N88ws4YGLWR+4U0IMgiou9QQtMnmpouJFjeUNxtLSPMPODVXP7zq4sKt5HR5B3fX9MW4mKm351fvnQEoihETn06pKiXGnY//SlTPTt67MX9ZOYmd9ohJReMDOZDgqhnGLxfymycGtsLAmdjDZnAl+IMqgg0FMyVFj9Cl9aKxnn12lxQyX4zabHKk8TUKD3By8ZoEUnJMHt3gEtOmbDgS4brcTPeHCzqnYFw73LEnkqvz+JP0XwauJY7Cf8lminKm/klmjCkQji8T9SHI52v1g0Fxpx0ucp2o3vulQrLHXaHvZ6Fr7J0cSXXzaFF3rrGLt4t4jU/+9TZm1+n5k5XuPW4x4NTCC9NmIj/z0/z41t82E9qZhzhtm2Jdsg6H2tNk+C774TYqcmR6GCvfRadfjRp3cA5dh0UwDVjH2MJFxlHDVkl6la0mVVRsCGF3oBKZVk0BDl1womfnmI46o/uU+gLknHN6Ed6PHHPPYDViWd3VKdmHKT7XrkMMUF6HjZUtla689DWIOWZSiV++1dVPcl/1TV+6tTmN4bBtPcLuX7SHRuLp2PI2kATvRMECsa7gZRypW4jKpVn7b2yetX9TVI3i1zR5zkQJ3dPg8sATvYPL53aKH/WsqUg4rzoAlbk9so+++R4bQY69LhV3B511B7EAynoZFdM
|
||||
file_glob: true
|
||||
file: $CRATE_NAME-$TRAVIS_TAG-$TARGET.*
|
||||
on:
|
||||
# TODO Here you can pick which targets will generate binary releases
|
||||
# In this example, there are some targets that are tested using the stable
|
||||
# and nightly channels. This condition makes sure there is only one release
|
||||
# for such targets and that's generated using the stable channel
|
||||
condition: $TRAVIS_RUST_VERSION = stable
|
||||
tags: true
|
||||
provider: releases
|
||||
skip_cleanup: true
|
||||
|
||||
cache: cargo
|
||||
before_cache:
|
||||
# Travis can't cache files that are not readable by "others"
|
||||
- chmod -R a+r $HOME/.cargo
|
||||
|
||||
branches:
|
||||
only:
|
||||
# release tags
|
||||
- /^v\d+\.\d+\.\d+.*$/
|
||||
- master
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
672
Cargo.lock
generated
672
Cargo.lock
generated
@@ -1,271 +1,409 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "assert_cli"
|
||||
version = "0.5.4"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.8"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.5"
|
||||
version = "0.3.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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.16"
|
||||
version = "0.1.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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]]
|
||||
name = "bitflags"
|
||||
version = "0.9.1"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytecount"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cargo_metadata"
|
||||
version = "0.3.3"
|
||||
name = "c2-chacha"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.9"
|
||||
version = "1.0.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.2"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.31.1"
|
||||
version = "2.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.14 (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)",
|
||||
"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)",
|
||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "1.6.0"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.4.0"
|
||||
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"
|
||||
dependencies = [
|
||||
"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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.7.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)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difference"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "dtoa"
|
||||
version = "0.4.2"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "du-dust"
|
||||
version = "0.2.4"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.31.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.0.0 (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)",
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"jwalk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"terminal_size 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.3"
|
||||
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 = "error-chain"
|
||||
version = "0.11.0"
|
||||
name = "failure"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
name = "failure_derive"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"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]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
name = "getrandom"
|
||||
version = "0.1.14"
|
||||
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)",
|
||||
"libc 0.2.66 (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]]
|
||||
name = "glob"
|
||||
version = "0.2.11"
|
||||
name = "hermit-abi"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.1"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
name = "jwalk"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.11"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.39"
|
||||
version = "0.2.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.2"
|
||||
name = "memoffset"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.3.2"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pulldown-cmark"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.9.1 (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 = "quote"
|
||||
version = "0.5.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.2"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (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)",
|
||||
"rand_chacha 0.2.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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"c2-chacha 0.2.3 (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 = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"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]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.37"
|
||||
version = "0.1.56"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_termios"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.0"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.7"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "0.1.3"
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"semver 0.9.0 (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.8.0"
|
||||
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)",
|
||||
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -275,158 +413,117 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.37"
|
||||
version = "1.0.104"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive_internals 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.13"
|
||||
version = "1.0.47"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "skeptic"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempdir"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "1.0.7"
|
||||
name = "syn"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
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]]
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
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)",
|
||||
"libc 0.2.66 (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)",
|
||||
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.4"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
@@ -434,58 +531,67 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930"
|
||||
"checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4"
|
||||
"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2"
|
||||
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
|
||||
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
|
||||
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||
"checksum bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af27422163679dea46a1a7239dffff64d3dcdc3ba5fe9c49c789fbfe0eb949de"
|
||||
"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537"
|
||||
"checksum cc 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "2b4911e4bdcb4100c7680e7e854ff38e23f1b34d4d9e079efae3da2801341ffc"
|
||||
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
|
||||
"checksum clap 2.31.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5dc18f6f4005132120d9711636b32c46a233fad94df6217fa1d81c5e97a9f200"
|
||||
"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
|
||||
"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
|
||||
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
|
||||
"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 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 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 c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
|
||||
"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 clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d"
|
||||
"checksum crossbeam 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69323bff1fb41c635347b8ead484a5ca6c3f11914d784170b158d8449ab07f8e"
|
||||
"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 either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
"checksum environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee"
|
||||
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
|
||||
"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff"
|
||||
"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364"
|
||||
"checksum proc-macro2 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "681c2c8e039ff358cb926dbc5151d561cbd0249089986ace39dfe8e405bb7511"
|
||||
"checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32"
|
||||
"checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a"
|
||||
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
|
||||
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum remove_dir_all 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dfc5b3ce5d5ea144bb04ebd093a9e14e9765bcfec866aecda9b6dec43b3d1e24"
|
||||
"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb"
|
||||
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
|
||||
"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
|
||||
"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 hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772"
|
||||
"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e"
|
||||
"checksum jwalk 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3dbf0a8f61baee43a2918ff50ac6a2d3b2c105bc08ed53bc298779f1263409"
|
||||
"checksum 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 memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
|
||||
"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6"
|
||||
"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
|
||||
"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548"
|
||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
"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_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 rayon 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "db6ce3297f9c85e16621bb8cca38a06779ffc31bb8184e1be4bed2be4678a098"
|
||||
"checksum rayon-core 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08a89b46efaf957e52b18062fb2f4660f8b8a4dde1807ca002690868ef2c85a9"
|
||||
"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
|
||||
"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
|
||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
"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.37 (registry+https://github.com/rust-lang/crates.io-index)" = "d3bcee660dcde8f52c3765dd9ca5ee36b4bf35470a738eb0bd5a8752b0389645"
|
||||
"checksum serde_derive 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "f1711ab8b208541fa8de00425f6a577d90f27bb60724d2bb5fd911314af9668f"
|
||||
"checksum serde_derive_internals 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "89b340a48245bc03ddba31d0ff1709c118df90edc6adabaca4aac77aea181cce"
|
||||
"checksum serde_json 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "5c508584d9913df116b91505eec55610a2f5b16e9ed793c46e4d0152872b3e74"
|
||||
"checksum skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8431f8fca168e2db4be547bd8329eac70d095dff1444fee4b0fa0fabc7df75a"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59"
|
||||
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
"checksum tempfile 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "439d9a7c00f98b1b5ee730039bf5b1f9203d508690e3c76b509e7ad59f8f7c99"
|
||||
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
|
||||
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
|
||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
|
||||
"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"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 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 terminal_size 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "e25a60e3024df9029a414be05f46318a77c22538861a22170077d0388c0e926e"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"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-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-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
24
Cargo.toml
24
Cargo.toml
@@ -1,8 +1,9 @@
|
||||
[package]
|
||||
name = "du-dust"
|
||||
description = "A more intuitive version of du"
|
||||
version = "0.2.4"
|
||||
version = "0.5.0"
|
||||
authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"]
|
||||
edition = "2018"
|
||||
|
||||
documentation = "https://github.com/bootandy/dust"
|
||||
homepage = "https://github.com/bootandy/dust"
|
||||
@@ -20,8 +21,21 @@ name = "dust"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
ansi_term = "0.11"
|
||||
clap = "2.31"
|
||||
assert_cli = "0.5"
|
||||
tempfile = "3"
|
||||
ansi_term = "=0.12"
|
||||
clap = "=2.33"
|
||||
jwalk = "0.4.0"
|
||||
num_cpus = "1.12"
|
||||
terminal_size = "0.1.10"
|
||||
unicode-width = "0.1.7"
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi-util = "0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cli = "=0.6"
|
||||
tempfile = "=3"
|
||||
|
||||
|
||||
[[test]]
|
||||
name = "integration"
|
||||
path = "tests/tests.rs"
|
||||
|
||||
97
README.md
97
README.md
@@ -1,58 +1,91 @@
|
||||
|
||||
[](https://travis-ci.org/bootandy/dust)
|
||||
|
||||
|
||||
# Dust
|
||||
|
||||
du + rust = dust. Like du but more intuitive
|
||||
|
||||
## Install
|
||||
|
||||
* 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/
|
||||
#### Cargo Install
|
||||
|
||||
* cargo install du-dust
|
||||
|
||||
#### Download Install
|
||||
|
||||
* 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
|
||||
|
||||
Dust is meant to give you an instant overview of which directories are using disk space without requiring sort or head. Dust will print a maximum of 1 'Did not have permissions message'.
|
||||
|
||||
Dust will list the 15 biggest sub directories or files and will smartly recurse down the tree to find the larger ones. There is no need for a '-d' flag or a '-h' flag. The largest sub directory will have its size shown in *red*
|
||||
Dust will list the terminal height - 10 biggest sub directories or files and will smartly recurse down the tree to find the larger ones. There is no need for a '-d' flag or a '-h' flag. The largest sub directory will have its size shown in *red*
|
||||
|
||||
## Why?
|
||||
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 you just do some rough math in your head and use the ordering to sanity check. 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.
|
||||
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: dust
|
||||
Usage: dust <dir>
|
||||
Usage: dust <dir> <another_dir> <and_more>
|
||||
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 15)
|
||||
Usage: dust <dir> <another_dir> <and_more>
|
||||
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 -n 30 <dir> (Shows 30 directories not 20)
|
||||
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 -x <dir> (Only show directories on same filesystem)
|
||||
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)
|
||||
```
|
||||
|
||||
```
|
||||
$ 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%
|
||||
|
||||
```
|
||||
djin:git/dust> dust
|
||||
65M .
|
||||
65M └─┬ ./target
|
||||
49M ├─┬ ./target/debug
|
||||
26M │ ├─┬ ./target/debug/deps
|
||||
21M │ │ └── ./target/debug/deps/libclap-9e6625ac8ff074ad.rlib
|
||||
13M │ ├── ./target/debug/dust
|
||||
8.9M │ └─┬ ./target/debug/incremental
|
||||
6.7M │ ├─┬ ./target/debug/incremental/dust-2748eiei2tcnp
|
||||
6.7M │ │ └─┬ ./target/debug/incremental/dust-2748eiei2tcnp/s-ezd6jnik5u-163pyem-1aab9ncf5glum
|
||||
3.0M │ │ └── ./target/debug/incremental/dust-2748eiei2tcnp/s-ezd6jnik5u-163pyem-1aab9ncf5glum/dep-graph.bin
|
||||
2.2M │ └─┬ ./target/debug/incremental/dust-1dlon65p8m3vl
|
||||
2.2M │ └── ./target/debug/incremental/dust-1dlon65p8m3vl/s-ezd6jncecv-1xsnfd0-4dw9l1r2th2t
|
||||
15M └─┬ ./target/release
|
||||
9.2M ├─┬ ./target/release/deps
|
||||
6.7M │ └── ./target/release/deps/libclap-87bc2534ea57f044.rlib
|
||||
5.9M └── ./target/release/dust
|
||||
```
|
||||
## Performance
|
||||
dust is currently about 4 times slower than du.
|
||||
|
||||
|
||||
## Alternatives
|
||||
* [NCDU](https://dev.yorhel.nl/ncdu)
|
||||
* du -d 1 -h | sort -h
|
||||
|
||||
* [NCDU](https://dev.yorhel.nl/ncdu)
|
||||
* [dutree](https://github.com/nachoparker/dutree)
|
||||
* du -d 1 -h | sort -h
|
||||
|
||||
Note: Apparent-size is calculated slightly differently in dust to gdu. In dust each hard link is counted as using file_length space. In gdu only the first entry is counted.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
# This script takes care of building your crate and packaging it for release
|
||||
|
||||
set -ex
|
||||
|
||||
6
ci/how2publish.txt
Normal file
6
ci/how2publish.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# ----------- To do a release ---------
|
||||
# tag a commit and push:
|
||||
# git tag v0.4.5
|
||||
# git push origin v0.4.5
|
||||
|
||||
# cargo publish to put it in crates.io
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
main() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
# This script takes care of testing your crate
|
||||
|
||||
set -ex
|
||||
|
||||
363
src/display.rs
363
src/display.rs
@@ -1,100 +1,301 @@
|
||||
extern crate ansi_term;
|
||||
|
||||
use self::ansi_term::Colour::Fixed;
|
||||
use self::ansi_term::Style;
|
||||
use crate::utils::Node;
|
||||
|
||||
use lib::Node;
|
||||
use terminal_size::{terminal_size, Height, Width};
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
||||
use std::cmp::max;
|
||||
use std::cmp::min;
|
||||
use std::iter::repeat;
|
||||
use std::path::Path;
|
||||
|
||||
static UNITS: [char; 4] = ['T', 'G', 'M', 'K'];
|
||||
static BLOCKS: [char; 5] = ['█', '▓', '▒', '░', ' '];
|
||||
static DEFAULT_TERMINAL_WIDTH: u16 = 80;
|
||||
|
||||
pub fn draw_it(permissions: bool, heads: &Vec<Node>, to_display: &Vec<&Node>) -> () {
|
||||
if !permissions {
|
||||
eprintln!("Did not have permissions for all directories");
|
||||
}
|
||||
|
||||
for d in to_display {
|
||||
if heads.contains(d) {
|
||||
display_node(d, &to_display, true, "")
|
||||
}
|
||||
}
|
||||
pub struct DisplayData {
|
||||
pub short_paths: bool,
|
||||
pub is_reversed: bool,
|
||||
pub colors_on: bool,
|
||||
pub base_size: u64,
|
||||
pub longest_string_length: usize,
|
||||
}
|
||||
|
||||
fn display_node<S: Into<String>>(
|
||||
node_to_print: &Node,
|
||||
to_display: &Vec<&Node>,
|
||||
is_first: bool,
|
||||
indentation_str: S,
|
||||
) {
|
||||
let mut is = indentation_str.into();
|
||||
print_this_node(node_to_print, is_first, is.as_ref());
|
||||
|
||||
is = is.replace("└─┬", " ");
|
||||
is = is.replace("└──", " ");
|
||||
is = is.replace("├──", "│ ");
|
||||
is = is.replace("├─┬", "│ ");
|
||||
|
||||
let printable_node_slashes = node_to_print.name().matches('/').count();
|
||||
|
||||
let mut num_siblings = to_display.iter().fold(0, |a, b| {
|
||||
if node_to_print.children().contains(b)
|
||||
&& b.name().matches('/').count() == printable_node_slashes + 1
|
||||
{
|
||||
a + 1
|
||||
impl DisplayData {
|
||||
#[allow(clippy::collapsible_if)]
|
||||
fn get_tree_chars(&self, was_i_last: bool, has_children: bool) -> &'static str {
|
||||
if self.is_reversed {
|
||||
if was_i_last {
|
||||
if has_children {
|
||||
"┌─┴"
|
||||
} else {
|
||||
"┌──"
|
||||
}
|
||||
} else if has_children {
|
||||
"├─┴"
|
||||
} else {
|
||||
"├──"
|
||||
}
|
||||
} else {
|
||||
a
|
||||
}
|
||||
});
|
||||
|
||||
let mut is_biggest = true;
|
||||
for node in to_display {
|
||||
if node_to_print.children().contains(node) {
|
||||
let has_display_children = node.children()
|
||||
.iter()
|
||||
.fold(false, |has_kids, n| has_kids || to_display.contains(&n));
|
||||
|
||||
let has_children = node.children().len() > 0 && has_display_children;
|
||||
if node.name().matches('/').count() == printable_node_slashes + 1 {
|
||||
num_siblings -= 1;
|
||||
|
||||
let tree_chars = {
|
||||
if num_siblings == 0 {
|
||||
if has_children {
|
||||
"└─┬"
|
||||
} else {
|
||||
"└──"
|
||||
}
|
||||
} else {
|
||||
if has_children {
|
||||
"├─┬"
|
||||
} else {
|
||||
"├──"
|
||||
}
|
||||
}
|
||||
};
|
||||
display_node(&node, to_display, is_biggest, is.to_string() + tree_chars);
|
||||
is_biggest = false;
|
||||
if was_i_last {
|
||||
if has_children {
|
||||
"└─┬"
|
||||
} else {
|
||||
"└──"
|
||||
}
|
||||
} else if has_children {
|
||||
"├─┬"
|
||||
} else {
|
||||
"├──"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_this_node(node: &Node, is_biggest: bool, indentation: &str) {
|
||||
let pretty_size = format!("{:>5}", human_readable_number(node.size()),);
|
||||
println!(
|
||||
"{}",
|
||||
format_string(node.name(), is_biggest, pretty_size.as_ref(), indentation)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn format_string(dir_name: &str, is_biggest: bool, size: &str, indentation: &str) -> String {
|
||||
format!(
|
||||
"{} {} {}",
|
||||
if is_biggest {
|
||||
Fixed(196).paint(size)
|
||||
fn is_biggest(&self, num_siblings: usize, max_siblings: u64) -> bool {
|
||||
if self.is_reversed {
|
||||
num_siblings == (max_siblings - 1) as usize
|
||||
} else {
|
||||
Fixed(7).paint(size)
|
||||
num_siblings == 0
|
||||
}
|
||||
}
|
||||
|
||||
fn is_last(&self, num_siblings: usize, max_siblings: u64) -> bool {
|
||||
if self.is_reversed {
|
||||
num_siblings == 0
|
||||
} else {
|
||||
num_siblings == (max_siblings - 1) as usize
|
||||
}
|
||||
}
|
||||
|
||||
fn percent_size(&self, node: &Node) -> f32 {
|
||||
let result = node.size as f32 / self.base_size as f32;
|
||||
if result.is_normal() {
|
||||
result
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_children_from_node(node: Node, is_reversed: bool) -> impl Iterator<Item = Node> {
|
||||
if is_reversed {
|
||||
let n: Vec<Node> = node.children.into_iter().rev().map(|a| a).collect();
|
||||
n.into_iter()
|
||||
} else {
|
||||
node.children.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
struct DrawData<'a> {
|
||||
indent: String,
|
||||
percent_bar: String,
|
||||
display_data: &'a DisplayData,
|
||||
}
|
||||
|
||||
impl DrawData<'_> {
|
||||
fn get_new_indent(&self, has_children: bool, was_i_last: bool) -> String {
|
||||
let chars = self.display_data.get_tree_chars(was_i_last, has_children);
|
||||
self.indent.to_string() + chars
|
||||
}
|
||||
|
||||
fn generate_bar(&self, node: &Node, level: usize) -> String {
|
||||
let chars_in_bar = self.percent_bar.chars().count();
|
||||
let num_bars = chars_in_bar as f32 * self.display_data.percent_size(node);
|
||||
let mut num_not_my_bar = (chars_in_bar as i32) - num_bars as i32;
|
||||
|
||||
let mut new_bar = "".to_string();
|
||||
let idx = 5 - min(5, max(1, level));
|
||||
|
||||
for c in self.percent_bar.chars() {
|
||||
num_not_my_bar -= 1;
|
||||
if num_not_my_bar <= 0 {
|
||||
new_bar.push(BLOCKS[0]);
|
||||
} else if c == BLOCKS[0] {
|
||||
new_bar.push(BLOCKS[idx]);
|
||||
} else {
|
||||
new_bar.push(c);
|
||||
}
|
||||
}
|
||||
new_bar
|
||||
}
|
||||
}
|
||||
|
||||
fn get_width_of_terminal() -> u16 {
|
||||
// Windows CI runners detect a very low terminal width
|
||||
if let Some((Width(w), Height(_h))) = terminal_size() {
|
||||
max(w, DEFAULT_TERMINAL_WIDTH)
|
||||
} else {
|
||||
DEFAULT_TERMINAL_WIDTH
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_it(
|
||||
permissions: bool,
|
||||
use_full_path: bool,
|
||||
is_reversed: bool,
|
||||
no_colors: bool,
|
||||
no_percents: bool,
|
||||
root_node: Node,
|
||||
) {
|
||||
if !permissions {
|
||||
eprintln!("Did not have permissions for all directories");
|
||||
}
|
||||
let longest_string_length = root_node
|
||||
.children
|
||||
.iter()
|
||||
.map(|c| find_longest_dir_name(&c, " ", !use_full_path))
|
||||
.fold(0, max);
|
||||
let terminal_width = get_width_of_terminal() - 16;
|
||||
|
||||
let max_bar_length = if no_percents || longest_string_length >= terminal_width as usize {
|
||||
0
|
||||
} else {
|
||||
terminal_width as usize - longest_string_length
|
||||
};
|
||||
|
||||
// handle usize error also add do not show fancy output option
|
||||
let bar_text = repeat(BLOCKS[0]).take(max_bar_length).collect::<String>();
|
||||
|
||||
for c in get_children_from_node(root_node, is_reversed) {
|
||||
let display_data = DisplayData {
|
||||
short_paths: !use_full_path,
|
||||
is_reversed,
|
||||
colors_on: !no_colors,
|
||||
base_size: c.size,
|
||||
longest_string_length,
|
||||
};
|
||||
let draw_data = DrawData {
|
||||
indent: "".to_string(),
|
||||
percent_bar: bar_text.clone(),
|
||||
display_data: &display_data,
|
||||
};
|
||||
display_node(c, &draw_data, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
// We can probably pass depth instead of indent here.
|
||||
// It is ugly to feed in ' ' instead of the actual tree characters but we don't need them yet.
|
||||
fn find_longest_dir_name(node: &Node, indent: &str, long_paths: bool) -> usize {
|
||||
let longest = UnicodeWidthStr::width(&*get_printable_name(&node.name, long_paths, indent));
|
||||
|
||||
// each none root tree drawing is 2 chars
|
||||
let full_indent: String = indent.to_string() + " ";
|
||||
node.children
|
||||
.iter()
|
||||
.map(|c| find_longest_dir_name(c, &*full_indent, long_paths))
|
||||
.fold(longest, max)
|
||||
}
|
||||
|
||||
fn display_node(node: Node, draw_data: &DrawData, is_biggest: bool, is_last: bool) {
|
||||
let indent2 = draw_data.get_new_indent(!node.children.is_empty(), is_last);
|
||||
// hacky way of working out how deep we are in the tree
|
||||
let level = ((indent2.chars().count() - 1) / 2) - 1;
|
||||
let bar_text = draw_data.generate_bar(&node, level);
|
||||
|
||||
let to_print = format_string(
|
||||
&node,
|
||||
&*indent2,
|
||||
&*bar_text,
|
||||
is_biggest,
|
||||
draw_data.display_data,
|
||||
);
|
||||
|
||||
if !draw_data.display_data.is_reversed {
|
||||
println!("{}", to_print)
|
||||
}
|
||||
|
||||
let dd = DrawData {
|
||||
indent: clean_indentation_string(&*indent2),
|
||||
percent_bar: bar_text,
|
||||
display_data: draw_data.display_data,
|
||||
};
|
||||
let num_siblings = node.children.len() as u64;
|
||||
|
||||
for (count, c) in get_children_from_node(node, draw_data.display_data.is_reversed).enumerate() {
|
||||
let is_biggest = dd.display_data.is_biggest(count, num_siblings);
|
||||
let was_i_last = dd.display_data.is_last(count, num_siblings);
|
||||
display_node(c, &dd, is_biggest, was_i_last);
|
||||
}
|
||||
|
||||
if draw_data.display_data.is_reversed {
|
||||
println!("{}", to_print)
|
||||
}
|
||||
}
|
||||
|
||||
fn clean_indentation_string(s: &str) -> String {
|
||||
let mut is: String = s.into();
|
||||
// For reversed:
|
||||
is = is.replace("┌─┴", " ");
|
||||
is = is.replace("┌──", " ");
|
||||
is = is.replace("├─┴", "│ ");
|
||||
is = is.replace("─┴", " ");
|
||||
// For normal
|
||||
is = is.replace("└─┬", " ");
|
||||
is = is.replace("└──", " ");
|
||||
is = is.replace("├─┬", "│ ");
|
||||
is = is.replace("─┬", " ");
|
||||
// For both
|
||||
is = is.replace("├──", "│ ");
|
||||
is
|
||||
}
|
||||
|
||||
fn get_printable_name<P: AsRef<Path>>(dir_name: &P, long_paths: bool, indentation: &str) -> String {
|
||||
let dir_name = dir_name.as_ref();
|
||||
let printable_name = {
|
||||
if long_paths {
|
||||
match dir_name.parent() {
|
||||
Some(prefix) => match dir_name.strip_prefix(prefix) {
|
||||
Ok(base) => base,
|
||||
Err(_) => dir_name,
|
||||
},
|
||||
None => dir_name,
|
||||
}
|
||||
} else {
|
||||
dir_name
|
||||
}
|
||||
};
|
||||
format!("{} {}", indentation, printable_name.display())
|
||||
}
|
||||
|
||||
pub fn format_string(
|
||||
node: &Node,
|
||||
indent: &str,
|
||||
percent_bar: &str,
|
||||
is_biggest: bool,
|
||||
display_data: &DisplayData,
|
||||
) -> String {
|
||||
let pretty_size = format!("{:>5}", human_readable_number(node.size));
|
||||
|
||||
let percent_size = display_data.percent_size(node);
|
||||
let percent_size_str = format!("{:.0}%", percent_size * 100.0);
|
||||
|
||||
let tree_and_path = get_printable_name(&node.name, display_data.short_paths, &*indent);
|
||||
|
||||
let printable_chars = UnicodeWidthStr::width(&*tree_and_path);
|
||||
let tree_and_path = tree_and_path
|
||||
+ &(repeat(" ")
|
||||
.take(display_data.longest_string_length - printable_chars)
|
||||
.collect::<String>());
|
||||
|
||||
let percents = if percent_bar != "" {
|
||||
format!("│{} │ {:>4}", percent_bar, percent_size_str)
|
||||
} else {
|
||||
"".into()
|
||||
};
|
||||
|
||||
format!(
|
||||
"{} {}{}",
|
||||
if is_biggest && display_data.colors_on {
|
||||
Fixed(196).paint(pretty_size)
|
||||
} else {
|
||||
Style::new().paint(pretty_size)
|
||||
},
|
||||
indentation,
|
||||
dir_name,
|
||||
tree_and_path,
|
||||
percents,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
68
src/lib.rs
68
src/lib.rs
@@ -1,68 +0,0 @@
|
||||
use std::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Node {
|
||||
name: String,
|
||||
size: u64,
|
||||
children: Vec<Node>,
|
||||
}
|
||||
|
||||
impl Node {
|
||||
pub fn new<S: Into<String>>(name: S, size: u64, children: Vec<Node>) -> Self {
|
||||
Node {
|
||||
children: children,
|
||||
name: name.into(),
|
||||
size: size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn children(&self) -> &Vec<Node> {
|
||||
&self.children
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &String {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn size(&self) -> u64 {
|
||||
self.size
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Node {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
if self.size > other.size {
|
||||
Ordering::Less
|
||||
} else if self.size < other.size {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
let my_slashes = self.name.matches('/').count();
|
||||
let other_slashes = other.name.matches('/').count();
|
||||
|
||||
if my_slashes > other_slashes {
|
||||
Ordering::Greater
|
||||
} else if my_slashes < other_slashes {
|
||||
Ordering::Less
|
||||
} else {
|
||||
if self.name < other.name {
|
||||
Ordering::Less
|
||||
} else if self.name > other.name {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl PartialOrd for Node {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
impl PartialEq for Node {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
(&self.name, self.size) == (&other.name, other.size)
|
||||
}
|
||||
}
|
||||
impl Eq for Node {}
|
||||
205
src/main.rs
205
src/main.rs
@@ -1,49 +1,224 @@
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate assert_cli;
|
||||
extern crate unicode_width;
|
||||
|
||||
use self::display::draw_it;
|
||||
use crate::utils::is_a_parent_of;
|
||||
use clap::{App, AppSettings, Arg};
|
||||
use utils::{find_big_ones, get_dir_tree};
|
||||
|
||||
use std::cmp::max;
|
||||
use std::path::PathBuf;
|
||||
use terminal_size::{terminal_size, Height, Width};
|
||||
use utils::{find_big_ones, get_dir_tree, simplify_dir_names, sort, trim_deep_ones, Node};
|
||||
|
||||
mod display;
|
||||
mod utils;
|
||||
mod lib;
|
||||
|
||||
static DEFAULT_NUMBER_OF_LINES: &'static str = "15";
|
||||
static DEFAULT_NUMBER_OF_LINES: usize = 30;
|
||||
|
||||
#[cfg(windows)]
|
||||
fn init_color() {
|
||||
ansi_term::enable_ansi_support().expect("Couldn't enable color support");
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn init_color() {}
|
||||
|
||||
fn get_height_of_terminal() -> usize {
|
||||
// Windows CI runners detect a terminal height of 0
|
||||
if let Some((Width(_w), Height(h))) = terminal_size() {
|
||||
max(h as usize, DEFAULT_NUMBER_OF_LINES) - 10
|
||||
} else {
|
||||
DEFAULT_NUMBER_OF_LINES - 10
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
init_color();
|
||||
|
||||
let default_height = get_height_of_terminal();
|
||||
let def_num_str = default_height.to_string();
|
||||
|
||||
let options = App::new("Dust")
|
||||
.about("Like du but more intuitive")
|
||||
.version(crate_version!())
|
||||
.setting(AppSettings::TrailingVarArg)
|
||||
.arg(
|
||||
Arg::with_name("depth")
|
||||
.short("d")
|
||||
.long("depth")
|
||||
.help("Depth to show")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("threads")
|
||||
.short("t")
|
||||
.long("threads")
|
||||
.help("Number of threads to spawn simultaneously")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("number_of_lines")
|
||||
.short("n")
|
||||
.long("number-of-lines")
|
||||
.help("Number of lines of output to show")
|
||||
.takes_value(true)
|
||||
.default_value(DEFAULT_NUMBER_OF_LINES),
|
||||
.default_value(def_num_str.as_ref()),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("use_apparent_size")
|
||||
Arg::with_name("display_full_paths")
|
||||
.short("p")
|
||||
.long("full-paths")
|
||||
.help("If set sub directories will not have their path shortened"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("ignore_directory")
|
||||
.short("X")
|
||||
.long("ignore-directory")
|
||||
.takes_value(true)
|
||||
.number_of_values(1)
|
||||
.multiple(true)
|
||||
.help("Exclude any file or directory with this name."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("limit_filesystem")
|
||||
.short("x")
|
||||
.long("limit-filesystem")
|
||||
.help("Only count the files and directories in the same filesystem as the supplied directory"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("display_apparent_size")
|
||||
.short("s")
|
||||
.long("apparent-size")
|
||||
.help("If set will use file length. Otherwise we use blocks"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("reverse")
|
||||
.short("r")
|
||||
.long("reverse")
|
||||
.help("If applied tree will be printed upside down (biggest highest)"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("no_colors")
|
||||
.short("c")
|
||||
.long("no_colors")
|
||||
.help("If applied no colors will be printed (normally largest directories are marked in red"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("no_bars")
|
||||
.short("b")
|
||||
.long("no_percent_bars")
|
||||
.help("If applied no percent bars or percents will be displayed"),
|
||||
)
|
||||
.arg(Arg::with_name("inputs").multiple(true))
|
||||
.get_matches();
|
||||
|
||||
let filenames = {
|
||||
let target_dirs = {
|
||||
match options.values_of("inputs") {
|
||||
None => vec!["."],
|
||||
Some(r) => r.collect(),
|
||||
}
|
||||
};
|
||||
let number_of_lines = value_t!(options.value_of("number_of_lines"), usize).unwrap();
|
||||
let use_apparent_size = options.is_present("use_apparent_size");
|
||||
|
||||
let (permissions, node_per_top_level_dir) = get_dir_tree(&filenames, use_apparent_size);
|
||||
let slice_it = find_big_ones(&node_per_top_level_dir, number_of_lines);
|
||||
draw_it(permissions, &node_per_top_level_dir, &slice_it);
|
||||
let number_of_lines = match value_t!(options.value_of("number_of_lines"), usize) {
|
||||
Ok(v) => v,
|
||||
Err(_) => {
|
||||
eprintln!("Ignoring bad value for number_of_lines");
|
||||
default_height
|
||||
}
|
||||
};
|
||||
|
||||
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| {
|
||||
depth
|
||||
.parse::<u64>()
|
||||
.map(|v| v + 1)
|
||||
.map_err(|_| eprintln!("Ignoring bad value for depth"))
|
||||
.ok()
|
||||
});
|
||||
if options.is_present("depth") && number_of_lines != default_height {
|
||||
eprintln!("Use either -n or -d. Not both");
|
||||
return;
|
||||
}
|
||||
|
||||
let use_apparent_size = options.is_present("display_apparent_size");
|
||||
let limit_filesystem = options.is_present("limit_filesystem");
|
||||
let ignore_directories = match options.values_of("ignore_directory") {
|
||||
Some(i) => Some(i.map(PathBuf::from).collect()),
|
||||
None => None,
|
||||
};
|
||||
|
||||
let simplified_dirs = simplify_dir_names(target_dirs);
|
||||
let (permissions, nodes) = get_dir_tree(
|
||||
&simplified_dirs,
|
||||
&ignore_directories,
|
||||
use_apparent_size,
|
||||
limit_filesystem,
|
||||
threads,
|
||||
);
|
||||
let sorted_data = sort(nodes);
|
||||
let biggest_ones = {
|
||||
match depth {
|
||||
None => find_big_ones(sorted_data, number_of_lines + simplified_dirs.len()),
|
||||
Some(d) => trim_deep_ones(sorted_data, d, &simplified_dirs),
|
||||
}
|
||||
};
|
||||
let tree = build_tree(biggest_ones, depth);
|
||||
|
||||
draw_it(
|
||||
permissions,
|
||||
options.is_present("display_full_paths"),
|
||||
!options.is_present("reverse"),
|
||||
options.is_present("no_colors"),
|
||||
options.is_present("no_bars"),
|
||||
tree,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
fn build_tree(biggest_ones: Vec<(PathBuf, u64)>, depth: Option<u64>) -> Node {
|
||||
let mut top_parent = Node::default();
|
||||
|
||||
// assume sorted order
|
||||
for b in biggest_ones {
|
||||
let n = Node {
|
||||
name: b.0,
|
||||
size: b.1,
|
||||
children: Vec::default(),
|
||||
};
|
||||
recursively_build_tree(&mut top_parent, n, depth);
|
||||
}
|
||||
top_parent
|
||||
}
|
||||
|
||||
fn recursively_build_tree(parent_node: &mut Node, new_node: Node, depth: Option<u64>) {
|
||||
let new_depth = match depth {
|
||||
None => None,
|
||||
Some(0) => return,
|
||||
Some(d) => Some(d - 1),
|
||||
};
|
||||
if let Some(c) = parent_node
|
||||
.children
|
||||
.iter_mut()
|
||||
.find(|c| is_a_parent_of(&c.name, &new_node.name))
|
||||
{
|
||||
recursively_build_tree(c, new_node, new_depth);
|
||||
} else {
|
||||
parent_node.children.push(new_node);
|
||||
}
|
||||
}
|
||||
|
||||
1
src/test_dir2/dir/hello
Normal file
1
src/test_dir2/dir/hello
Normal file
@@ -0,0 +1 @@
|
||||
hello
|
||||
1
src/test_dir2/dir_name_clash
Normal file
1
src/test_dir2/dir_name_clash
Normal file
@@ -0,0 +1 @@
|
||||
hello
|
||||
1
src/test_dir2/dir_substring/hello
Normal file
1
src/test_dir2/dir_substring/hello
Normal file
@@ -0,0 +1 @@
|
||||
hello
|
||||
0
src/test_dir3/ラウトは難しいです!.japan
Normal file
0
src/test_dir3/ラウトは難しいです!.japan
Normal file
0
src/test_dir3/👩.unicode
Normal file
0
src/test_dir3/👩.unicode
Normal file
214
src/tests.rs
214
src/tests.rs
@@ -1,214 +0,0 @@
|
||||
extern crate ansi_term;
|
||||
extern crate tempfile;
|
||||
use self::tempfile::Builder;
|
||||
use self::tempfile::TempDir;
|
||||
use super::*;
|
||||
use display::format_string;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::panic;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
#[test]
|
||||
pub fn test_main() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["src/test_dir"])
|
||||
.stdout()
|
||||
.is(main_output())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn main_output() -> String {
|
||||
format!(
|
||||
"{}
|
||||
{}
|
||||
{}
|
||||
{}",
|
||||
format_string("src/test_dir", true, " 4.0K", ""),
|
||||
format_string("src/test_dir/many", true, " 4.0K", "└─┬",),
|
||||
format_string("src/test_dir/many/hello_file", true, " 4.0K", " ├──",),
|
||||
format_string("src/test_dir/many/a_file", false, " 0B", " └──",),
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main_output() -> String {
|
||||
format!(
|
||||
"{}
|
||||
{}
|
||||
{}
|
||||
{}",
|
||||
format_string("src/test_dir", true, " 8.0K", ""),
|
||||
format_string("src/test_dir/many", true, " 4.0K", "└─┬",),
|
||||
format_string("src/test_dir/many/hello_file", true, " 4.0K", " ├──",),
|
||||
format_string("src/test_dir/many/a_file", false, " 0B", " └──",),
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_main_extra_slash() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["src/test_dir/"])
|
||||
.stdout()
|
||||
.is(main_output())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_apparent_size() {
|
||||
let r = format!(
|
||||
"{}",
|
||||
format_string("src/test_dir/many/hello_file", true, " 6B", " ├──",),
|
||||
);
|
||||
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-s", "src/test_dir"])
|
||||
.stdout()
|
||||
.contains(r)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn build_temp_file(dir: &TempDir) -> (PathBuf) {
|
||||
let file_path = dir.path().join("notes.txt");
|
||||
let mut file = File::create(&file_path).unwrap();
|
||||
writeln!(file, "I am a temp file").unwrap();
|
||||
file_path
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_soft_sym_link() {
|
||||
let dir = Builder::new().tempdir().unwrap();
|
||||
let file = build_temp_file(&dir);
|
||||
let dir_s = dir.path().to_str().unwrap();
|
||||
let file_path_s = file.to_str().unwrap();
|
||||
|
||||
let link_name = dir.path().join("the_link");
|
||||
let link_name_s = link_name.to_str().unwrap();
|
||||
let c = Command::new("ln")
|
||||
.arg("-s")
|
||||
.arg(file_path_s)
|
||||
.arg(link_name_s)
|
||||
.output();
|
||||
assert!(c.is_ok());
|
||||
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&[dir_s])
|
||||
.stdout()
|
||||
.contains(soft_sym_link_output(dir_s, file_path_s, link_name_s))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn soft_sym_link_output(dir: &str, file_path: &str, link_name: &str) -> String {
|
||||
format!(
|
||||
"{}
|
||||
{}
|
||||
{}",
|
||||
format_string(dir, true, " 8.0K", ""),
|
||||
format_string(file_path, true, " 4.0K", "├──",),
|
||||
format_string(link_name, false, " 4.0K", "└──",),
|
||||
)
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
fn soft_sym_link_output(dir: &str, file_path: &str, link_name: &str) -> String {
|
||||
format!(
|
||||
"{}
|
||||
{}
|
||||
{}",
|
||||
format_string(dir, true, " 4.0K", ""),
|
||||
format_string(file_path, true, " 4.0K", "├──",),
|
||||
format_string(link_name, false, " 0B", "└──",),
|
||||
)
|
||||
}
|
||||
|
||||
// Hard links are ignored as the inode is the same as the file
|
||||
#[test]
|
||||
pub fn test_hard_sym_link() {
|
||||
let dir = Builder::new().tempdir().unwrap();
|
||||
let file = build_temp_file(&dir);
|
||||
let dir_s = dir.path().to_str().unwrap();
|
||||
let file_path_s = file.to_str().unwrap();
|
||||
|
||||
let link_name = dir.path().join("the_link");
|
||||
let link_name_s = link_name.to_str().unwrap();
|
||||
let c = Command::new("ln")
|
||||
.arg(file_path_s)
|
||||
.arg(link_name_s)
|
||||
.output();
|
||||
assert!(c.is_ok());
|
||||
|
||||
let r = format!(
|
||||
"{}
|
||||
{}",
|
||||
format_string(dir_s, true, " 4.0K", ""),
|
||||
format_string(file_path_s, true, " 4.0K", "└──")
|
||||
);
|
||||
let r2 = format!(
|
||||
"{}
|
||||
{}",
|
||||
format_string(dir_s, true, " 4.0K", ""),
|
||||
format_string(link_name_s, true, " 4.0K", "└──")
|
||||
);
|
||||
|
||||
// Because this is a hard link the file and hard link look identicle. Therefore
|
||||
// we cannot guarantee which version will appear first.
|
||||
// TODO: Consider adding predictable itteration order (sort file entries by name?)
|
||||
let result = panic::catch_unwind(|| {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&[dir_s])
|
||||
.stdout()
|
||||
.contains(r)
|
||||
.unwrap();
|
||||
});
|
||||
if result.is_err() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&[dir_s])
|
||||
.stdout()
|
||||
.contains(r2)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
//Check we don't recurse down an infinite symlink tree
|
||||
#[test]
|
||||
pub fn test_recursive_sym_link() {
|
||||
let dir = Builder::new().tempdir().unwrap();
|
||||
let dir_s = dir.path().to_str().unwrap();
|
||||
|
||||
let link_name = dir.path().join("the_link");
|
||||
let link_name_s = link_name.to_str().unwrap();
|
||||
|
||||
let c = Command::new("ln")
|
||||
.arg("-s")
|
||||
.arg(dir_s)
|
||||
.arg(link_name_s)
|
||||
.output();
|
||||
assert!(c.is_ok());
|
||||
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&[dir_s])
|
||||
.stdout()
|
||||
.contains(recursive_sym_link_output(dir_s, link_name_s))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn recursive_sym_link_output(dir: &str, link_name: &str) -> String {
|
||||
format!(
|
||||
"{}
|
||||
{}",
|
||||
format_string(dir, true, " 4.0K", ""),
|
||||
format_string(link_name, true, " 4.0K", "└──",),
|
||||
)
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
fn recursive_sym_link_output(dir: &str, link_name: &str) -> String {
|
||||
format!(
|
||||
"{}
|
||||
{}",
|
||||
format_string(dir, true, " 0B", ""),
|
||||
format_string(link_name, true, " 0B", "└──",),
|
||||
)
|
||||
}
|
||||
440
src/utils/mod.rs
440
src/utils/mod.rs
@@ -1,121 +1,383 @@
|
||||
use jwalk::DirEntry;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use std::fs;
|
||||
use jwalk::WalkDir;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use lib::Node;
|
||||
mod platform;
|
||||
use self::platform::*;
|
||||
|
||||
pub fn get_dir_tree(filenames: &Vec<&str>, apparent_size: bool) -> (bool, Vec<Node>) {
|
||||
let mut permissions = true;
|
||||
let mut inodes: HashSet<(u64, u64)> = HashSet::new();
|
||||
let mut results = vec![];
|
||||
for &b in filenames {
|
||||
let filename = strip_end_slashes(b);
|
||||
let (hp, data) = examine_dir(&Path::new(&filename), apparent_size, &mut inodes);
|
||||
permissions = permissions && hp;
|
||||
match data {
|
||||
Some(d) => results.push(d),
|
||||
None => permissions = false,
|
||||
#[derive(Debug, Default, Eq)]
|
||||
pub struct Node {
|
||||
pub name: PathBuf,
|
||||
pub size: u64,
|
||||
pub children: Vec<Node>,
|
||||
}
|
||||
|
||||
impl Ord for Node {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
if self.size == other.size {
|
||||
self.name.cmp(&other.name)
|
||||
} else {
|
||||
self.size.cmp(&other.size)
|
||||
}
|
||||
}
|
||||
(permissions, results)
|
||||
}
|
||||
|
||||
fn strip_end_slashes(s: &str) -> String {
|
||||
let mut new_name = String::from(s);
|
||||
while new_name.chars().last() == Some('/') && new_name.len() != 1 {
|
||||
new_name.pop();
|
||||
impl PartialOrd for Node {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
new_name
|
||||
}
|
||||
|
||||
fn examine_dir(
|
||||
sdir: &Path,
|
||||
impl PartialEq for Node {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.name == other.name && self.size == other.size && self.children == other.children
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_a_parent_of<P: AsRef<Path>>(parent: P, child: P) -> bool {
|
||||
let parent = parent.as_ref();
|
||||
let child = child.as_ref();
|
||||
(child.starts_with(parent) && !parent.starts_with(child))
|
||||
}
|
||||
|
||||
pub fn simplify_dir_names<P: AsRef<Path>>(filenames: Vec<P>) -> HashSet<PathBuf> {
|
||||
let mut top_level_names: HashSet<PathBuf> = HashSet::with_capacity(filenames.len());
|
||||
let mut to_remove: Vec<PathBuf> = Vec::with_capacity(filenames.len());
|
||||
|
||||
for t in filenames {
|
||||
let top_level_name = normalize_path(t);
|
||||
let mut can_add = true;
|
||||
|
||||
for tt in top_level_names.iter() {
|
||||
if is_a_parent_of(&top_level_name, tt) {
|
||||
to_remove.push(tt.to_path_buf());
|
||||
} else if is_a_parent_of(tt, &top_level_name) {
|
||||
can_add = false;
|
||||
}
|
||||
}
|
||||
to_remove.sort_unstable();
|
||||
top_level_names.retain(|tr| to_remove.binary_search(tr).is_err());
|
||||
to_remove.clear();
|
||||
if can_add {
|
||||
top_level_names.insert(top_level_name);
|
||||
}
|
||||
}
|
||||
|
||||
top_level_names
|
||||
}
|
||||
|
||||
pub fn get_dir_tree<P: AsRef<Path>>(
|
||||
top_level_names: &HashSet<P>,
|
||||
ignore_directories: &Option<Vec<PathBuf>>,
|
||||
apparent_size: bool,
|
||||
inodes: &mut HashSet<(u64, u64)>,
|
||||
) -> (bool, Option<Node>) {
|
||||
match fs::read_dir(sdir) {
|
||||
Ok(file_iter) => {
|
||||
let mut result = vec![];
|
||||
let mut have_permission = true;
|
||||
let mut total_size = 0;
|
||||
limit_filesystem: bool,
|
||||
threads: Option<usize>,
|
||||
) -> (bool, HashMap<PathBuf, u64>) {
|
||||
let mut permissions = 0;
|
||||
let mut data: HashMap<PathBuf, u64> = HashMap::new();
|
||||
let restricted_filesystems = if limit_filesystem {
|
||||
get_allowed_filesystems(top_level_names)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
for single_path in file_iter {
|
||||
match single_path {
|
||||
Ok(d) => {
|
||||
let file_type = d.file_type().ok();
|
||||
let maybe_size_and_inode = get_metadata(&d, apparent_size);
|
||||
for b in top_level_names.iter() {
|
||||
examine_dir(
|
||||
b,
|
||||
apparent_size,
|
||||
&restricted_filesystems,
|
||||
ignore_directories,
|
||||
&mut data,
|
||||
&mut permissions,
|
||||
threads,
|
||||
);
|
||||
}
|
||||
(permissions == 0, data)
|
||||
}
|
||||
|
||||
match (file_type, maybe_size_and_inode) {
|
||||
(Some(file_type), Some((size, maybe_inode))) => {
|
||||
if !apparent_size {
|
||||
if let Some(inode_dev_pair) = maybe_inode {
|
||||
if inodes.contains(&inode_dev_pair) {
|
||||
continue;
|
||||
}
|
||||
inodes.insert(inode_dev_pair);
|
||||
}
|
||||
}
|
||||
total_size += size;
|
||||
fn get_allowed_filesystems<P: AsRef<Path>>(top_level_names: &HashSet<P>) -> Option<HashSet<u64>> {
|
||||
let mut limit_filesystems: HashSet<u64> = HashSet::new();
|
||||
for file_name in top_level_names.iter() {
|
||||
if let Ok(a) = get_filesystem(file_name) {
|
||||
limit_filesystems.insert(a);
|
||||
}
|
||||
}
|
||||
Some(limit_filesystems)
|
||||
}
|
||||
|
||||
if d.path().is_dir() && !file_type.is_symlink() {
|
||||
let (hp, child) = examine_dir(&d.path(), apparent_size, inodes);
|
||||
have_permission = have_permission && hp;
|
||||
pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
|
||||
// normalize path ...
|
||||
// 1. removing repeated separators
|
||||
// 2. removing interior '.' ("current directory") path segments
|
||||
// 3. removing trailing extra separators and '.' ("current directory") path segments
|
||||
// * `Path.components()` does all the above work; ref: <https://doc.rust-lang.org/std/path/struct.Path.html#method.components>
|
||||
// 4. changing to os preferred separator (automatically done by recollecting components back into a PathBuf)
|
||||
path.as_ref().components().collect::<PathBuf>()
|
||||
}
|
||||
|
||||
match child {
|
||||
Some(c) => {
|
||||
total_size += c.size();
|
||||
result.push(c);
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
} else {
|
||||
let path_name = d.path().to_string_lossy().to_string();
|
||||
result.push(Node::new(path_name, size, vec![]))
|
||||
}
|
||||
}
|
||||
(_, None) => have_permission = false,
|
||||
(_, _) => (),
|
||||
}
|
||||
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;
|
||||
}
|
||||
Err(_) => (),
|
||||
}
|
||||
}
|
||||
let n = Node::new(sdir.to_string_lossy().to_string(), total_size, result);
|
||||
(have_permission, Some(n))
|
||||
|
||||
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
|
||||
}
|
||||
Err(_) => (false, None),
|
||||
}
|
||||
}
|
||||
|
||||
// We start with a list of root directories - these must be the biggest folders
|
||||
// We then repeadedly merge in the children of the biggest directory - Each iteration
|
||||
// the next biggest directory's children are merged in.
|
||||
pub fn find_big_ones<'a>(l: &'a Vec<Node>, max_to_show: usize) -> Vec<&Node> {
|
||||
let mut new_l: Vec<&Node> = l.iter().map(|a| a).collect();
|
||||
new_l.sort();
|
||||
|
||||
for processed_pointer in 0..max_to_show {
|
||||
if new_l.len() == processed_pointer {
|
||||
break;
|
||||
fn should_ignore_file(
|
||||
apparent_size: bool,
|
||||
restricted_filesystems: &Option<HashSet<u64>>,
|
||||
inodes: &mut HashSet<(u64, u64)>,
|
||||
inode: u64,
|
||||
device: u64,
|
||||
) -> bool {
|
||||
// Ignore files on different devices (if flag applied)
|
||||
if let Some(rs) = restricted_filesystems {
|
||||
if !rs.contains(&device) {
|
||||
return true;
|
||||
}
|
||||
// Must be a list of pointers into new_l otherwise b_list will go out of scope
|
||||
// when it is deallocated
|
||||
let mut b_list: Vec<&Node> = new_l[processed_pointer]
|
||||
.children()
|
||||
.iter()
|
||||
.map(|a| a)
|
||||
.collect();
|
||||
new_l.extend(b_list);
|
||||
new_l.sort();
|
||||
}
|
||||
|
||||
if new_l.len() > max_to_show {
|
||||
new_l[0..max_to_show + 1].to_vec()
|
||||
if !apparent_size {
|
||||
// Ignore files already visited or symlinked
|
||||
if inodes.contains(&(inode, device)) {
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sort_by_size_first_name_second(a: &(PathBuf, u64), b: &(PathBuf, u64)) -> Ordering {
|
||||
let result = b.1.cmp(&a.1);
|
||||
if result == Ordering::Equal {
|
||||
a.0.cmp(&b.0)
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sort(data: HashMap<PathBuf, u64>) -> Vec<(PathBuf, u64)> {
|
||||
let mut new_l: Vec<(PathBuf, u64)> = data.iter().map(|(a, b)| (a.clone(), *b)).collect();
|
||||
new_l.sort_unstable_by(sort_by_size_first_name_second);
|
||||
new_l
|
||||
}
|
||||
|
||||
pub fn find_big_ones(new_l: Vec<(PathBuf, u64)>, max_to_show: usize) -> Vec<(PathBuf, u64)> {
|
||||
if max_to_show > 0 && new_l.len() > max_to_show {
|
||||
new_l[0..max_to_show].to_vec()
|
||||
} else {
|
||||
new_l
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
#[allow(unused_imports)]
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_simplify_dir() {
|
||||
let mut correct = HashSet::new();
|
||||
correct.insert(PathBuf::from("a"));
|
||||
assert_eq!(simplify_dir_names(vec!["a"]), correct);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simplify_dir_rm_subdir() {
|
||||
let mut correct = HashSet::new();
|
||||
correct.insert(["a", "b"].iter().collect::<PathBuf>());
|
||||
assert_eq!(simplify_dir_names(vec!["a/b", "a/b/c", "a/b/d/f"]), correct);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simplify_dir_duplicates() {
|
||||
let mut correct = HashSet::new();
|
||||
correct.insert(["a", "b"].iter().collect::<PathBuf>());
|
||||
correct.insert(PathBuf::from("c"));
|
||||
assert_eq!(
|
||||
simplify_dir_names(vec![
|
||||
"a/b",
|
||||
"a/b//",
|
||||
"a/././b///",
|
||||
"c",
|
||||
"c/",
|
||||
"c/.",
|
||||
"c/././",
|
||||
"c/././."
|
||||
]),
|
||||
correct
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_simplify_dir_rm_subdir_and_not_substrings() {
|
||||
let mut correct = HashSet::new();
|
||||
correct.insert(PathBuf::from("b"));
|
||||
correct.insert(["c", "a", "b"].iter().collect::<PathBuf>());
|
||||
correct.insert(["a", "b"].iter().collect::<PathBuf>());
|
||||
assert_eq!(simplify_dir_names(vec!["a/b", "c/a/b/", "b"]), correct);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simplify_dir_dots() {
|
||||
let mut correct = HashSet::new();
|
||||
correct.insert(PathBuf::from("src"));
|
||||
assert_eq!(simplify_dir_names(vec!["src/."]), correct);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_simplify_dir_substring_names() {
|
||||
let mut correct = HashSet::new();
|
||||
correct.insert(PathBuf::from("src"));
|
||||
correct.insert(PathBuf::from("src_v2"));
|
||||
assert_eq!(simplify_dir_names(vec!["src/", "src_v2"]), correct);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_a_parent_of() {
|
||||
assert!(is_a_parent_of("/usr", "/usr/andy"));
|
||||
assert!(is_a_parent_of("/usr", "/usr/andy/i/am/descendant"));
|
||||
assert!(!is_a_parent_of("/usr", "/usr/."));
|
||||
assert!(!is_a_parent_of("/usr", "/usr/"));
|
||||
assert!(!is_a_parent_of("/usr", "/usr"));
|
||||
assert!(!is_a_parent_of("/usr/", "/usr"));
|
||||
assert!(!is_a_parent_of("/usr/andy", "/usr"));
|
||||
assert!(!is_a_parent_of("/usr/andy", "/usr/sibling"));
|
||||
assert!(!is_a_parent_of("/usr/folder", "/usr/folder_not_a_child"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_a_parent_of_root() {
|
||||
assert!(is_a_parent_of("/", "/usr/andy"));
|
||||
assert!(is_a_parent_of("/", "/usr"));
|
||||
assert!(!is_a_parent_of("/", "/"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_ignore_file() {
|
||||
let mut files = HashSet::new();
|
||||
files.insert((10, 20));
|
||||
|
||||
assert!(!should_ignore_file(true, &None, &mut files, 0, 0));
|
||||
|
||||
// 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!(files.contains(&(11, 12)));
|
||||
|
||||
// The same file will be ignored the second time
|
||||
assert!(should_ignore_file(false, &None, &mut files, 11, 12));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_ignore_file_on_different_device() {
|
||||
let mut files = HashSet::new();
|
||||
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
|
||||
assert!(!should_ignore_file(false, &od, &mut files, 2, 99));
|
||||
assert!(!should_ignore_file(true, &od, &mut files, 2, 99));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +1,56 @@
|
||||
use std;
|
||||
use jwalk::DirEntry;
|
||||
#[allow(unused_imports)]
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
fn get_block_size() -> u64 {
|
||||
// All os specific implementations of MetatdataExt seem to define a block as 512 bytes
|
||||
// https://doc.rust-lang.org/std/os/linux/fs/trait.MetadataExt.html#tymethod.st_blocks
|
||||
512
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn get_metadata(
|
||||
d: &std::fs::DirEntry,
|
||||
use_apparent_size: bool,
|
||||
) -> Option<(u64, Option<(u64, u64)>)> {
|
||||
use std::os::linux::fs::MetadataExt;
|
||||
match d.metadata().ok() {
|
||||
Some(md) => {
|
||||
let inode = Some((md.st_ino(), md.st_dev()));
|
||||
if use_apparent_size {
|
||||
Some((md.len(), inode))
|
||||
} else {
|
||||
Some((md.st_blocks() * get_block_size(), inode))
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "unix")]
|
||||
pub fn get_metadata(
|
||||
d: &std::fs::DirEntry,
|
||||
use_apparent_size: bool,
|
||||
) -> Option<(u64, Option<(u64, u64)>)> {
|
||||
#[cfg(target_family = "unix")]
|
||||
pub fn get_metadata(d: &DirEntry, use_apparent_size: bool) -> Option<(u64, u64, u64)> {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
match d.metadata().ok() {
|
||||
Some(md) => {
|
||||
let inode = Some((md.ino(), md.dev()));
|
||||
if use_apparent_size {
|
||||
Some((md.len(), inode))
|
||||
} else {
|
||||
Some((md.blocks() * get_block_size(), inode))
|
||||
}
|
||||
d.metadata.as_ref().unwrap().as_ref().ok().map(|md| {
|
||||
if use_apparent_size {
|
||||
(md.len(), md.ino(), md.dev())
|
||||
} else {
|
||||
(md.blocks() * get_block_size(), md.ino(), md.dev())
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn get_metadata(
|
||||
d: &std::fs::DirEntry,
|
||||
use_apparent_size: bool,
|
||||
) -> Option<(u64, Option<(u64, u64)>)> {
|
||||
use std::os::macos::fs::MetadataExt;
|
||||
match d.metadata().ok() {
|
||||
Some(md) => {
|
||||
let inode = Some((md.st_ino(), md.st_dev()));
|
||||
if use_apparent_size {
|
||||
Some((md.len(), inode))
|
||||
} else {
|
||||
Some((md.st_blocks() * get_block_size(), inode))
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
#[cfg(target_family = "windows")]
|
||||
pub fn get_metadata(d: &DirEntry, _use_apparent_size: bool) -> Option<(u64, u64, u64)> {
|
||||
use winapi_util::file::information;
|
||||
use winapi_util::Handle;
|
||||
|
||||
let h = Handle::from_path_any(d.path()).ok()?;
|
||||
let info = information(&h).ok()?;
|
||||
|
||||
Some((
|
||||
info.file_size(),
|
||||
info.file_index(),
|
||||
info.volume_serial_number(),
|
||||
))
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "unix", target_os = "macos")))]
|
||||
pub fn get_metadata(d: &std::fs::DirEntry, _apparent: bool) -> Option<(u64, Option<(u64, u64)>)> {
|
||||
match d.metadata().ok() {
|
||||
Some(md) => Some((md.len(), None)),
|
||||
None => None,
|
||||
}
|
||||
#[cfg(target_family = "unix")]
|
||||
pub fn get_filesystem<P: AsRef<Path>>(file_path: P) -> Result<u64, io::Error> {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
let metadata = fs::metadata(file_path)?;
|
||||
Ok(metadata.dev())
|
||||
}
|
||||
|
||||
#[cfg(target_family = "windows")]
|
||||
pub fn get_filesystem<P: AsRef<Path>>(file_path: P) -> Result<u64, io::Error> {
|
||||
use winapi_util::file::information;
|
||||
use winapi_util::Handle;
|
||||
|
||||
let h = Handle::from_path_any(file_path)?;
|
||||
let info = information(&h)?;
|
||||
Ok(info.volume_serial_number())
|
||||
}
|
||||
|
||||
259
tests/tests.rs
Normal file
259
tests/tests.rs
Normal file
@@ -0,0 +1,259 @@
|
||||
mod tests_symlinks;
|
||||
|
||||
// File sizes differ on both platform and on the format of the disk.
|
||||
// We can at least test the file names are there
|
||||
#[test]
|
||||
pub fn test_basic_output() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["src/test_dir/"])
|
||||
.stdout()
|
||||
.contains(" ┌─┴ test_dir ")
|
||||
.stdout()
|
||||
.contains(" ┌─┴ many ")
|
||||
.stdout()
|
||||
.contains(" ├── hello_file")
|
||||
.stdout()
|
||||
.contains(" ┌── a_file ")
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// fix! [rivy; 2020-22-01] "windows" result data can vary by host (size seems to be variable by one byte); fix code vs test and re-enable
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_main_basic() {
|
||||
// -c is no color mode - This makes testing much simpler
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-c", "src/test_dir"])
|
||||
.stdout()
|
||||
.is(main_output().as_str())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// fix! [rivy; 2020-22-01] "windows" result data can vary by host (size seems to be variable by one byte); fix code vs test and re-enable
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_main_multi_arg() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-c", "src/test_dir/many/", "src/test_dir/", "src/test_dir"])
|
||||
.stdout()
|
||||
.is(main_output().as_str())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn main_output() -> String {
|
||||
r#"
|
||||
0B ┌── a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
4.0K ├── hello_file│██████████████████████████████████████████████ │ 100%
|
||||
4.0K ┌─┴ many │██████████████████████████████████████████████ │ 100%
|
||||
4.0K ┌─┴ test_dir │██████████████████████████████████████████████ │ 100%
|
||||
"#
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main_output() -> String {
|
||||
r#"
|
||||
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
4.0K ├── hello_file│ ░░░░░░░░░░░░░░░████████████████ │ 33%
|
||||
8.0K ┌─┴ many │ ███████████████████████████████ │ 67%
|
||||
12K ┌─┴ test_dir │██████████████████████████████████████████████ │ 100%
|
||||
"#
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn main_output() -> String {
|
||||
"PRs welcome".to_string()
|
||||
}
|
||||
|
||||
// fix! [rivy; 2020-22-01] "windows" result data can vary by host (size seems to be variable by one byte); fix code vs test and re-enable
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_main_long_paths() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-c", "-p", "src/test_dir"])
|
||||
.stdout()
|
||||
.is(main_output_long_paths().as_str())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn main_output_long_paths() -> String {
|
||||
r#"
|
||||
0B ┌── src/test_dir/many/a_file │░░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
4.0K ├── src/test_dir/many/hello_file│████████████████████████████ │ 100%
|
||||
4.0K ┌─┴ src/test_dir/many │████████████████████████████ │ 100%
|
||||
4.0K ┌─┴ src/test_dir │████████████████████████████ │ 100%
|
||||
"#
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn main_output_long_paths() -> String {
|
||||
r#"
|
||||
0B ┌── src/test_dir/many/a_file │ ░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
4.0K ├── src/test_dir/many/hello_file│ ░░░░░░░░░██████████ │ 33%
|
||||
8.0K ┌─┴ src/test_dir/many │ ███████████████████ │ 67%
|
||||
12K ┌─┴ src/test_dir │████████████████████████████ │ 100%
|
||||
"#
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn main_output_long_paths() -> String {
|
||||
"PRs welcome".to_string()
|
||||
}
|
||||
|
||||
// fix! [rivy; 2020-22-01] "windows" result data can vary by host (size seems to be variable by one byte); fix code vs test and re-enable
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_apparent_size() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-c", "-s", "src/test_dir"])
|
||||
.stdout()
|
||||
.is(output_apparent_size().as_str())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn output_apparent_size() -> String {
|
||||
r#"
|
||||
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
6B ├── hello_file│ ░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
4.0K ┌─┴ many │ ████████████████████████ │ 50%
|
||||
8.0K ┌─┴ test_dir │██████████████████████████████████████████████ │ 100%
|
||||
"#
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn output_apparent_size() -> String {
|
||||
r#"
|
||||
0B ┌── a_file │ ░░░░░░░░░░░░░░░░░░░░░░░░░░█ │ 0%
|
||||
6B ├── hello_file│ ░░░░░░░░░░░░░░░░░░░░░░░░░██ │ 3%
|
||||
134B ┌─┴ many │ ███████████████████████████ │ 58%
|
||||
230B ┌─┴ test_dir │██████████████████████████████████████████████ │ 100%
|
||||
"#
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn output_apparent_size() -> String {
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_reverse_flag() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-c", "-r", "src/test_dir/"])
|
||||
.stdout()
|
||||
.contains(" └─┬ test_dir ")
|
||||
.stdout()
|
||||
.contains(" └─┬ many ")
|
||||
.stdout()
|
||||
.contains(" ├── hello_file")
|
||||
.stdout()
|
||||
.contains(" └── a_file ")
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn test_d_flag_works() {
|
||||
// We should see the top level directory but not the sub dirs / files:
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-d", "1", "-s", "src/test_dir"])
|
||||
.stdout()
|
||||
.doesnt_contain("hello_file")
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// Check against directories and files whos names are substrings of each other
|
||||
// fix! [rivy; 2020-22-01] "windows" result data can vary by host (size seems to be variable by one byte); fix code vs test and re-enable
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_substring_of_names() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-c", "src/test_dir2"])
|
||||
.stdout()
|
||||
.is(no_substring_of_names_output().as_str())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn no_substring_of_names_output() -> String {
|
||||
"
|
||||
4.0K ┌── dir_name_clash│ ████████ │ 17%
|
||||
4.0K │ ┌── hello │ ░░░░░░░████████ │ 17%
|
||||
8.0K ├─┴ dir_substring │ ███████████████ │ 33%
|
||||
4.0K │ ┌── hello │ ░░░░░░░████████ │ 17%
|
||||
8.0K ├─┴ dir │ ███████████████ │ 33%
|
||||
24K ┌─┴ test_dir2 │████████████████████████████████████████████ │ 100%
|
||||
"
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn no_substring_of_names_output() -> String {
|
||||
"
|
||||
4.0K ┌── hello │ ███████████████ │ 33%
|
||||
4.0K ┌─┴ dir_substring │ ███████████████ │ 33%
|
||||
4.0K ├── dir_name_clash│ ███████████████ │ 33%
|
||||
4.0K │ ┌── hello │ ███████████████ │ 33%
|
||||
4.0K ├─┴ dir │ ███████████████ │ 33%
|
||||
12K ┌─┴ test_dir2 │████████████████████████████████████████████ │ 100%
|
||||
"
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn no_substring_of_names_output() -> String {
|
||||
"PRs".into()
|
||||
}
|
||||
|
||||
// fix! [rivy; 2020-22-01] "windows" result data can vary by host (size seems to be variable by one byte); fix code vs test and re-enable
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_unicode_directories() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-c", "src/test_dir3"])
|
||||
.stdout()
|
||||
.is(unicode_dir().as_str())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn unicode_dir() -> String {
|
||||
// The way unicode & asian characters are rendered on the terminal should make this line up
|
||||
"
|
||||
0B ┌── 👩.unicode │ █ │ 0%
|
||||
0B ├── ラウトは難しいです!.japan│ █ │ 0%
|
||||
4.0K ┌─┴ test_dir3 │████████████████████████████████ │ 100%
|
||||
"
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn unicode_dir() -> String {
|
||||
"
|
||||
0B ┌── 👩.unicode │ █ │ 0%
|
||||
0B ├── ラウトは難しいです!.japan│ █ │ 0%
|
||||
0B ┌─┴ test_dir3 │ █ │ 0%
|
||||
"
|
||||
.into()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn unicode_dir() -> String {
|
||||
"".into()
|
||||
}
|
||||
|
||||
// Check against directories and files whos names are substrings of each other
|
||||
#[test]
|
||||
pub fn test_ignore_dir() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-c", "-X", "dir_substring", "src/test_dir2"])
|
||||
.stdout()
|
||||
.doesnt_contain("dir_substring")
|
||||
.unwrap();
|
||||
}
|
||||
119
tests/tests_symlinks.rs
Normal file
119
tests/tests_symlinks.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::panic;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use tempfile::Builder;
|
||||
use tempfile::TempDir;
|
||||
|
||||
// File sizes differ on both platform and on the format of the disk.
|
||||
// Windows: `ln` is not usually an available command; creation of symbolic links requires special enhanced permissions
|
||||
|
||||
fn build_temp_file(dir: &TempDir) -> PathBuf {
|
||||
let file_path = dir.path().join("notes.txt");
|
||||
let mut file = File::create(&file_path).unwrap();
|
||||
writeln!(file, "I am a temp file").unwrap();
|
||||
file_path
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_soft_sym_link() {
|
||||
let dir = Builder::new().tempdir().unwrap();
|
||||
let file = build_temp_file(&dir);
|
||||
let dir_s = dir.path().to_str().unwrap();
|
||||
let file_path_s = file.to_str().unwrap();
|
||||
|
||||
let link_name = dir.path().join("the_link");
|
||||
let link_name_s = link_name.to_str().unwrap();
|
||||
let c = Command::new("ln")
|
||||
.arg("-s")
|
||||
.arg(file_path_s)
|
||||
.arg(link_name_s)
|
||||
.output();
|
||||
assert!(c.is_ok());
|
||||
|
||||
let c = format!(" ┌── {}", link_name_s);
|
||||
let b = format!(" ├── {}", file_path_s);
|
||||
let a = format!("─┴ {}", dir_s);
|
||||
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-p", &dir_s])
|
||||
.stdout()
|
||||
.contains(a.as_str())
|
||||
.stdout()
|
||||
.contains(b.as_str())
|
||||
.stdout()
|
||||
.contains(c.as_str())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_hard_sym_link() {
|
||||
let dir = Builder::new().tempdir().unwrap();
|
||||
let file = build_temp_file(&dir);
|
||||
let dir_s = dir.path().to_str().unwrap();
|
||||
let file_path_s = file.to_str().unwrap();
|
||||
|
||||
let link_name = dir.path().join("the_link");
|
||||
let link_name_s = link_name.to_str().unwrap();
|
||||
let c = Command::new("ln")
|
||||
.arg(file_path_s)
|
||||
.arg(link_name_s)
|
||||
.output();
|
||||
assert!(c.is_ok());
|
||||
|
||||
let a = format!("─┴ {}", dir_s);
|
||||
let b = format!(" ┌── {}", link_name_s);
|
||||
let b2 = format!(" ┌── {}", file_path_s);
|
||||
|
||||
// Because this is a hard link the file and hard link look identical. Therefore
|
||||
// we cannot guarantee which version will appear first.
|
||||
let result = panic::catch_unwind(|| {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-p", dir_s])
|
||||
.stdout()
|
||||
.contains(a.as_str())
|
||||
.stdout()
|
||||
.contains(b.as_str())
|
||||
.unwrap();
|
||||
});
|
||||
if result.is_err() {
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-p", dir_s])
|
||||
.stdout()
|
||||
.contains(a.as_str())
|
||||
.stdout()
|
||||
.contains(b2.as_str())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(target_os = "windows", ignore)]
|
||||
#[test]
|
||||
pub fn test_recursive_sym_link() {
|
||||
let dir = Builder::new().tempdir().unwrap();
|
||||
let dir_s = dir.path().to_str().unwrap();
|
||||
|
||||
let link_name = dir.path().join("the_link");
|
||||
let link_name_s = link_name.to_str().unwrap();
|
||||
|
||||
let c = Command::new("ln")
|
||||
.arg("-s")
|
||||
.arg(dir_s)
|
||||
.arg(link_name_s)
|
||||
.output();
|
||||
assert!(c.is_ok());
|
||||
|
||||
let a = format!("─┬ {}", dir_s);
|
||||
let b = format!(" └── {}", link_name_s);
|
||||
|
||||
assert_cli::Assert::main_binary()
|
||||
.with_args(&["-r", "-p", dir_s])
|
||||
.stdout()
|
||||
.contains(a.as_str())
|
||||
.stdout()
|
||||
.contains(b.as_str())
|
||||
.unwrap();
|
||||
}
|
||||
Reference in New Issue
Block a user