initial
This commit is contained in:
commit
deb48ee511
10 changed files with 828 additions and 0 deletions
9
.editorconfig
Normal file
9
.editorconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_file = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 4
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/target
|
||||
**/*.rs.bk
|
427
Cargo.lock
generated
Normal file
427
Cargo.lock
generated
Normal file
|
@ -0,0 +1,427 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
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.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.5 (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 = "env_logger"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "numtoa"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
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 = "quick-error"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.54"
|
||||
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.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "structopt"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "structopt-derive"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.12 (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 = "termcolor"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termion"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.54 (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.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "trash"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucd-util"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.5"
|
||||
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 = "utf8-ranges"
|
||||
version = "1.0.3"
|
||||
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 = "walkdir"
|
||||
version = "2.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.7"
|
||||
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-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.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wincolor"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "xdg"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
|
||||
"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf"
|
||||
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
|
||||
"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
|
||||
"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe"
|
||||
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
|
||||
"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
|
||||
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
|
||||
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
|
||||
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
|
||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||
"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
|
||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
|
||||
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
|
||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||
"checksum regex 1.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0b2f0808e7d7e4fb1cb07feb6ff2f4bc827938f24f8c2e6a3beb7370af544bdd"
|
||||
"checksum regex-syntax 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d76410686f9e3a17f06128962e0ecc5755870bb890c34820c7af7f1db2e1d48"
|
||||
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
|
||||
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
"checksum structopt 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "fa19a5a708e22bb5be31c1b6108a2a902f909c4b9ba85cba44c06632386bc0ff"
|
||||
"checksum structopt-derive 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)" = "c6d59d0ae8ef8de16e49e3ca7afa16024a3e0dfd974a75ef93fdc5464e34523f"
|
||||
"checksum syn 0.15.38 (registry+https://github.com/rust-lang/crates.io-index)" = "37ea458a750f59ab679b47fef9b6722c586c5742f4cfe18a120bbc807e5e01fd"
|
||||
"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
|
||||
"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330"
|
||||
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
|
||||
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
|
||||
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum walkdir 2.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c7904a7e2bb3cdf0cf5e783f44204a85a37a93151738fa349f06680f59a98b45"
|
||||
"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
|
||||
"checksum xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
|
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "trash"
|
||||
version = "0.1.0"
|
||||
authors = ["Michael Zhang <iptq@protonmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4"
|
||||
env_logger = "0.6"
|
||||
lazy_static = "1.0"
|
||||
log = "0.4"
|
||||
regex = "1.1"
|
||||
structopt = "0.2"
|
||||
walkdir = "2.2"
|
||||
xdg = "2.2"
|
25
README.md
Normal file
25
README.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
trash-cli
|
||||
=========
|
||||
|
||||
rust ver of trash-cli, basic functionality is in, code is probably shit
|
||||
|
||||
full free-desktop compliance when
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
```
|
||||
$ trash put [-r] file1 file2 ...
|
||||
|
||||
$ trash restore
|
||||
[..interactive]
|
||||
|
||||
$ trash list
|
||||
```
|
||||
|
||||
About
|
||||
-----
|
||||
|
||||
Author: Michael Zhang
|
||||
|
||||
License: MIT
|
32
src/errors.rs
Normal file
32
src/errors.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Io(std::io::Error),
|
||||
WalkDir(walkdir::Error),
|
||||
BadTrashInfo(TrashInfoError),
|
||||
ParseDate(chrono::format::ParseError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TrashInfoError {
|
||||
MissingHeader,
|
||||
MissingPath,
|
||||
MissingDate,
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Error::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<walkdir::Error> for Error {
|
||||
fn from(err: walkdir::Error) -> Self {
|
||||
Error::WalkDir(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<chrono::format::ParseError> for Error {
|
||||
fn from(err: chrono::format::ParseError) -> Self {
|
||||
Error::ParseDate(err)
|
||||
}
|
||||
}
|
111
src/main.rs
Normal file
111
src/main.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
mod errors;
|
||||
mod ops;
|
||||
mod trashdir;
|
||||
mod trashinfo;
|
||||
|
||||
use std::fs;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use structopt::StructOpt;
|
||||
use xdg::BaseDirectories;
|
||||
|
||||
use crate::trashdir::TrashDir;
|
||||
|
||||
lazy_static! {
|
||||
static ref XDG: BaseDirectories = BaseDirectories::new().unwrap();
|
||||
}
|
||||
|
||||
#[derive(StructOpt)]
|
||||
enum Command {
|
||||
#[structopt(name = "empty")]
|
||||
Empty,
|
||||
|
||||
#[structopt(name = "list")]
|
||||
List,
|
||||
|
||||
#[structopt(name = "put")]
|
||||
Put {
|
||||
/// The target path to be trashed
|
||||
#[structopt(parse(from_os_str))]
|
||||
paths: Vec<PathBuf>,
|
||||
|
||||
/// Trashes directories recursively
|
||||
#[structopt(long = "recursive", short = "r")]
|
||||
recursive: bool,
|
||||
},
|
||||
|
||||
#[structopt(name = "restore")]
|
||||
Restore,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let cmd = Command::from_args();
|
||||
match cmd {
|
||||
Command::Empty => {
|
||||
println!("TODO");
|
||||
}
|
||||
Command::List => {
|
||||
let home_trash = TrashDir::get_home_trash();
|
||||
for info in home_trash.iter() {
|
||||
let info = match info {
|
||||
Ok(info) => info,
|
||||
Err(err) => {
|
||||
warn!("failed to get file info: {:?}", err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
println!("{}\t{}", info.deletion_date, info.path.to_str().unwrap());
|
||||
}
|
||||
}
|
||||
Command::Put { paths, recursive } => {
|
||||
for path in paths {
|
||||
match crate::ops::put(path, recursive) {
|
||||
Ok(_) => (),
|
||||
Err(err) => error!("error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
Command::Restore => {
|
||||
let home_trash = TrashDir::get_home_trash();
|
||||
let files = home_trash
|
||||
.iter()
|
||||
.filter_map(|entry| match entry {
|
||||
Ok(info) => Some(info),
|
||||
Err(err) => {
|
||||
warn!("failed to get file info: {:?}", err);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
for (i, info) in files.iter().enumerate() {
|
||||
println!(
|
||||
"[{}]\t{}\t{}",
|
||||
i,
|
||||
info.deletion_date,
|
||||
info.path.to_str().unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
let stdin = io::stdin();
|
||||
let mut s = String::new();
|
||||
println!("which file to restore? [0..{}]", files.len());
|
||||
stdin.read_line(&mut s).unwrap();
|
||||
|
||||
match s.trim_end().parse::<usize>() {
|
||||
Ok(i) if i < files.len() => {
|
||||
let info = files.get(i).unwrap();
|
||||
fs::rename(&info.deleted_path, &info.path);
|
||||
}
|
||||
_ => println!("Invalid number."),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
src/ops.rs
Normal file
43
src/ops.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use std::fs::{self, File};
|
||||
use std::path::Path;
|
||||
|
||||
use chrono::Local;
|
||||
|
||||
use crate::errors::Error;
|
||||
use crate::trashdir::TrashDir;
|
||||
use crate::trashinfo::TrashInfo;
|
||||
|
||||
pub fn put(path: impl AsRef<Path>, recursive: bool) -> Result<(), Error> {
|
||||
let path = path.as_ref().canonicalize()?;
|
||||
if path.is_dir() && !recursive {
|
||||
error!("cannot trash directories without --recursive");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let now = Local::now();
|
||||
let elapsed = now.timestamp_millis();
|
||||
|
||||
let home_trash = TrashDir::get_home_trash();
|
||||
let file_name = format!(
|
||||
"{}.{}.trashinfo",
|
||||
elapsed,
|
||||
path.file_name().unwrap().to_str().unwrap()
|
||||
);
|
||||
|
||||
let trash_file_path = home_trash.files_dir()?.join(&file_name);
|
||||
let trash_info_path = home_trash.info_dir()?.join(&file_name);
|
||||
|
||||
let trash_info = TrashInfo {
|
||||
path: path.clone(),
|
||||
deletion_date: now,
|
||||
deleted_path: trash_file_path.clone(),
|
||||
};
|
||||
{
|
||||
let trash_info_file = File::create(trash_info_path)?;
|
||||
trash_info.write(&trash_info_file)?;
|
||||
}
|
||||
|
||||
fs::rename(path, trash_file_path)?;
|
||||
|
||||
Ok(())
|
||||
}
|
73
src/trashdir.rs
Normal file
73
src/trashdir.rs
Normal file
|
@ -0,0 +1,73 @@
|
|||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
use crate::errors::Error;
|
||||
use crate::trashinfo::TrashInfo;
|
||||
use crate::XDG;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TrashDir(PathBuf);
|
||||
|
||||
impl TrashDir {
|
||||
pub fn get_home_trash() -> Self {
|
||||
TrashDir(XDG.get_data_home().join("Trash"))
|
||||
}
|
||||
|
||||
pub fn files_dir(&self) -> Result<PathBuf, Error> {
|
||||
let target = self.0.join("files");
|
||||
if !target.exists() {
|
||||
fs::create_dir_all(&target)?;
|
||||
}
|
||||
Ok(target)
|
||||
}
|
||||
|
||||
pub fn info_dir(&self) -> Result<PathBuf, Error> {
|
||||
let target = self.0.join("info");
|
||||
if !target.exists() {
|
||||
fs::create_dir_all(&target)?;
|
||||
}
|
||||
Ok(target)
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> TrashDirIter {
|
||||
let iter = WalkDir::new(&self.0.join("info"))
|
||||
.contents_first(true)
|
||||
.into_iter()
|
||||
.filter_entry(|entry| {
|
||||
// warn!("path: {:?}", entry.path());
|
||||
match entry.path().extension() {
|
||||
Some(x) => x == "trashinfo",
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
TrashDirIter(Box::new(iter))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TrashDirIter(Box<Iterator<Item = walkdir::Result<DirEntry>>>);
|
||||
|
||||
impl Iterator for TrashDirIter {
|
||||
type Item = Result<TrashInfo, Error>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let entry = {
|
||||
let mut entry;
|
||||
loop {
|
||||
entry = match self.0.next() {
|
||||
Some(Ok(entry)) => entry,
|
||||
Some(Err(err)) => return Some(Err(Error::from(err))),
|
||||
None => return None,
|
||||
};
|
||||
if entry.path().is_dir() {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
entry
|
||||
};
|
||||
|
||||
Some(TrashInfo::from_file(entry.path()).map_err(Error::from))
|
||||
}
|
||||
}
|
91
src/trashinfo.rs
Normal file
91
src/trashinfo.rs
Normal file
|
@ -0,0 +1,91 @@
|
|||
use std::fs::File;
|
||||
use std::io::{self, BufRead, BufReader, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use chrono::{DateTime, Local, TimeZone};
|
||||
use regex::Regex;
|
||||
|
||||
use crate::errors::{Error, TrashInfoError};
|
||||
|
||||
lazy_static! {
|
||||
static ref KEY_VALUE_PATTERN: Regex = Regex::new(r"([A-Za-z]+)\s*=\s*(.*)").unwrap();
|
||||
}
|
||||
|
||||
const DATE_FORMAT: &str = "%Y-%m-%dT%H:%M:%S";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TrashInfo {
|
||||
pub path: PathBuf,
|
||||
pub deletion_date: DateTime<Local>,
|
||||
pub deleted_path: PathBuf,
|
||||
}
|
||||
|
||||
impl TrashInfo {
|
||||
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, Error> {
|
||||
let path = path.as_ref();
|
||||
let original_path = path.to_path_buf();
|
||||
let file = File::open(path)?;
|
||||
let reader = BufReader::new(file);
|
||||
|
||||
let mut path = None;
|
||||
let mut deletion_date = None;
|
||||
|
||||
for (i, line) in reader.lines().enumerate() {
|
||||
let line = line?;
|
||||
|
||||
// first line must be "[Trash Info]"
|
||||
if i == 0 && line != "[Trash Info]" {
|
||||
return Err(Error::BadTrashInfo(TrashInfoError::MissingHeader));
|
||||
}
|
||||
|
||||
// look for path and deletion date
|
||||
let captures = match KEY_VALUE_PATTERN.captures(&line) {
|
||||
Some(captures) => captures,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// safe to unwrap because the parser confirmed their existence
|
||||
let key = captures.get(1).unwrap().as_str();
|
||||
let value = captures.get(2).unwrap().as_str();
|
||||
|
||||
match key {
|
||||
"Path" => {
|
||||
let value = PathBuf::from(value);
|
||||
path = Some(value)
|
||||
}
|
||||
"DeletionDate" => {
|
||||
let date = Local.datetime_from_str(value, DATE_FORMAT)?;
|
||||
deletion_date = Some(date)
|
||||
}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
let path = match path {
|
||||
Some(path) => path,
|
||||
None => return Err(Error::BadTrashInfo(TrashInfoError::MissingPath)),
|
||||
};
|
||||
|
||||
let deletion_date = match deletion_date {
|
||||
Some(deletion_date) => deletion_date,
|
||||
None => return Err(Error::BadTrashInfo(TrashInfoError::MissingDate)),
|
||||
};
|
||||
|
||||
Ok(TrashInfo {
|
||||
path,
|
||||
deletion_date,
|
||||
deleted_path: original_path,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write(&self, mut out: impl Write) -> Result<(), io::Error> {
|
||||
out.write(b"[Trash Info]\n")?;
|
||||
write!(out, "Path={}\n", self.path.to_str().unwrap())?;
|
||||
write!(
|
||||
out,
|
||||
"DeletionDate={}\n",
|
||||
self.deletion_date.format(DATE_FORMAT)
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue