From deb48ee51144f372754514450e8ed3a75c8b15be Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Wed, 26 Jun 2019 02:46:46 -0500 Subject: [PATCH] initial --- .editorconfig | 9 + .gitignore | 2 + Cargo.lock | 427 +++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 15 ++ README.md | 25 +++ src/errors.rs | 32 ++++ src/main.rs | 111 ++++++++++++ src/ops.rs | 43 +++++ src/trashdir.rs | 73 ++++++++ src/trashinfo.rs | 91 ++++++++++ 10 files changed, 828 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/errors.rs create mode 100644 src/main.rs create mode 100644 src/ops.rs create mode 100644 src/trashdir.rs create mode 100644 src/trashinfo.rs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4266da6 --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..53eaa21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +**/*.rs.bk diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..af43332 --- /dev/null +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a507ae4 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "trash" +version = "0.1.0" +authors = ["Michael Zhang "] +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" diff --git a/README.md b/README.md new file mode 100644 index 0000000..3bb11f8 --- /dev/null +++ b/README.md @@ -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 diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..3af2c77 --- /dev/null +++ b/src/errors.rs @@ -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 for Error { + fn from(err: std::io::Error) -> Self { + Error::Io(err) + } +} + +impl From for Error { + fn from(err: walkdir::Error) -> Self { + Error::WalkDir(err) + } +} + +impl From for Error { + fn from(err: chrono::format::ParseError) -> Self { + Error::ParseDate(err) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8bdb1d3 --- /dev/null +++ b/src/main.rs @@ -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, + + /// 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::>(); + 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::() { + Ok(i) if i < files.len() => { + let info = files.get(i).unwrap(); + fs::rename(&info.deleted_path, &info.path); + } + _ => println!("Invalid number."), + } + } + } +} diff --git a/src/ops.rs b/src/ops.rs new file mode 100644 index 0000000..a28ee7f --- /dev/null +++ b/src/ops.rs @@ -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, 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(()) +} diff --git a/src/trashdir.rs b/src/trashdir.rs new file mode 100644 index 0000000..7a0818f --- /dev/null +++ b/src/trashdir.rs @@ -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 { + let target = self.0.join("files"); + if !target.exists() { + fs::create_dir_all(&target)?; + } + Ok(target) + } + + pub fn info_dir(&self) -> Result { + 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>>); + +impl Iterator for TrashDirIter { + type Item = Result; + + fn next(&mut self) -> Option { + 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)) + } +} diff --git a/src/trashinfo.rs b/src/trashinfo.rs new file mode 100644 index 0000000..d04df1f --- /dev/null +++ b/src/trashinfo.rs @@ -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, + pub deleted_path: PathBuf, +} + +impl TrashInfo { + pub fn from_file(path: impl AsRef) -> Result { + 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(()) + } +}