diff --git a/ark-cli/.github/workflows/rust.yml b/ark-cli/.github/workflows/rust.yml new file mode 100644 index 00000000..84779b0a --- /dev/null +++ b/ark-cli/.github/workflows/rust.yml @@ -0,0 +1,30 @@ +name: Build CLI tool + +on: [push] + +env: + CARGO_TERM_COLOR: always + +jobs: + check: + name: Build ARK-CLI + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt, clippy + + - name: Check + run: cargo check + + - name: Format + run: | + cargo fmt --all -- --check + cargo clippy + + - name: Build Release + run: cargo build --verbose --release diff --git a/ark-cli/.gitignore b/ark-cli/.gitignore new file mode 100644 index 00000000..9869c062 --- /dev/null +++ b/ark-cli/.gitignore @@ -0,0 +1,3 @@ +target +.ark +.vscode \ No newline at end of file diff --git a/ark-cli/Cargo.lock b/ark-cli/Cargo.lock new file mode 100644 index 00000000..c11ccdcd --- /dev/null +++ b/ark-cli/Cargo.lock @@ -0,0 +1,2999 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1" + +[[package]] +name = "ark-cli" +version = "0.1.0" +dependencies = [ + "anyhow", + "arklib", + "chrono", + "clap", + "env_logger", + "fs_extra", + "home", + "serde", + "serde_json", + "thiserror", + "tokio", + "url", + "walkdir", +] + +[[package]] +name = "arklib" +version = "0.1.0" +source = "git+https://github.com/ARK-Builders/arklib?rev=2c7ceda#2c7ceda1a6c7285e406b64762d6a977c5ab8000a" +dependencies = [ + "anyhow", + "canonical-path", + "crc32fast", + "env_logger", + "fastrand", + "flate2", + "fs_extra", + "image", + "itertools", + "lazy_static", + "libloading", + "log", + "once_cell", + "pathdiff", + "pdfium-render", + "reqwest", + "ring", + "scraper", + "serde", + "serde_json", + "tar", + "target-lexicon", + "thiserror", + "tokio", + "ureq", + "url", + "uuid", + "walkdir", + "zip", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bindgen" +version = "0.69.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ffcebc3849946a7170a05992aac39da343a90676ab392c51a4280981d6379c2" +dependencies = [ + "bitflags 2.4.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.52", + "which", +] + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "canonical-path" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e9e01327e6c86e92ec72b1c798d4a94810f147209bbe3ffab6a86954937a6f" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-targets 0.52.0", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "atty", + "bitflags 1.3.2", + "clap_derive", + "clap_lex", + "indexmap 1.9.3", + "once_cell", + "strsim", + "termcolor", + "textwrap", +] + +[[package]] +name = "clap_derive" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa 0.4.8", + "matches", + "phf 0.8.0", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.52", +] + +[[package]] +name = "deranged" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eb30d70a07a3b04884d2677f06bec33509dc67ca60d92949e5535352d3191dc" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dtoa-short" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" +dependencies = [ + "dtoa", +] + +[[package]] +name = "ego-tree" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "exr" +version = "1.71.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832a761f35ab3e6664babfbdc6cef35a4860e816ec3916dcfd0882954e98a8a8" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fdeflate" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.52.0", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" + +[[package]] +name = "futures-sink" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" + +[[package]] +name = "futures-task" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" + +[[package]] +name = "futures-util" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "h2" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.10", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa 1.0.10", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "image" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", + "qoi", + "tiff", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "iter_tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531cafdc99b3b3252bb32f5620e61d56b19415efc19900b12d1b2e7483854897" +dependencies = [ + "itertools", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" +dependencies = [ + "rayon", +] + +[[package]] +name = "js-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf 0.10.1", + "phf_codegen 0.10.0", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "maybe-owned" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4facc753ae494aeb6e3c22f839b158aebd4f9270f55cd3c79906c45476c47ab4" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.3", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cde4d2d9200ad5909f8dac647e29482e07c3a35de8a13fce7c9c7747ad9f671" +dependencies = [ + "bitflags 2.4.1", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1665caf8ab2dc9aef43d1c0023bd904633a6a05cb30b0ad59bec2ae986e57a7" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "pdfium-render" +version = "0.7.26" +source = "git+https://github.com/ajrcarey/pdfium-render?rev=d2559c1#d2559c10d27392cc48e51a55d80fffbe6fc87b5c" +dependencies = [ + "bindgen", + "bitflags 1.3.2", + "bytes", + "console_error_panic_hook", + "console_log", + "image", + "iter_tools", + "js-sys", + "lazy_static", + "libloading", + "log", + "maybe-owned", + "utf16string", + "vecmath", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_macros", + "phf_shared 0.8.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piston-float" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad78bf43dcf80e8f950c92b84f938a0fc7590b7f6866fbcbeca781609c115590" + +[[package]] +name = "pkg-config" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" + +[[package]] +name = "png" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.52", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.11", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "reqwest" +version = "0.11.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "ring" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b" +dependencies = [ + "cc", + "getrandom 0.2.11", + "libc", + "spin", + "untrusted", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scraper" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5684396b456f3eb69ceeb34d1b5cb1a2f6acf7ca4452131efa3ba0ee2c2d0a70" +dependencies = [ + "cssparser", + "ego-tree", + "getopts", + "html5ever", + "matches", + "selectors", + "smallvec", + "tendril", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "selectors" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "matches", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", + "thin-slice", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa 1.0.10", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.10", + "ryu", + "serde", +] + +[[package]] +name = "servo_arc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.52" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.12.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a" + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "termcolor" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + +[[package]] +name = "thiserror" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "tiff" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "time" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +dependencies = [ + "deranged", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cdd25c339e200129fe4de81451814e5228c9b771d57378817d6117cc2b3f97" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-webpki", + "url", + "webpki-roots", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16string" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b62a1e85e12d5d712bf47a85f426b73d303e2d00a90de5f3004df3596e9d216" +dependencies = [ + "byteorder", +] + +[[package]] +name = "uuid" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +dependencies = [ + "getrandom 0.2.11", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vecmath" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ae1e0d85bca567dee1dcf87fb1ca2e792792f66f87dced8381f99cd91156a" +dependencies = [ + "piston-float", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.52", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.52", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" + +[[package]] +name = "web-sys" +version = "0.3.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-roots" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" + +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "xattr" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7dae5072fe1f8db8f8d29059189ac175196e410e40ba42d5d4684ae2f750995" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] diff --git a/ark-cli/Cargo.toml b/ark-cli/Cargo.toml new file mode 100644 index 00000000..1c257ce7 --- /dev/null +++ b/ark-cli/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "ark-cli" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "ark-cli" + +[dependencies] +tokio = { version = "1.35.1", features = ["full"] } +arklib = { git = "https://github.com/ARK-Builders/arklib", rev = "2c7ceda" } +clap = { version = "3.0.10", features = ["derive"] } +env_logger = "0.9.0" +fs_extra = "1.2.0" +walkdir = "2.3.2" +home = "0.5.3" +url = { version = "2.2.2", features = ["serde"] } +serde_json = "1.0.82" +serde = { version = "1.0.138", features = ["derive"] } +chrono = "0.4.34" +anyhow = "1.0.80" +thiserror = "1.0.57" diff --git a/ark-cli/LICENSE b/ark-cli/LICENSE new file mode 100644 index 00000000..ea8b0971 --- /dev/null +++ b/ark-cli/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 ARK Builders + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ark-cli/README.md b/ark-cli/README.md new file mode 100644 index 00000000..da191e1e --- /dev/null +++ b/ark-cli/README.md @@ -0,0 +1,111 @@ +# Ark-CLI + +### Installation + +To compile you will need openssl libraries and headers: + +```shell +# macOS (Homebrew) +$ brew install openssl@3 + +# macOS (MacPorts) +$ sudo port install openssl + +# macOS (pkgsrc) +$ sudo pkgin install openssl + +# Arch Linux +$ sudo pacman -S pkg-config openssl + +# Debian and Ubuntu +$ sudo apt-get install pkg-config libssl-dev + +# Fedora +$ sudo dnf install pkg-config perl-FindBin openssl-devel + +# Alpine Linux +$ apk add pkgconfig openssl-dev +``` + +### Usage + +```shell +ark-cli + +OPTIONS: + -h, --help Print help information + +SUBCOMMANDS: + backup + collisions + help Print this message or the help of the given subcommand(s) + link + monitor + render + +``` + +#### Backup +```shell +USAGE: + ark-cli backup [ROOTS_CFG] + +ARGS: + + +OPTIONS: + -h, --help Print help information +``` + +#### Collisions +```shell +USAGE: + ark-cli collisions [ROOT_DIR] + +ARGS: + + +OPTIONS: + -h, --help Print help information +``` + +#### Link +```shell +USAGE: + ark-cli link + +OPTIONS: + -h, --help Print help information + +SUBCOMMANDS: + create + help Print this message or the help of the given subcommand(s) + load +``` + +#### Monitor +```shell +USAGE: + ark-cli monitor [ARGS] + +ARGS: + + + +OPTIONS: + -h, --help Print help information +``` + +#### Render +```shell +USAGE: + ark-cli render [ARGS] + +ARGS: + + + +OPTIONS: + -h, --help Print help information + +``` \ No newline at end of file diff --git a/ark-cli/USAGE.md b/ark-cli/USAGE.md new file mode 100644 index 00000000..fe48aac2 --- /dev/null +++ b/ark-cli/USAGE.md @@ -0,0 +1,192 @@ +# Usage + +## Get started + +Create an empty dir: +``` +mkdir /tmp/test +cd /tmp/test +``` + +Let's fill it with something. One of the simplest ways to create resources it is to save a link to web page using `ark-cli link` command: +``` +$ ark-cli link create . http://google.com goo +$ ark-cli link create . http://duckduckgo.com duck +``` + +We can use `ark-cli list` to see just created resources: +``` +22-207093268 +18-1909444406 +``` + +These are just ids, derived from the URLs themselves. + +Now, the dir structure should resemble this: +``` +/tmp/test +└───.ark + ├───cache + │ ├───metadata + │ └───previews + │ + └───user + ├───properties + ├───scores + └───tags +``` + +### Label your data + +You can attach various metadata to your data, e.g. tags: +``` +$ ark-cli file append . tags 22-207093268 search,engine +``` + +The same way we can append scores: +``` +$ ark-cli file append . scores 22-207093268 15 +``` + +Generic metadata is possible using JSON-based properties: +``` +$ ark-cli file append . properties 22-207093268 favorites:false,ai:true --format=json +``` + +### Navigate your data + +The simplest command to observe your resources is `list`: +``` +$ ark-cli list + +18-1909444406 +22-207093268 +``` + +You can also target this command to other folders: +``` +$ ark-cli list ~/Pictures/ + +58922-3276384608 +62591-2492670715 +723145-720506115 +125308-3041567246 +``` + +But it's a bit boring and doesn't really tell anything, right? Various flags should be used to gain more knowledge about your collections of resources: +* `--entry=id|path|both|link` to show the path,the id or both of a resource +* `--modified` to show or not the last modified timestamp of a resource +* `--tags=true` to show or not the tags for every resource +* `--scores=true` to show or not the scores for every resource +* `--sort=asc|desc` to sort resources by asc or dsc order of scores +* `--filter=query` to filter resources by their tags + +For instance, you can list files with their paths and attached tags: +``` +$ ark-cli list -pt + +30-4257856154 search +18-1909444406 hello +22-207093268 search,engine +38-103010298 NO_TAGS +``` + +You Can list the links of the files + +``` +$ark-cli list -l + +https://google.com +https://news.ycombinator.com +https://youtube.com +https://github.com + +``` + +Or, sort by score: +``` +$ ark-cli list -s --sort=asc + +30-4257856154 NO_SCORE +18-1909444406 2 +38-103010298 10 +22-207093268 15 +``` + +Finally, you can filter resources using their tags: +``` +$ /tmp/ark-cli list -t --filter=search + +30-4257856154 search +22-207093268 search,engine +``` + +## :zap: Low-level utilities :zap: + +There are commands which could be useful with time, when you grasp the basic concepts. Some of these commands also can be useful for debugging [ArkLib](https://github.com/ARK-Builders/ark-rust). + +### Retrieve the metadata + +You can read these properties: +``` +$ ark-cli file read . properties 22-207093268 +{"ai":"true","desc":null,"favorites":"false","title":"duck"} +``` + +As well as scores or tags: +``` +$ ark-cli file read . scores 22-207093268 +15 +$ ark-cli file read . tags 22-207093268 +search,engine +``` + +### Inspect storages + +It's also possible to list resources having some metadata in a particular storage: +``` +$ ark-cli storage list . properties +22-207093268 +18-1909444406 + +$ ark-cli storage list . tags +22-207093268 + +$ ark-cli storage list . scores +22-207093268 +``` + +Note that, in this example, resource with id `18-1909444406` is listed only in `properties` storage since it lacks any metadata in `tags` and `scores` storages. The `ark-cli storage list` command only lists entries of a particular storage, not all resources. + +### Inspect versions + +For delving into history of storage mutations, we made `--versions` flag: +``` +$ ark-cli storage list . properties --versions=true +version name machine path +2 22-207093268 0592a937-a5d1-4843-8f03-ae0d6a9e77b5 ./.ark/user/properties/22-207093268/22-207093268_0592a937-a5d1-4843-8f03-ae0d6a9e77b5.2 +1 18-1909444406 0592a937-a5d1-4843-8f03-ae0d6a9e77b5 ./.ark/user/properties/18-1909444406/18-1909444406_0592a937-a5d1-4843-8f03-ae0d6a9e77b5.1 +``` + +Each storage mutation made by `ark-cli file append` or `ark-cli file insert` commands increases the number in `version` column. Versions help to prevent dirty-writes caused by using same storages by separate apps, or devices. + +The `properties` storage is _folder-based_, but same command can be used with _file-based_ storages like `tags`: +``` +$ ark-cli storage list . tags --versions=true +Loading app id at /home/kirill/.ark... +id value +22-207093268 search,engine + +$ ark-cli file append . tags 22-207093268 wow +$ ark-cli storage list . tags --versions=true +id value +22-207093268 search,engine +22-207093268 wow + +$ ark-cli file append . tags 22-207093268 one_more_time +$ ark-cli storage list . tags --versions=true +id value +22-207093268 search,engine +22-207093268 wow +22-207093268 one_more_time +``` diff --git a/ark-cli/ark-shelf/16-720383087 b/ark-cli/ark-shelf/16-720383087 new file mode 100644 index 00000000..4b23f03e --- /dev/null +++ b/ark-cli/ark-shelf/16-720383087 @@ -0,0 +1 @@ +http://bing.com/ \ No newline at end of file diff --git a/ark-cli/ark-shelf/18-1909444406 b/ark-cli/ark-shelf/18-1909444406 new file mode 100644 index 00000000..d2a553a6 --- /dev/null +++ b/ark-cli/ark-shelf/18-1909444406 @@ -0,0 +1 @@ +http://google.com/ \ No newline at end of file diff --git a/ark-cli/rustfmt.toml b/ark-cli/rustfmt.toml new file mode 100644 index 00000000..2f7bc3e1 --- /dev/null +++ b/ark-cli/rustfmt.toml @@ -0,0 +1,17 @@ +verbose = "Verbose" +tab_spaces = 4 + +max_width = 80 +chain_width = 50 +single_line_if_else_max_width = 30 + +force_explicit_abi = true + +report_todo = "Always" +report_fixme = "Always" + +reorder_imports = true + +wrap_comments = true + +newline_style = "Unix" diff --git a/ark-cli/src/commands/file.rs b/ark-cli/src/commands/file.rs new file mode 100644 index 00000000..a9149137 --- /dev/null +++ b/ark-cli/src/commands/file.rs @@ -0,0 +1,142 @@ +use crate::error::AppError; +use crate::models::{format, format::Format}; +use arklib::{modify, modify_json, AtomicFile, Result as ArklibResult}; + +pub fn file_append( + atomic_file: &AtomicFile, + content: &str, + format: Format, +) -> Result<(), AppError> { + match format { + Format::Raw => Ok(modify(atomic_file, |current| { + let mut combined_vec: Vec = current.to_vec(); + combined_vec.extend_from_slice(content.as_bytes()); + combined_vec + })?), + Format::KeyValue => { + let values = format::key_value_to_str(content)?; + + Ok(append_json(atomic_file, values.to_vec())?) + } + } +} + +pub fn file_insert( + atomic_file: &AtomicFile, + content: &str, + format: Format, +) -> Result<(), AppError> { + match format { + Format::Raw => { + Ok(modify(atomic_file, |_| content.as_bytes().to_vec())?) + } + Format::KeyValue => { + let values = format::key_value_to_str(content)?; + + modify_json( + atomic_file, + |current: &mut Option| { + let mut new = serde_json::Map::new(); + for (key, value) in &values { + new.insert( + key.clone(), + serde_json::Value::String(value.clone()), + ); + } + *current = Some(serde_json::Value::Object(new)); + }, + ) + .map_err(|e| AppError::FileOperationError(e.to_string())) + } + } +} + +fn append_json( + atomic_file: &AtomicFile, + data: Vec<(String, String)>, +) -> ArklibResult<()> { + modify_json(atomic_file, |current: &mut Option| { + let current_data = match current { + Some(current) => { + if let Ok(value) = serde_json::to_value(current) { + match value { + serde_json::Value::Object(map) => Some(map), + _ => None, + } + } else { + None + } + } + + None => None, + }; + let mut new = serde_json::Map::new(); + + if current_data.is_none() { + for (key, value) in &data { + new.insert( + key.clone(), + serde_json::Value::String(value.clone()), + ); + } + *current = Some(serde_json::Value::Object(new)); + } else if let Some(values) = current_data { + for (key, value) in &values { + new.insert(key.clone(), value.clone()); + } + + for (key, value) in &data { + new.insert( + key.clone(), + serde_json::Value::String(value.clone()), + ); + } + *current = Some(serde_json::Value::Object(new)); + } + })?; + + Ok(()) +} + +pub fn format_line( + version: A, + name: B, + machine: C, + path: D, +) -> String +where + A: std::fmt::Display, + B: std::fmt::Display, + C: std::fmt::Display, + D: std::fmt::Display, +{ + format!("{: <8} {: <14} {: <36} {}", version, name, machine, path) +} + +pub fn format_file(file: &AtomicFile) -> Option { + let current = file.load().ok()?; + + if current.version == 0 { + return None; + } + + let mut split = current + .path + .file_name() + .expect("Not a file") + .to_str() + .unwrap() + .split('_'); + + let name = split.next().unwrap(); + + let machine = split.next().unwrap(); + let machine = &machine[..machine.len() - 2]; + + Some(format_line( + current.version, + name, + machine, + current.path.display(), + )) +} diff --git a/ark-cli/src/commands/link.rs b/ark-cli/src/commands/link.rs new file mode 100644 index 00000000..fee36cc5 --- /dev/null +++ b/ark-cli/src/commands/link.rs @@ -0,0 +1,54 @@ +use arklib::{id::ResourceId, link::Link}; +use std::path::PathBuf; +use url::Url; + +use crate::error::AppError; +use crate::util::provide_index; // Import your custom AppError type + +pub async fn create_link( + root: &PathBuf, + url: &str, + title: &str, + desc: Option, +) -> Result<(), AppError> { + let url = Url::parse(url) + .map_err(|_| AppError::LinkCreationError("Invalid url".to_owned()))?; + let link: Link = Link::new(url, title.to_owned(), desc.to_owned()); + link.save(root, true) + .await + .map_err(|e| AppError::LinkCreationError(e.to_string())) +} + +pub fn load_link( + root: &PathBuf, + file_path: &Option, + id: &Option, +) -> Result { + let path_from_index = id.map(|id| { + let index = provide_index(root); + index.id2path[&id].as_path().to_path_buf() + }); + let path_from_user = file_path; + + let path = match (path_from_user, path_from_index) { + (Some(path), Some(path2)) => { + if path.canonicalize()? != path2 { + Err(AppError::LinkLoadError(format!( + "Path {:?} was requested. But id {} maps to path {:?}", + path, + id.unwrap(), + path2, + ))) + } else { + Ok(path.to_path_buf()) + } + } + (Some(path), None) => Ok(path.to_path_buf()), + (None, Some(path)) => Ok(path), + (None, None) => Err(AppError::LinkLoadError( + "Provide a path or id for request.".to_owned(), + ))?, + }?; + + Ok(arklib::link::Link::load(root, &path)?) +} diff --git a/ark-cli/src/commands/mod.rs b/ark-cli/src/commands/mod.rs new file mode 100644 index 00000000..7ee11691 --- /dev/null +++ b/ark-cli/src/commands/mod.rs @@ -0,0 +1,2 @@ +pub mod file; +pub mod link; diff --git a/ark-cli/src/error.rs b/ark-cli/src/error.rs new file mode 100644 index 00000000..59bd92d6 --- /dev/null +++ b/ark-cli/src/error.rs @@ -0,0 +1,57 @@ +use arklib::ArklibError; +use std::io; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum InlineJsonParseError { + #[error("Invalid JSON: entries must be key-value pairs seperated by ':'")] + InvalidKeyValPair, +} + +#[derive(Debug, Error)] +pub enum AppError { + #[error("Couldn't retrieve home directory!")] + HomeDirNotFound, + + #[error("Couldn't create .ark directory: {0}")] + ArkDirectoryCreationError(String), + + #[error("Couldn't load app id: {0}")] + AppIdLoadError(String), + + #[error("Could not provide/read index: {0}")] + IndexError(String), + + #[error("Could not create storage: {0}")] + StorageCreationError(String), + + #[error("Failed to create link: {0}")] + LinkCreationError(String), + + #[error("Could not load link: {0}")] + LinkLoadError(String), + + #[error("File operation error: {0}")] + FileOperationError(String), + + #[error("Failed to create backup: {0}")] + BackupCreationError(String), + + #[error("Unknown render option")] + InvalidRenderOption, + + #[error("Storage not found: {0}")] + StorageNotFound(String), + + #[error("Invalid entry option")] + InvalidEntryOption, + + #[error(transparent)] + IoError(#[from] io::Error), + + #[error(transparent)] + ArklibError(#[from] ArklibError), + + #[error(transparent)] + InlineJsonParseError(#[from] InlineJsonParseError), +} diff --git a/ark-cli/src/main.rs b/ark-cli/src/main.rs new file mode 100644 index 00000000..51b441ea --- /dev/null +++ b/ark-cli/src/main.rs @@ -0,0 +1,623 @@ +use std::fs::{create_dir_all, File}; +use std::io::{Read, Write}; +use std::path::PathBuf; +use std::str::FromStr; + +use arklib::id::ResourceId; +use arklib::pdf::PDFQuality; +use arklib::{app_id, provide_index}; + +use chrono::prelude::DateTime; +use chrono::Utc; + +use clap::Parser; + +use fs_extra::dir::{self, CopyOptions}; + +use home::home_dir; + +use crate::models::cli::{Command, FileCommand, Link, StorageCommand}; +use crate::models::entry::EntryOutput; +use crate::models::format::Format; +use crate::models::sort::Sort; +use crate::models::storage::{Storage, StorageType}; + +use crate::error::AppError; + +use util::{ + discover_roots, monitor_index, provide_root, read_storage_value, + storages_exists, timestamp, translate_storage, +}; + +mod commands; +mod error; +mod models; +mod util; + +const ARK_CONFIG: &str = ".config/ark"; +const ARK_BACKUPS_PATH: &str = ".ark-backups"; +const ROOTS_CFG_FILENAME: &str = "roots"; + +struct StorageEntry { + path: Option, + resource: Option, + content: Option, + tags: Option>, + scores: Option, + datetime: Option, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + env_logger::init(); + + let args = models::cli::Cli::parse(); + + let app_id_dir = home_dir().ok_or(AppError::HomeDirNotFound)?; + + let ark_dir = app_id_dir.join(".ark"); + + if !ark_dir.exists() { + std::fs::create_dir(&ark_dir) + .map_err(|e| AppError::ArkDirectoryCreationError(e.to_string()))?; + } + + println!("Loading app id at {}...", ark_dir.display()); + + let _ = app_id::load(ark_dir) + .map_err(|e| AppError::AppIdLoadError(e.to_string()))?; + + match &args.command { + Command::List { + entry, + entry_id, + entry_path, + entry_link, + + root_dir, + modified, + tags, + scores, + sort, + filter, + } => { + let root = provide_root(root_dir)?; + + let entry_output = match (entry, entry_id, entry_path, entry_link) { + (Some(e), false, false, false) => Ok(*e), + (None, true, false, false) => Ok(EntryOutput::Id), + (None, false, true, false) => Ok(EntryOutput::Path), + (None, true, true, false) => Ok(EntryOutput::Both), + (None, false, false, false) => Ok(EntryOutput::Id), + (None, false, false, true) => Ok(EntryOutput::Link), + _ => Err(AppError::InvalidEntryOption), + }?; + + let mut storage_entries: Vec = provide_index(&root) + .map_err(|_| { + AppError::IndexError("Could not provide index".to_owned()) + })? + .read() + .map_err(|_| { + AppError::IndexError("Could not read index".to_owned()) + })? + .path2id + .iter() + .filter_map(|(path, resource)| { + let tags = if *tags { + Some( + read_storage_value( + &root, + "tags", + &resource.id.to_string(), + &None, + ) + .map_or(vec![], |s| { + s.split(',') + .map(|s| s.trim().to_string()) + .collect::>() + }), + ) + } else { + None + }; + + let scores = if *scores { + Some( + read_storage_value( + &root, + "scores", + &resource.id.to_string(), + &None, + ) + .map_or(0, |s| s.parse::().unwrap_or(0)), + ) + } else { + None + }; + + let datetime = if *modified { + let format = "%b %e %H:%M %Y"; + Some( + DateTime::::from(resource.modified) + .format(format) + .to_string(), + ) + } else { + None + }; + + let (path, resource, content) = match entry_output { + EntryOutput::Both => ( + Some(path.to_owned().into_path_buf()), + Some(resource.id), + None, + ), + EntryOutput::Path => { + (Some(path.to_owned().into_path_buf()), None, None) + } + EntryOutput::Id => (None, Some(resource.id), None), + EntryOutput::Link => match File::open(&path) { + Ok(mut file) => { + let mut contents = String::new(); + match file.read_to_string(&mut contents) { + Ok(_) => (None, None, Some(contents)), + Err(_) => return None, + } + } + Err(_) => return None, + }, + }; + + Some(StorageEntry { + path, + resource, + content, + tags, + scores, + datetime, + }) + }) + .collect::>(); + + match sort { + Some(Sort::Asc) => { + storage_entries.sort_by(|a, b| a.datetime.cmp(&b.datetime)) + } + + Some(Sort::Desc) => { + storage_entries.sort_by(|a, b| b.datetime.cmp(&a.datetime)) + } + None => (), + }; + + if let Some(filter) = filter { + storage_entries.retain(|entry| { + entry + .tags + .as_ref() + .map(|tags| tags.contains(filter)) + .unwrap_or(false) + }); + } + + let no_tags = "NO_TAGS"; + let no_scores = "NO_SCORE"; + + let longest_path = storage_entries + .iter() + .map(|entry| { + if let Some(path) = entry.path.as_ref() { + path.display().to_string().len() + } else { + 0 + } + }) + .max_by(|a, b| a.cmp(b)) + .unwrap_or(0); + + let longest_id = storage_entries.iter().fold(0, |acc, entry| { + if let Some(resource) = &entry.resource { + let id_len = resource.to_string().len(); + if id_len > acc { + id_len + } else { + acc + } + } else { + acc + } + }); + + let longest_tags = storage_entries.iter().fold(0, |acc, entry| { + let tags_len = entry + .tags + .as_ref() + .map(|tags| { + if tags.is_empty() { + no_tags.len() + } else { + tags.join(", ").len() + } + }) + .unwrap_or(0); + if tags_len > acc { + tags_len + } else { + acc + } + }); + + let longest_scores = + storage_entries.iter().fold(0, |acc, entry| { + let scores_len = entry + .scores + .as_ref() + .map(|score| { + if *score == 0 { + no_scores.len() + } else { + score.to_string().len() + } + }) + .unwrap_or(0); + if scores_len > acc { + scores_len + } else { + acc + } + }); + + let longest_datetime = + storage_entries.iter().fold(0, |acc, entry| { + let datetime_len = entry + .datetime + .as_ref() + .map(|datetime| datetime.len()) + .unwrap_or(0); + if datetime_len > acc { + datetime_len + } else { + acc + } + }); + + let longest_content = + storage_entries.iter().fold(0, |acc, entry| { + let content_len = entry + .content + .as_ref() + .map(|content| content.len()) + .unwrap_or(0); + if content_len > acc { + content_len + } else { + acc + } + }); + + for entry in &storage_entries { + let mut output = String::new(); + + if let Some(content) = &entry.content { + output.push_str(&format!( + "{:width$} ", + content, + width = longest_content + )); + } + + if let Some(path) = &entry.path { + output.push_str(&format!( + "{:width$} ", + path.display(), + width = longest_path + )); + } + + if let Some(resource) = &entry.resource { + output.push_str(&format!( + "{:width$} ", + resource.to_string(), + width = longest_id + )); + } + + if let Some(tags) = &entry.tags { + let tags_out = if tags.is_empty() { + no_tags.to_owned() + } else { + tags.join(", ") + }; + + output.push_str(&format!( + "{:width$} ", + tags_out, + width = longest_tags + )); + } + + if let Some(scores) = &entry.scores { + let scores_out = if *scores == 0 { + no_scores.to_owned() + } else { + scores.to_string() + }; + + output.push_str(&format!( + "{:width$} ", + scores_out, + width = longest_scores + )); + } + + if let Some(datetime) = &entry.datetime { + output.push_str(&format!( + "{:width$} ", + datetime, + width = longest_datetime + )); + } + + println!("{}", output); + } + } + Command::Backup { roots_cfg } => { + let timestamp = timestamp().as_secs(); + let backup_dir = home_dir() + .ok_or(AppError::HomeDirNotFound)? + .join(ARK_BACKUPS_PATH) + .join(timestamp.to_string()); + + if backup_dir.is_dir() { + println!("Wait at least 1 second, please!"); + std::process::exit(0) + } + + println!("Preparing backup:"); + let roots = discover_roots(roots_cfg)?; + + let (valid, invalid): (Vec, Vec) = roots + .into_iter() + .partition(|root| storages_exists(root)); + + if !invalid.is_empty() { + println!("These folders don't contain any storages:"); + invalid + .into_iter() + .for_each(|root| println!("\t{}", root.display())); + } + + if valid.is_empty() { + println!("Nothing to backup. Bye!"); + std::process::exit(0) + } + + create_dir_all(&backup_dir).map_err(|_| { + AppError::BackupCreationError( + "Couldn't create backup directory!".to_owned(), + ) + })?; + + let mut roots_cfg_backup = + File::create(backup_dir.join(ROOTS_CFG_FILENAME))?; + + valid.iter().for_each(|root| { + let res = writeln!(roots_cfg_backup, "{}", root.display()); + if let Err(e) = res { + println!("Failed to write root to backup file: {}", e); + } + }); + + println!("Performing backups:"); + valid + .into_iter() + .enumerate() + .for_each(|(i, root)| { + println!("\tRoot {}", root.display()); + let storage_backup = backup_dir.join(i.to_string()); + + let mut options = CopyOptions::new(); + options.overwrite = true; + options.copy_inside = true; + + let result = dir::copy( + root.join(arklib::ARK_FOLDER), + storage_backup, + &options, + ); + + if let Err(e) = result { + println!("\t\tFailed to copy storages!\n\t\t{}", e); + } + }); + + println!("Backup created:\n\t{}", backup_dir.display()); + } + Command::Collisions { root_dir } => monitor_index(root_dir, None)?, + Command::Monitor { root_dir, interval } => { + let millis = interval.unwrap_or(1000); + monitor_index(root_dir, Some(millis))? + } + Command::Render { path, quality } => { + let filepath = path.to_owned().unwrap(); + let quality = match quality.to_owned().unwrap().as_str() { + "high" => Ok(PDFQuality::High), + "medium" => Ok(PDFQuality::Medium), + "low" => Ok(PDFQuality::Low), + _ => Err(AppError::InvalidRenderOption), + }?; + let buf = File::open(&filepath).unwrap(); + let dest_path = filepath.with_file_name( + filepath + .file_stem() + .unwrap() + .to_str() + .unwrap() + .to_owned() + + ".png", + ); + let img = arklib::pdf::render_preview_page(buf, quality); + img.save(dest_path).unwrap(); + } + Command::Link(link) => match &link { + Link::Create { + root_dir, + url, + title, + desc, + } => { + let root = provide_root(root_dir)?; + let url = url.as_ref().ok_or_else(|| { + AppError::LinkCreationError( + "Url was not provided".to_owned(), + ) + })?; + let title = title.as_ref().ok_or_else(|| { + AppError::LinkCreationError( + "Title was not provided".to_owned(), + ) + })?; + + println!("Saving link..."); + + match commands::link::create_link( + &root, + url, + title, + desc.to_owned(), + ) + .await + { + Ok(_) => { + println!("Link saved successfully!"); + } + Err(e) => println!("{}", e), + } + } + + Link::Load { + root_dir, + file_path, + id, + } => { + let root = provide_root(root_dir)?; + let link = commands::link::load_link(&root, file_path, id)?; + println!("Link data:\n{:?}", link); + } + }, + Command::File(file) => match &file { + FileCommand::Append { + root_dir, + storage, + id, + content, + format, + type_, + } => { + let (file_path, storage_type) = + translate_storage(&Some(root_dir.to_owned()), storage) + .ok_or(AppError::StorageNotFound(storage.to_owned()))?; + + let storage_type = storage_type.unwrap_or(match type_ { + Some(t) => *t, + None => StorageType::File, + }); + + let format = format.unwrap_or(Format::Raw); + + let mut storage = Storage::new(file_path, storage_type)?; + + let resource_id = ResourceId::from_str(id)?; + + storage.append(resource_id, content, format)?; + } + + FileCommand::Insert { + root_dir, + storage, + id, + content, + format, + type_, + } => { + let (file_path, storage_type) = + translate_storage(&Some(root_dir.to_owned()), storage) + .ok_or(AppError::StorageNotFound(storage.to_owned()))?; + + let storage_type = storage_type.unwrap_or(match type_ { + Some(t) => *t, + None => StorageType::File, + }); + + let format = format.unwrap_or(Format::Raw); + + let mut storage = Storage::new(file_path, storage_type)?; + + let resource_id = ResourceId::from_str(id)?; + + storage.insert(resource_id, content, format)?; + } + + FileCommand::Read { + root_dir, + storage, + id, + type_, + } => { + let (file_path, storage_type) = + translate_storage(&Some(root_dir.to_owned()), storage) + .ok_or(AppError::StorageNotFound(storage.to_owned()))?; + + let storage_type = storage_type.unwrap_or(match type_ { + Some(t) => *t, + None => StorageType::File, + }); + + let mut storage = Storage::new(file_path, storage_type)?; + + let resource_id = ResourceId::from_str(id)?; + + let output = storage.read(resource_id)?; + + println!("{}", output); + } + }, + Command::Storage(cmd) => match &cmd { + StorageCommand::List { + root_dir, + storage, + type_, + versions, + } => { + let storage = + storage + .as_ref() + .ok_or(AppError::StorageCreationError( + "Storage was not provided".to_owned(), + ))?; + + let versions = versions.unwrap_or(false); + + let (file_path, storage_type) = + translate_storage(root_dir, storage) + .ok_or(AppError::StorageNotFound(storage.to_owned()))?; + + let storage_type = storage_type.unwrap_or(match type_ { + Some(t) => *t, + None => StorageType::File, + }); + + let mut storage = Storage::new(file_path, storage_type)?; + + storage.load()?; + + let output = storage.list(versions)?; + + println!("{}", output); + } + }, + }; + + Ok(()) +} diff --git a/ark-cli/src/models/cli.rs b/ark-cli/src/models/cli.rs new file mode 100644 index 00000000..24f3d485 --- /dev/null +++ b/ark-cli/src/models/cli.rs @@ -0,0 +1,169 @@ +use std::path::PathBuf; + +use arklib::id::ResourceId; +use clap::{Parser, Subcommand}; + +use super::{ + entry::EntryOutput, format::Format, sort::Sort, storage::StorageType, +}; + +#[derive(Parser, Debug)] +#[clap(name = "ark-cli")] +#[clap(about = "Manage ARK tag storages and indexes", long_about = None)] +pub struct Cli { + #[clap(subcommand)] + pub command: Command, +} + +#[derive(Subcommand, Debug)] +pub enum Command { + Backup { + #[clap(parse(from_os_str))] + roots_cfg: Option, + }, + + Collisions { + #[clap(parse(from_os_str))] + root_dir: Option, + }, + + Monitor { + #[clap(parse(from_os_str))] + root_dir: Option, + interval: Option, + }, + + Render { + #[clap(parse(from_os_str))] + path: Option, + quality: Option, + }, + + List { + #[clap(parse(from_os_str))] + root_dir: Option, + + #[clap(long)] + entry: Option, + + #[clap(long, short = 'i', action)] + entry_id: bool, + + #[clap(long, short = 'p', action)] + entry_path: bool, + + #[clap(long, short = 'l', action)] + entry_link: bool, + + #[clap(long, short, action)] + modified: bool, + + #[clap(long, short, action)] + tags: bool, + + #[clap(long, short, action)] + scores: bool, + + #[clap(long)] + sort: Option, + + #[clap(long)] + filter: Option, + }, + + #[clap(subcommand)] + Link(Link), + + #[clap(subcommand)] + File(FileCommand), + + #[clap(subcommand)] + Storage(StorageCommand), +} + +#[derive(Subcommand, Debug)] +pub enum StorageCommand { + List { + #[clap(parse(from_os_str))] + root_dir: Option, + + storage: Option, + + #[clap(short, long)] + versions: Option, + + #[clap(short, long)] + type_: Option, + }, +} + +#[derive(Subcommand, Debug)] +pub enum FileCommand { + Append { + #[clap(parse(from_os_str))] + root_dir: PathBuf, + + storage: String, + + id: String, + + content: String, + + #[clap(short, long)] + format: Option, + + #[clap(short, long)] + type_: Option, + }, + + Insert { + #[clap(parse(from_os_str))] + root_dir: PathBuf, + + storage: String, + + id: String, + + content: String, + + #[clap(short, long)] + format: Option, + + #[clap(short, long)] + type_: Option, + }, + + Read { + #[clap(parse(from_os_str))] + root_dir: PathBuf, + + storage: String, + + id: String, + + #[clap(short, long)] + type_: Option, + }, +} + +#[derive(Subcommand, Debug)] +pub enum Link { + Create { + #[clap(parse(from_os_str))] + root_dir: Option, + + url: Option, + title: Option, + desc: Option, + }, + + Load { + #[clap(parse(from_os_str))] + root_dir: Option, + + #[clap(parse(from_os_str))] + file_path: Option, + + id: Option, + }, +} diff --git a/ark-cli/src/models/entry.rs b/ark-cli/src/models/entry.rs new file mode 100644 index 00000000..475909bf --- /dev/null +++ b/ark-cli/src/models/entry.rs @@ -0,0 +1,23 @@ +use clap::Parser; + +#[derive(Parser, Debug, Clone, Copy, PartialEq, Eq)] +pub enum EntryOutput { + Link, + Id, + Path, + Both, +} + +impl std::str::FromStr for EntryOutput { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "id" => Ok(EntryOutput::Id), + "path" => Ok(EntryOutput::Path), + "both" => Ok(EntryOutput::Both), + "link" => Ok(EntryOutput::Link), + _ => Err("Entry output must be either 'id', 'path' or 'both'"), + } + } +} diff --git a/ark-cli/src/models/format.rs b/ark-cli/src/models/format.rs new file mode 100644 index 00000000..c8d6fb55 --- /dev/null +++ b/ark-cli/src/models/format.rs @@ -0,0 +1,40 @@ +use crate::error::InlineJsonParseError; + +#[derive(Debug, Clone, Copy)] +pub enum Format { + KeyValue, + Raw, +} + +impl std::str::FromStr for Format { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "json" => Ok(Format::KeyValue), + "raw" => Ok(Format::Raw), + _ => Err("Invalid format".to_owned()), + } + } +} + +pub fn key_value_to_str( + s: &str, +) -> Result, InlineJsonParseError> { + let pairs: Vec<&str> = s.split(',').collect(); + + let mut values = Vec::new(); + + for pair in pairs { + let key_value: Vec<&str> = pair.split(':').collect(); + if key_value.len() == 2 { + let key = key_value[0].trim().to_string(); + let value = key_value[1].trim().to_string(); + values.push((key, value)); + } else { + return Err(InlineJsonParseError::InvalidKeyValPair); + } + } + + Ok(values) +} diff --git a/ark-cli/src/models/mod.rs b/ark-cli/src/models/mod.rs new file mode 100644 index 00000000..bc37c45a --- /dev/null +++ b/ark-cli/src/models/mod.rs @@ -0,0 +1,5 @@ +pub mod cli; +pub mod entry; +pub mod format; +pub mod sort; +pub mod storage; diff --git a/ark-cli/src/models/sort.rs b/ark-cli/src/models/sort.rs new file mode 100644 index 00000000..000da162 --- /dev/null +++ b/ark-cli/src/models/sort.rs @@ -0,0 +1,19 @@ +use clap::Parser; + +#[derive(Parser, Debug)] +pub enum Sort { + Asc, + Desc, +} + +impl std::str::FromStr for Sort { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "asc" => Ok(Sort::Asc), + "desc" => Ok(Sort::Desc), + _ => Err("Sort must be either 'asc' or 'desc'"), + } + } +} diff --git a/ark-cli/src/models/storage.rs b/ark-cli/src/models/storage.rs new file mode 100644 index 00000000..6e49d32b --- /dev/null +++ b/ark-cli/src/models/storage.rs @@ -0,0 +1,435 @@ +use arklib::{id::ResourceId, AtomicFile}; +use std::fmt::Write; +use std::path::PathBuf; + +use crate::{ + commands::{ + self, + file::{format_file, format_line}, + }, + error::AppError, + models::format::Format, +}; + +#[derive(Debug, Clone, Copy)] +pub enum StorageType { + File, + Folder, +} + +impl std::str::FromStr for StorageType { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "file" => Ok(StorageType::File), + "folder" => Ok(StorageType::Folder), + _ => Err(format!("Invalid storage type: {}", s)), + } + } +} + +pub struct Storage { + path: PathBuf, + storage_type: StorageType, + files: Vec, +} + +impl Storage { + pub fn new>( + path: P, + storage_type: StorageType, + ) -> Result { + let path = path.into(); + + if !path.exists() { + std::fs::create_dir_all(&path).map_err(|e| { + AppError::StorageCreationError(format!( + "Failed to create storage folder at {:?} with error: {:?}", + path, e + )) + })?; + } + + Ok(Self { + path, + storage_type, + files: Vec::new(), + }) + } + + #[allow(dead_code)] + pub fn load(&mut self) -> Result<(), AppError> { + match self.storage_type { + StorageType::File => { + let atomic_file = AtomicFile::new(self.path.clone())?; + + let atomic_file_data = atomic_file.load()?; + + let data = atomic_file_data.read_to_string()?; + + for (i, line) in data.lines().enumerate() { + let mut line = line.split(':'); + let id = line.next().unwrap(); + match id.parse::().map_err(|_| { + AppError::IndexError(format!( + "Failed to parse ResourceId from line: {i}", + )) + }) { + Ok(id) => self.files.push(id), + Err(e) => { + eprintln!("Error parsing line {}: {}", i, e); + } + } + } + } + StorageType::Folder => { + let folder_entries = + std::fs::read_dir(&self.path).map_err(|e| { + AppError::FileOperationError(format!( + "Failed to read folder at {:?} with error: {:?}", + self.path, e + )) + })?; + + for entry in folder_entries { + let entry = entry.map_err(|e| { + AppError::FileOperationError(format!( + "Error reading folder entry: {:?}", + e + )) + })?; + + if let Some(file_name) = entry.file_name().to_str() { + let id = file_name.parse::().map_err(|_| { + AppError::IndexError(format!( + "Failed to parse ResourceId from folder entry: {:?}", + file_name + )) + })?; + self.files.push(id); + } + } + } + }; + + Ok(()) + } + + pub fn append( + &mut self, + id: ResourceId, + content: &str, + format: Format, + ) -> Result<(), AppError> { + match self.storage_type { + StorageType::File => { + let atomic_file = AtomicFile::new(&self.path).map_err(|e| { + AppError::FileOperationError(format!( + "Failed to create atomic file at {} with error: {:?}", + self.path.display(), + e + )) + })?; + + let content = match format { + Format::KeyValue => return Err( + AppError::StorageCreationError( + "Key value format is not supported for file storage" + .to_owned(), + ), + ), + Format::Raw => format!("{}:{}\n", id, content), + }; + + match commands::file::file_append( + &atomic_file, + &content, + Format::Raw, + ) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } + StorageType::Folder => { + let folder_path = self.path.join(id.to_string()); + if !folder_path.exists() { + std::fs::create_dir_all(&folder_path).map_err(|e| { + AppError::StorageCreationError(format!( + "Failed to create folder at {:?} with error: {:?}", + folder_path, e + )) + })?; + } + + let atomic_file = AtomicFile::new(&folder_path) + .map_err(|e| { + AppError::FileOperationError(format!( + "Failed to create atomic file at {} with error: {:?}", + self.path.display(), e + )) + })?; + + match commands::file::file_append(&atomic_file, content, format) + { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } + } + } + + pub fn read(&mut self, id: ResourceId) -> Result { + match self.storage_type { + StorageType::File => { + let atomic_file = AtomicFile::new(&self.path).map_err(|e| { + AppError::FileOperationError(format!( + "Failed to create atomic file at {} with error: {:?}", + self.path.display(), + e + )) + })?; + + let atomic_file_data = atomic_file.load().map_err(|e| { + AppError::FileOperationError(format!( + "Failed to load atomic file at {:?} with error: {:?}", + self.path, e + )) + })?; + + let data = atomic_file_data.read_to_string().map_err(|_| { + AppError::FileOperationError( + "Could not read atomic file content.".to_string(), + ) + })?; + + for (i, line) in data.lines().enumerate() { + let mut line = line.split(':'); + let line_id: &str = line.next().unwrap(); + match line_id.parse::().map_err(|_| { + AppError::IndexError(format!( + "Failed to parse ResourceId from line: {i}", + )) + }) { + Ok(line_id) => { + if id == line_id { + let data = line.next().unwrap(); + return Ok(data.to_string()); + } + } + Err(e) => { + eprintln!("Error parsing line {}: {}", i, e); + } + } + } + + Err(AppError::StorageNotFound(format!( + "Resource with id {} not found", + id + ))) + } + StorageType::Folder => { + let folder_path = self.path.join(id.to_string()); + if !folder_path.exists() { + return Err(AppError::StorageNotFound(format!( + "Resource with id {} not found", + id + ))); + } + + let atomic_file = AtomicFile::new(&folder_path) + .map_err(|e| { + AppError::FileOperationError(format!( + "Failed to create atomic file at {} with error: {:?}", + self.path.display(), e + )) + })?; + + let atomic_file_data = atomic_file.load().map_err(|e| { + AppError::FileOperationError(format!( + "Failed to load atomic file at {:?} with error: {:?}", + self.path, e + )) + })?; + + let data = atomic_file_data.read_to_string().map_err(|_| { + AppError::FileOperationError( + "Could not read atomic file content.".to_string(), + ) + })?; + + Ok(data) + } + } + } + + pub fn insert( + &mut self, + id: ResourceId, + content: &str, + format: Format, + ) -> Result<(), AppError> { + match self.storage_type { + StorageType::File => { + let atomic_file = AtomicFile::new(&self.path).map_err(|e| { + AppError::FileOperationError(format!( + "Failed to create atomic file at {} with error: {:?}", + self.path.display(), + e + )) + })?; + + let content = match format { + Format::KeyValue => return Err( + AppError::StorageCreationError( + "Key value format is not supported for file storage" + .to_owned(), + ), + ), + Format::Raw => format!("{}:{}\n", id, content), + }; + + match commands::file::file_insert( + &atomic_file, + &content, + Format::Raw, + ) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } + StorageType::Folder => { + let folder_path = self.path.join(id.to_string()); + if !folder_path.exists() { + std::fs::create_dir_all(&folder_path).map_err(|e| { + AppError::StorageCreationError(format!( + "Failed to create folder at {:?} with error: {:?}", + folder_path, e + )) + })?; + } + + let atomic_file = AtomicFile::new(&folder_path) + .map_err(|e| { + AppError::FileOperationError(format!( + "Failed to create atomic file at {} with error: {:?}", + self.path.display(), e + )) + })?; + + match commands::file::file_insert(&atomic_file, content, format) + { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } + } + } + + pub fn list(&self, versions: bool) -> Result { + let mut output = String::new(); + + if !versions { + for id in &self.files { + writeln!(output, "{}", id).map_err(|_| { + AppError::FileOperationError( + "Could not write to output".to_string(), + ) + })?; + } + } else { + match self.storage_type { + StorageType::File => { + let atomic_file = AtomicFile::new(&self.path) + .map_err(|e| { + AppError::FileOperationError(format!( + "Failed to create atomic file at {} with error: {:?}", + self.path.display(), e + )) + })?; + + let atomic_file_data = atomic_file.load().map_err(|e| { + AppError::FileOperationError(format!( + "Failed to load atomic file at {:?} with error: {:?}", + self.path, e + )) + })?; + + writeln!(output, "{: <16} value", "id").map_err(|_| { + AppError::FileOperationError( + "Could not write to output".to_string(), + ) + })?; + + let data = + atomic_file_data.read_to_string().map_err(|_| { + AppError::FileOperationError( + "Could not read atomic file content." + .to_string(), + ) + })?; + + for line in data.lines() { + let mut line = line.split(':'); + let id = line.next(); + let data = line.next(); + + if let (Some(id), Some(data)) = (id, data) { + writeln!(output, "{: <16} {}", id, data).map_err( + |_| { + AppError::FileOperationError( + "Could not write to output".to_string(), + ) + }, + )?; + } + } + } + StorageType::Folder => { + let folder_entries = std::fs::read_dir(&self.path) + .map_err(|e| { + AppError::FileOperationError(format!( + "Failed to read folder at {:?} with error: {:?}", + self.path, e + )) + })? + .filter_map(|v| v.ok()) + .filter(|e| { + if let Ok(ftype) = e.file_type() { + ftype.is_dir() + } else { + false + } + }) + .filter_map(|e| match AtomicFile::new(e.path()) { + Ok(file) => Some(file), + Err(_) => None, + }); + + writeln!( + output, + "{}", + format_line("version", "name", "machine", "path"), + ) + .map_err(|_| { + AppError::FileOperationError( + "Could not write to output".to_string(), + ) + })?; + + for entry in folder_entries { + if let Some(file) = format_file(&entry) { + writeln!(output, "{}", file).map_err(|_| { + AppError::FileOperationError( + "Could not write to output".to_string(), + ) + })?; + } + } + } + }; + } + + Ok(output) + } +} diff --git a/ark-cli/src/util.rs b/ark-cli/src/util.rs new file mode 100644 index 00000000..65905e76 --- /dev/null +++ b/ark-cli/src/util.rs @@ -0,0 +1,251 @@ +use arklib::id::ResourceId; +use arklib::index::ResourceIndex; +use arklib::{ + ARK_FOLDER, METADATA_STORAGE_FOLDER, PREVIEWS_STORAGE_FOLDER, + PROPERTIES_STORAGE_FOLDER, SCORE_STORAGE_FILE, STATS_FOLDER, + TAG_STORAGE_FILE, THUMBNAILS_STORAGE_FOLDER, +}; +use std::env::current_dir; +use std::fs::{canonicalize, metadata}; +use std::io::BufRead; +use std::io::BufReader; +use std::path::Path; +use std::str::FromStr; +use std::thread; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; +use std::{fs::File, path::PathBuf}; + +use crate::error::AppError; +use crate::models::storage::{Storage, StorageType}; +use crate::ARK_CONFIG; + +pub fn discover_roots( + roots_cfg: &Option, +) -> Result, AppError> { + if let Some(path) = roots_cfg { + println!( + "\tRoots config provided explicitly:\n\t\t{}", + path.display() + ); + let config = File::open(path)?; + + Ok(parse_roots(config)) + } else if let Ok(config) = File::open(ARK_CONFIG) { + println!( + "\tRoots config was found automatically:\n\t\t{}", + &ARK_CONFIG + ); + + Ok(parse_roots(config)) + } else { + println!("\tRoots config wasn't found."); + + println!("Looking for a folder containing tag storage:"); + let path = + canonicalize(current_dir().expect("Can't open current directory!")) + .expect("Couldn't canonicalize working directory!"); + + let result = path.ancestors().find(|path| { + println!("\t{}", path.display()); + storages_exists(path) + }); + + if let Some(root) = result { + println!("Root folder found:\n\t{}", root.display()); + Ok(vec![root.to_path_buf()]) + } else { + println!("Root folder wasn't found."); + Ok(vec![]) + } + } +} + +pub fn provide_root(root_dir: &Option) -> Result { + if let Some(path) = root_dir { + Ok(path.clone()) + } else { + Ok(current_dir()?) + } +} + +// Read-only structure +pub fn provide_index(root_dir: &PathBuf) -> ResourceIndex { + let rwlock = + arklib::provide_index(root_dir).expect("Failed to retrieve index"); + let index = &*rwlock.read().unwrap(); + index.clone() +} + +pub fn monitor_index( + root_dir: &Option, + interval: Option, +) -> Result<(), AppError> { + let dir_path = provide_root(root_dir)?; + + println!("Building index of folder {}", dir_path.display()); + let start = Instant::now(); + + let result = arklib::provide_index(dir_path); + let duration = start.elapsed(); + + match result { + Ok(rwlock) => { + println!("Build succeeded in {:?}\n", duration); + + if let Some(millis) = interval { + let mut index = rwlock.write().unwrap(); + loop { + let pause = Duration::from_millis(millis); + thread::sleep(pause); + + let start = Instant::now(); + match index.update_all() { + Err(msg) => println!("Oops! {}", msg), + Ok(diff) => { + index.store().expect("Could not store index"); + let duration = start.elapsed(); + println!("Updating succeeded in {:?}\n", duration); + + if !diff.deleted.is_empty() { + println!("Deleted: {:?}", diff.deleted); + } + if !diff.added.is_empty() { + println!("Added: {:?}", diff.added); + } + } + } + } + } else { + let index = rwlock.read().unwrap(); + + println!("Here are {} entries in the index", index.size()); + + for (key, count) in index.collisions.iter() { + println!("Id {:?} calculated {} times", key, count); + } + } + } + Err(err) => println!("Failure: {:?}", err), + } + + Ok(()) +} + +pub fn storages_exists(path: &Path) -> bool { + let meta = metadata(path.join(arklib::ARK_FOLDER)); + if let Ok(meta) = meta { + return meta.is_dir(); + } + + false +} + +pub fn parse_roots(config: File) -> Vec { + BufReader::new(config) + .lines() + .filter_map(|line| match line { + Ok(path) => Some(PathBuf::from(path)), + Err(msg) => { + println!("{:?}", msg); + None + } + }) + .collect() +} + +pub fn timestamp() -> Duration { + let start = SystemTime::now(); + start + .duration_since(UNIX_EPOCH) + .expect("Time went backwards!") +} + +pub fn translate_storage( + root: &Option, + storage: &str, +) -> Option<(PathBuf, Option)> { + if let Ok(path) = PathBuf::from_str(storage) { + if path.exists() && path.is_dir() { + return Some((path, None)); + } + } + + match storage.to_lowercase().as_str() { + "tags" => Some(( + provide_root(root) + .ok()? + .join(ARK_FOLDER) + .join(TAG_STORAGE_FILE), + Some(StorageType::File), + )), + "scores" => Some(( + provide_root(root) + .ok()? + .join(ARK_FOLDER) + .join(SCORE_STORAGE_FILE), + Some(StorageType::File), + )), + "stats" => Some(( + provide_root(root) + .ok()? + .join(ARK_FOLDER) + .join(STATS_FOLDER), + Some(StorageType::Folder), + )), + "properties" => Some(( + provide_root(root) + .ok()? + .join(ARK_FOLDER) + .join(PROPERTIES_STORAGE_FOLDER), + Some(StorageType::Folder), + )), + "metadata" => Some(( + provide_root(root) + .ok()? + .join(ARK_FOLDER) + .join(METADATA_STORAGE_FOLDER), + Some(StorageType::Folder), + )), + "previews" => Some(( + provide_root(root) + .ok()? + .join(ARK_FOLDER) + .join(PREVIEWS_STORAGE_FOLDER), + Some(StorageType::Folder), + )), + "thumbnails" => Some(( + provide_root(root) + .ok()? + .join(ARK_FOLDER) + .join(THUMBNAILS_STORAGE_FOLDER), + Some(StorageType::Folder), + )), + _ => None, + } +} + +pub fn read_storage_value( + root_dir: &PathBuf, + storage: &str, + id: &str, + type_: &Option, +) -> Result { + let (file_path, storage_type) = + translate_storage(&Some(root_dir.to_owned()), storage) + .ok_or(AppError::StorageNotFound(storage.to_owned()))?; + + let storage_type = storage_type.unwrap_or(match type_ { + Some(type_) => match type_.to_lowercase().as_str() { + "file" => StorageType::File, + "folder" => StorageType::Folder, + _ => panic!("unknown storage type"), + }, + None => StorageType::File, + }); + + let mut storage = Storage::new(file_path, storage_type)?; + + let resource_id = ResourceId::from_str(id)?; + + storage.read(resource_id) +}