app_dirs2-2.5.2/.cargo_vcs_info.json0000644000000001360000000000100127250ustar { "git": { "sha1": "bf12052c69551ed8940d62dc03ca674b6f11496b" }, "path_in_vcs": "" }app_dirs2-2.5.2/.github/workflows/rust.yaml000064400000000000000000000026170072674642500170310ustar 00000000000000name: Rust on: [push, pull_request] jobs: clippy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable override: true profile: minimal components: clippy - name: Clippy uses: actions-rs/cargo@v1 with: command: clippy args: --all --all-targets -- -Dwarnings test: strategy: matrix: os: - ubuntu-latest - windows-latest - macos-latest runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable override: true profile: minimal - name: Test all-targets uses: actions-rs/cargo@v1 with: command: test args: --workspace --all-targets - name: Test docs uses: actions-rs/cargo@v1 with: command: test args: --workspace --doc docs: runs-on: ubuntu-latest name: Build-test docs steps: - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 with: toolchain: stable override: true profile: minimal - name: Document all crates uses: actions-rs/cargo@v1 env: RUSTDOCFLAGS: -Dwarnings with: command: doc args: --all --all-features --no-deps --document-private-items app_dirs2-2.5.2/.gitignore000064400000000000000000000000220072674642500135270ustar 00000000000000target Cargo.lock app_dirs2-2.5.2/.travis.yml000064400000000000000000000001700072674642500136540ustar 00000000000000language: rust rust: - stable - beta - nightly matrix: allow_failures: - rust: nightly os: - linux - osxapp_dirs2-2.5.2/Cargo.lock0000644000000343270000000000100107110ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] [[package]] name = "android_log-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e" [[package]] name = "android_logger" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9ed09b18365ed295d722d0b5ed59c01b79a826ff2d2a8f73d5ecca8e6fb2f66" dependencies = [ "android_log-sys", "env_logger", "lazy_static", "log", ] [[package]] name = "app_dirs2" version = "2.5.2" dependencies = [ "jni", "log", "ndk-context", "ndk-glue", "once_cell", "tempfile", "test-case", "winapi", "xdg", ] [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bytes" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" [[package]] name = "cesu8" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "combine" version = "4.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" dependencies = [ "bytes", "memchr", ] [[package]] name = "darling" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ "darling_core", "darling_macro", ] [[package]] name = "darling_core" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", "syn", ] [[package]] name = "darling_macro" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", "syn", ] [[package]] name = "dirs" version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", "winapi", ] [[package]] name = "env_logger" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" dependencies = [ "log", "regex", ] [[package]] name = "fastrand" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" dependencies = [ "instant", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "getrandom" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "ident_case" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "instant" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", ] [[package]] name = "jni" version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" dependencies = [ "cesu8", "combine", "jni-sys", "log", "thiserror", "walkdir", ] [[package]] name = "jni-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "log" version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "ndk" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" dependencies = [ "bitflags", "jni-sys", "ndk-sys", "num_enum", "thiserror", ] [[package]] name = "ndk-context" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "ndk-glue" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d0c4a7b83860226e6b4183edac21851f05d5a51756e97a1144b7f5a6b63e65f" dependencies = [ "android_logger", "lazy_static", "libc", "log", "ndk", "ndk-context", "ndk-macro", "ndk-sys", ] [[package]] name = "ndk-macro" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c" dependencies = [ "darling", "proc-macro-crate", "proc-macro2", "quote", "syn", ] [[package]] name = "ndk-sys" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" dependencies = [ "jni-sys", ] [[package]] name = "num_enum" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", "syn", ] [[package]] name = "once_cell" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "proc-macro-crate" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ "thiserror", "toml", ] [[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", "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-macro2" version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "redox_users" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", "redox_syscall", "thiserror", ] [[package]] name = "regex" version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ "winapi", ] [[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 = "serde" version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tempfile" version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if", "fastrand", "libc", "redox_syscall", "remove_dir_all", "winapi", ] [[package]] name = "test-case" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "196e8a70562e252cc51eaaaee3ecddc39803d9b7fd4a772b7c7dae7cdf42a859" dependencies = [ "test-case-macros", ] [[package]] name = "test-case-macros" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd461f47ade621665c9f4e44b20449341769911c253275dc5cb03726cbb852c" dependencies = [ "cfg-if", "proc-macro-error", "proc-macro2", "quote", "syn", ] [[package]] name = "thiserror" version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "toml" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] [[package]] name = "unicode-ident" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" [[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.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", "winapi", "winapi-util", ] [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[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.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" 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 = "xdg" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4583db5cbd4c4c0303df2d15af80f0539db703fa1c68802d4cbbd2dd0f88f6" dependencies = [ "dirs", ] app_dirs2-2.5.2/Cargo.toml0000644000000034620000000000100107300ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "app_dirs2" version = "2.5.2" authors = [ "Andy Barron ", "Simon Heath ", ] description = "Put your app's data in the right place on every platform. Community-maintained project." homepage = "https://lib.rs/app_dirs2" documentation = "https://docs.rs/app_dirs2" readme = "README.md" keywords = [ "application", "data", "storage", "location", "directory", ] categories = [ "filesystem", "os", ] license = "MIT" repository = "https://github.com/app-dirs-rs/app_dirs2" [[example]] name = "android" crate-type = ["cdylib"] [dev-dependencies.once_cell] version = "1.0.1" [dev-dependencies.tempfile] version = "3.3" [dev-dependencies.test-case] version = "2.1" [target."cfg(all(unix, not(target_os = \"macos\")))".dependencies.xdg] version = "2.2.0" [target."cfg(target_os = \"android\")".dependencies.jni] version = "0.19.0" [target."cfg(target_os = \"android\")".dependencies.ndk-context] version = "0.1.0" [target."cfg(target_os = \"android\")".dev-dependencies.log] version = "0.4.13" [target."cfg(target_os = \"android\")".dev-dependencies.ndk-glue] version = "0.6" features = ["logger"] [target."cfg(windows)".dependencies.winapi] version = "0.3.8" features = [ "shlobj", "combaseapi", ] [badges.maintenance] status = "passively-maintained" app_dirs2-2.5.2/Cargo.toml.orig000064400000000000000000000021450072674642500144360ustar 00000000000000[package] name = "app_dirs2" version = "2.5.2" authors = ["Andy Barron ", "Simon Heath "] categories = ["filesystem", "os"] description = "Put your app's data in the right place on every platform. Community-maintained project." documentation = "https://docs.rs/app_dirs2" homepage = "https://lib.rs/app_dirs2" keywords = ["application", "data", "storage", "location", "directory"] license = "MIT" readme = "README.md" repository = "https://github.com/app-dirs-rs/app_dirs2" edition = "2018" [target.'cfg(all(unix, not(target_os = "macos")))'.dependencies] xdg = "2.2.0" [target.'cfg(target_os = "android")'.dependencies] jni = "0.19.0" ndk-context = "0.1.0" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.8", features = ["shlobj", "combaseapi"] } [dev-dependencies] once_cell = "1.0.1" tempfile = "3.3" test-case = "2.1" [target.'cfg(target_os = "android")'.dev-dependencies] ndk-glue = { version = "0.6", features = ["logger"] } log = "0.4.13" [badges] maintenance = { status = "passively-maintained" } [[example]] name = "android" crate-type = ["cdylib"] app_dirs2-2.5.2/LICENSE.txt000064400000000000000000000020730072674642500133720ustar 00000000000000The MIT License (MIT) Copyright (c) 2018 app-dirs-rs Team 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. app_dirs2-2.5.2/README.md000064400000000000000000000020470072674642500130270ustar 00000000000000# app_dirs2 *Put your app's data in the right place on every platform* [![crates.io:app_dirs2](https://img.shields.io/crates/v/app_dirs2.svg?label=crates.io%3A%20app_dirs2)](https://crates.rs/crates/app_dirs2) ## This is the up-to-date version of `app_dirs` The original [app_dirs](https://lib.rs/crates/app_dirs) crate is unmaintained and has seriously outdated dependencies. This is an fork that keeps the crate working and up-to-date. This is a *community-maintained project*, so if you find a bug or the crate is missing support for your platform, please help out. There are no major changes planned. If you're looking for a crate with more features, check out the [directories](https://lib.rs/crates/directories) crate. ## Documentation & examples https://docs.rs/app_dirs2 ## Installation Add the following to your `Cargo.toml` under `[dependencies]`: ```toml app_dirs = { package = "app_dirs2", version = "2.3" } ``` The syntax with `package` allows you to keep the old name in the code (`use app_dirs::*`), so that it's a drop-in replacement. app_dirs2-2.5.2/appveyor.yml000064400000000000000000000100230072674642500141310ustar 00000000000000# Appveyor configuration template for Rust # https://github.com/starkat99/appveyor-rust ## Operating System (VM environment) ## # Rust needs at least Visual Studio 2013 Appveyor OS for MSVC targets. os: Visual Studio 2015 ## Build Matrix ## # This configuration will setup a build for each channel & target combination (12 windows # combinations in all). # # There are 3 channels: stable, beta, and nightly. # # Alternatively, the full version may be specified for the channel to build using that specific # version (e.g. channel: 1.5.0) # # The values for target are the set of windows Rust build targets. Each value is of the form # # ARCH-pc-windows-TOOLCHAIN # # Where ARCH is the target architecture, either x86_64 or i686, and TOOLCHAIN is the linker # toolchain to use, either msvc or gnu. See https://www.rust-lang.org/downloads.html#win-foot for # a description of the toolchain differences. # # Comment out channel/target combos you do not wish to build in CI. environment: matrix: ### MSVC Toolchains ### # Stable 64-bit MSVC - channel: stable target: x86_64-pc-windows-msvc # Stable 32-bit MSVC - channel: stable target: i686-pc-windows-msvc # Beta 64-bit MSVC - channel: beta target: x86_64-pc-windows-msvc # Beta 32-bit MSVC - channel: beta target: i686-pc-windows-msvc # Nightly 64-bit MSVC - channel: nightly target: x86_64-pc-windows-msvc # Nightly 32-bit MSVC - channel: nightly target: i686-pc-windows-msvc ### GNU Toolchains ### # Stable 64-bit GNU - channel: stable target: x86_64-pc-windows-gnu # Stable 32-bit GNU - channel: stable target: i686-pc-windows-gnu # Beta 64-bit GNU - channel: beta target: x86_64-pc-windows-gnu # Beta 32-bit GNU - channel: beta target: i686-pc-windows-gnu # Nightly 64-bit GNU - channel: nightly target: x86_64-pc-windows-gnu # Nightly 32-bit GNU - channel: nightly target: i686-pc-windows-gnu ### Allowed failures ### # See Appveyor documentation for specific details. In short, place any channel or targets you wish # to allow build failures on (usually nightly at least is a wise choice). This will prevent a build # or test failure in the matching channels/targets from failing the entire build. matrix: allow_failures: - channel: nightly # If you only care about stable channel build failures, uncomment the following line: #- channel: beta # 32-bit MSVC isn't stablized yet, so you may optionally allow failures there (uncomment line): #- target: i686-pc-windows-msvc ## Install Script ## # This is the most important part of the Appveyor configuration. This installs the version of Rust # specified by the 'channel' and 'target' environment variables from the build matrix. By default, # Rust will be installed to C:\Rust for easy usage, but this path can be overridden by setting the # RUST_INSTALL_DIR environment variable. The URL to download rust distributions defaults to # https://static.rust-lang.org/dist/ but can overridden by setting the RUST_DOWNLOAD_URL environment # variable. # # For simple configurations, instead of using the build matrix, you can override the channel and # target environment variables with the -channel and -target script arguments. # # If no channel or target arguments or environment variables are specified, will default to stable # channel and x86_64-pc-windows-msvc target. # # The file appveyor_rust_install.ps1 must exist in the root directory of the repository. install: - ps: .\appveyor_rust_install.ps1 # Alternative install command for simple configurations without build matrix (uncomment line and # comment above line): #- ps: .\appveyor_rust_install.ps1 -channel stable -target x86_64-pc-windows-msvc ## Build Script ## build: false # fixes appveyor "project or solution file" error # Uses 'cargo test' to run tests. Alternatively, the project may call compiled programs directly or # perform other testing commands. Rust will automatically be placed in the PATH environment # variable. test_script: - cmd: cargo test --verbose app_dirs2-2.5.2/appveyor_rust_install.ps1000064400000000000000000000052030072674642500166420ustar 00000000000000##### Appveyor Rust Install Script ##### # https://github.com/starkat99/appveyor-rust # This is the most important part of the Appveyor configuration. This installs the version of Rust # specified by the "channel" and "target" environment variables from the build matrix. By default, # Rust will be installed to C:\Rust for easy usage, but this path can be overridden by setting the # RUST_INSTALL_DIR environment variable. The URL to download rust distributions defaults to # https://static.rust-lang.org/dist/ but can overridden by setting the RUST_DOWNLOAD_URL environment # variable. # # For simple configurations, instead of using the build matrix, you can override the channel and # target environment variables with the --channel and --target script arguments. # # If no channel or target arguments or environment variables are specified, will default to stable # channel and x86_64-pc-windows-msvc target. param([string]$channel=${env:channel}, [string]$target=${env:target}) # Initialize our parameters from arguments and environment variables, falling back to defaults if (!$channel) { $channel = "stable" } if (!$target) { $target = "x86_64-pc-windows-msvc" } $downloadUrl = "https://static.rust-lang.org/dist/" if ($env:RUST_DOWNLOAD_URL) { $downloadUrl = $env:RUST_DOWNLOAD_URL } $installDir = "C:\Rust" if ($env:RUST_INSTALL_DIR) { $installUrl = $env:RUST_INSTALL_DIR } if ($channel -eq "stable") { # Download manifest so we can find actual filename of installer to download. Needed for stable. echo "Downloading $channel channel manifest" $manifest = "${env:Temp}\channel-rust-${channel}" Start-FileDownload "${downloadUrl}channel-rust-${channel}" -FileName "$manifest" # Search the manifest lines for the correct filename based on target $match = Get-Content "$manifest" | Select-String -pattern "${target}.exe" -simplematch if (!$match -or !$match.line) { throw "Could not find $target in $channel channel manifest" } $installer = $match.line } else { # Otherwise download the file specified by channel directly. $installer = "rust-${channel}-${target}.exe" } # Download installer echo "Downloading ${downloadUrl}$installer" Start-FileDownload "${downloadUrl}$installer" -FileName "${env:Temp}\$installer" # Execute installer and wait for it to finish echo "Installing $installer to $installDir" &"${env:Temp}\$installer" /VERYSILENT /NORESTART /DIR="$installDir" | Write-Output # Add Rust to the path. $env:Path += ";${installDir}\bin;C:\MinGW\bin" echo "Installation of $channel Rust $target completed" # Test and display installed version information for rustc and cargo rustc -V cargo -Vapp_dirs2-2.5.2/examples/android.rs000064400000000000000000000011100072674642500153420ustar 00000000000000#![cfg(target_os = "android")] use app_dirs2::*; use log::info; const NDK_APP_INFO: AppInfo = AppInfo { name: "unnecessary", author: "The Android NDK Authors", }; #[cfg_attr( target_os = "android", ndk_glue::main(backtrace = "full", logger(level = "info", tag = "app_dirs2")) )] fn main() { let all = [ AppDataType::UserConfig, AppDataType::UserData, AppDataType::UserCache, AppDataType::SharedConfig, AppDataType::SharedData, ]; for t in all { info!("{:?}: {:?}", t, app_root(t, &NDK_APP_INFO)); } } app_dirs2-2.5.2/rustfmt.toml000064400000000000000000000000420072674642500141420ustar 00000000000000match_block_trailing_comma = true app_dirs2-2.5.2/src/common.rs000064400000000000000000000063130072674642500141750ustar 00000000000000/// Struct that holds information about your app. /// /// It's recommended to create a single `const` instance of `AppInfo`: /// /// ``` /// use app_dirs2::AppInfo; /// const APP_INFO: AppInfo = AppInfo{name: "Awesome App", author: "Dedicated Dev"}; /// ``` /// /// # Caveats /// Functions in this library sanitize any characters that could be /// non-filename-safe from `name` and `author`. The resulting paths will be /// more human-readable if you stick to **letters, numbers, spaces, hyphens, /// underscores, and periods** for both properties. /// /// The `author` property is currently only used by Windows, as macOS and *nix /// specifications don't require it. Make sure your `name` string is unique! #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct AppInfo { /// Name of your app (e.g. "Hearthstone"). pub name: &'static str, /// Author of your app (e.g. "Blizzard"). pub author: &'static str, } /// Enum specifying the type of app data you want to store. /// /// **Different platforms are NOT guaranteed to distinguish between each data /// type.** Keep this in mind when choosing data file paths. /// /// Example: Windows does not supported shared application data and does not /// distinguish between config and data. Therefore, on Windows, all variants /// except `UserCache` return the same path. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum AppDataType { /// User-specific app configuration data. UserConfig, /// User-specific arbitrary app data. UserData, /// User-specific app cache data. UserCache, /// System-wide arbitrary app data. SharedData, /// System-wide app configuration data. SharedConfig, } impl AppDataType { /// Returns `true` for non-user-specific data types. pub fn is_shared(&self) -> bool { use crate::AppDataType::*; matches!(self, SharedData | SharedConfig) } } const ERR_NOT_SUPPORTED: &str = "App data directories not supported"; const ERR_INVALID_APP_INFO: &str = "Invalid app name or author"; /// Error type for any `app_dirs` operation. #[derive(Debug)] pub enum AppDirsError { /// An I/O error occurred during the operation. Io(std::io::Error), /// App-specific directories are not properly supported by the system /// (e.g. required environment variables don't exist). NotSupported, /// App info given to this library was invalid (e.g. app name or author /// were empty). InvalidAppInfo, } impl std::fmt::Display for AppDirsError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { use crate::AppDirsError::*; match *self { Io(ref e) => std::fmt::Display::fmt(e, f), NotSupported => f.write_str(ERR_NOT_SUPPORTED), InvalidAppInfo => f.write_str(ERR_INVALID_APP_INFO), } } } impl std::error::Error for AppDirsError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { use crate::AppDirsError::*; match *self { Io(ref e) => Some(e), NotSupported => None, InvalidAppInfo => None, } } } impl From for AppDirsError { fn from(e: std::io::Error) -> Self { AppDirsError::Io(e) } } app_dirs2-2.5.2/src/imp/mod.rs000064400000000000000000000103150072674642500142460ustar 00000000000000use crate::common::{AppDataType, AppDirsError, AppInfo}; use crate::utils; use std::fs; use std::path::PathBuf; #[cfg(any(target_os = "macos", target_os = "ios"))] mod platform { mod macos; pub use self::macos::*; } #[cfg(all(unix, not(target_os = "macos"), not(target_os = "ios"), not(target_os = "android")))] mod platform { mod unix; pub use self::unix::*; } #[cfg(windows)] mod platform { mod windows; pub use self::windows::*; } #[cfg(not(any(windows, unix, target_os = "macos", target_os = "ios")))] mod platform { mod unknown; pub use self::unknown::*; } #[cfg(target_os = "android")] mod platform { mod android; pub use self::android::*; } /// Creates (if necessary) and returns path to **app-specific** data /// **subdirectory** for provided data type and subdirectory path. /// /// The `path` parameter should be a valid relative path separated by /// **forward slashes** (`/`). /// /// If the directory structure does not exist, this function will recursively /// create the full hierarchy. Therefore, a result of `Ok` guarantees that the /// returned path exists. pub fn app_dir(t: AppDataType, app: &AppInfo, path: &str) -> Result { let path = get_app_dir(t, app, path)?; match fs::create_dir_all(&path) { Ok(..) => Ok(path), Err(e) => Err(e.into()), } } /// Returns (but **does not create**) path to **app-specific** data /// **subdirectory** for provided data type and subdirectory path. /// /// The `path` parameter should be a valid relative path separated by /// **forward slashes** (`/`). /// /// A result of `Ok` means that we determined where the data SHOULD go, but /// it DOES NOT guarantee that the directory actually exists. (See /// [`app_dir`](fn.app_dir.html).) pub fn get_app_dir(t: AppDataType, app: &AppInfo, path: &str) -> Result { if app.author.is_empty() || app.name.is_empty() { return Err(AppDirsError::InvalidAppInfo); } get_app_root(t, app).map(|mut root| { for component in path.split('/').filter(|s| !s.is_empty()) { root.push(utils::sanitized(component)); } root }) } /// Creates (if necessary) and returns path to **app-specific** data /// directory for provided data type. /// /// If the directory structure does not exist, this function will recursively /// create the full hierarchy. Therefore, a result of `Ok` guarantees that the /// returned path exists. pub fn app_root(t: AppDataType, app: &AppInfo) -> Result { let path = get_app_root(t, app)?; match fs::create_dir_all(&path) { Ok(..) => Ok(path), Err(e) => Err(e.into()), } } /// Returns (but **does not create**) path to **app-specific** data directory /// for provided data type. /// /// A result of `Ok` means that we determined where the data SHOULD go, but /// it DOES NOT guarantee that the directory actually exists. (See /// [`app_root`](fn.app_root.html).) pub fn get_app_root(t: AppDataType, app: &AppInfo) -> Result { if app.author.is_empty() || app.name.is_empty() { return Err(AppDirsError::InvalidAppInfo); } get_data_root(t).map(|mut root| { if platform::USE_AUTHOR { root.push(utils::sanitized(app.author)); } root.push(utils::sanitized(app.name)); root }) } /// Creates (if necessary) and returns path to **top-level** data directory /// for provided data type. /// /// If the directory structure does not exist, this function will recursively /// create the full hierarchy. Therefore, a result of `Ok` guarantees that the /// returned path exists. pub fn data_root(t: AppDataType) -> Result { let path = platform::get_app_dir(t)?; match fs::create_dir_all(&path) { Ok(..) => Ok(path), Err(e) => Err(e.into()), } } /// Returns (but **does not create**) path to **top-level** data directory for /// provided data type. /// /// A result of `Ok` means that we determined where the data SHOULD go, but /// it DOES NOT guarantee that the directory actually exists. (See /// [`data_root`](fn.data_root.html).) pub fn get_data_root(t: AppDataType) -> Result { platform::get_app_dir(t) } app_dirs2-2.5.2/src/imp/platform/android.rs000064400000000000000000000044760072674642500167460ustar 00000000000000use crate::common::*; use std::io::{Error, ErrorKind}; use std::path::PathBuf; pub const USE_AUTHOR: bool = false; impl From for AppDirsError { fn from(error: jni::errors::Error) -> Self { AppDirsError::Io(Error::new(ErrorKind::Other, error)) } } fn get_jni_app_dir( context: &jni::objects::JObject<'_>, env: &jni::JNIEnv<'_>, method: &str, has_string_argument: bool, ) -> Result { let dir = if has_string_argument { env.call_method( *context, method, "(Ljava/lang/String;)Ljava/io/File;", &[jni::objects::JValue::Void], ) } else { env.call_method(*context, method, "()Ljava/io/File;", &[]) }?; let dir = match dir { jni::objects::JValue::Object(o) => o, _ => { return Err(AppDirsError::Io(Error::new( ErrorKind::Other, "dir is not `JObject`", ))) }, }; let path_string = env.call_method(dir, "getPath", "()Ljava/lang/String;", &[])?; let path_string = match path_string { jni::objects::JValue::Object(o) => jni::objects::JString::from(o), _ => { return Err(AppDirsError::Io(Error::new( ErrorKind::Other, "path_string is not `JObject`", ))) }, }; Ok(env.get_string(path_string)?.into()) } pub fn get_app_dir(t: AppDataType) -> Result { let android_context = ndk_context::android_context(); let vm = unsafe { jni::JavaVM::from_raw(android_context.vm().cast()) }?; let env = vm.attach_current_thread()?; let context = jni::objects::JObject::from(android_context.context().cast()); let path_string = match t { AppDataType::UserConfig => get_jni_app_dir(&context, &env, "getDataDir", false)?, AppDataType::UserData => get_jni_app_dir(&context, &env, "getFilesDir", false)?, AppDataType::UserCache => get_jni_app_dir(&context, &env, "getCacheDir", false)?, AppDataType::SharedData | AppDataType::SharedConfig => { get_jni_app_dir(&context, &env, "getExternalFilesDir", true)? }, // AppDataType::SharedCache => get_jni_app_dir(&context, &env, "getExternalCacheDir", false)?, }; Ok(PathBuf::from(path_string)) } app_dirs2-2.5.2/src/imp/platform/macos.rs000064400000000000000000000014650072674642500164230ustar 00000000000000use crate::common::*; use crate::AppDataType::*; use std::path::{Component, Path, PathBuf}; pub const USE_AUTHOR: bool = false; #[allow(deprecated)] // it's fine on macOS pub fn get_app_dir(t: AppDataType) -> Result { let dir_base: Result = if t.is_shared() { Ok(Path::new(&Component::RootDir).into()) } else { std::env::home_dir().ok_or_else(|| AppDirsError::NotSupported) }; dir_base.map(|mut path| { match t { UserConfig | UserData | SharedConfig | SharedData => { path.push("Library"); path.push("Application Support"); }, UserCache => { path.push("Library"); path.push("Caches"); }, }; path }) } app_dirs2-2.5.2/src/imp/platform/unix.rs000064400000000000000000000012220072674642500162730ustar 00000000000000extern crate xdg; use self::xdg::BaseDirectories as Xdg; use crate::common::*; use crate::AppDataType::*; use std::path::PathBuf; pub const USE_AUTHOR: bool = false; pub fn get_app_dir(t: AppDataType) -> Result { Xdg::new() .ok() .as_ref() .and_then(|x| match t { UserConfig => Some(x.get_config_home()), UserData => Some(x.get_data_home()), UserCache => Some(x.get_cache_home()), SharedData => x.get_data_dirs().into_iter().next(), SharedConfig => x.get_config_dirs().into_iter().next(), }) .ok_or(AppDirsError::NotSupported) } app_dirs2-2.5.2/src/imp/platform/unknown.rs000064400000000000000000000003340072674642500170120ustar 00000000000000use crate::common::*; use crate::AppDataType::*; use std::path::PathBuf; pub const USE_AUTHOR: bool = false; pub fn get_app_dir(_t: AppDataType) -> Result { Err(AppDirsError::NotSupported) } app_dirs2-2.5.2/src/imp/platform/windows.rs000064400000000000000000000075370072674642500170210ustar 00000000000000//! Windows provides three different ways to get the paths to roaming and local //! app data: environment variables, KNOWNFOLDERID, and CSIDL. From the CSIDL //! documentation: //! //! *"These values supersede the use of environment variables for this purpose. //! They are in turn superseded in Windows Vista and later by the KNOWNFOLDERID //! values."* //! - https://msdn.microsoft.com/en-us/library/windows/desktop/bb762494.aspx //! //! -_- // The function get_folder_path was adapted from: // https://github.com/AndyBarron/preferences-rs/blob/f03c7/src/lib.rs#L211-L296 // // Credit for the above code goes to Connorcpu (https://github.com/Connorcpu). extern crate winapi; use self::winapi::shared::guiddef::GUID; use self::winapi::um::combaseapi::CoTaskMemFree; use self::winapi::um::shlobj::SHGetKnownFolderPath; use self::winapi::um::winnt::PWSTR; use crate::common::*; use crate::AppDataType::*; use std::ffi::OsString; use std::os::windows::ffi::OsStringExt; use std::path::PathBuf; use std::ptr; use std::slice; pub const USE_AUTHOR: bool = true; pub fn get_app_dir(t: AppDataType) -> Result { let folder_id = match t { UserConfig => &FOLDERID_RoamingAppData, SharedConfig | SharedData => &FOLDERID_ProgramData, UserCache | UserData => &FOLDERID_LocalAppData, }; get_folder_path(folder_id).map(|os_str| os_str.into()) } /// https://msdn.microsoft.com/en-us/library/dd378457.aspx#FOLDERID_RoamingAppData #[allow(non_upper_case_globals)] static FOLDERID_RoamingAppData: GUID = GUID { Data1: 0x3EB685DB, Data2: 0x65F9, Data3: 0x4CF6, Data4: [0xA0, 0x3A, 0xE3, 0xEF, 0x65, 0x72, 0x9F, 0x3D], }; /// https://msdn.microsoft.com/en-us/library/dd378457.aspx#FOLDERID_LocalAppData #[allow(non_upper_case_globals)] static FOLDERID_LocalAppData: GUID = GUID { Data1: 0xF1B32785, Data2: 0x6FBA, Data3: 0x4FCF, Data4: [0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91], }; /// https://msdn.microsoft.com/en-us/library/dd378457.aspx#FOLDERID_ProgramData #[allow(non_upper_case_globals)] static FOLDERID_ProgramData: GUID = GUID { Data1: 0x62AB5D82, Data2: 0xFDC1, Data3: 0x4DC3, Data4: [0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97], }; /// Wrapper around `winapi::PWSTR` to automatically free the string pointer. /// This ensures the memory is freed when `get_folder_path` scope is left, /// regardless of whether the call succeeded or failed/panicked. struct SafePwstr(PWSTR); impl Drop for SafePwstr { fn drop(&mut self) { unsafe { CoTaskMemFree(self.0 as *mut _) } } } fn get_folder_path(folder_id: &GUID) -> Result { unsafe { // Wide C string to be allocated by SHGetKnownFolderPath. // We are responsible for freeing this! let mut raw_path: PWSTR = ptr::null_mut(); // SHGetKnownFolderPath arguments: // 1. reference to KNOWNFOLDERID // 2. no flags // 3. null handle -> current user // 4. output location let result = SHGetKnownFolderPath(folder_id, 0, ptr::null_mut(), &mut raw_path); // SHGetKnownFolderPath shouldn't ever fail, but if it does, // it will return a negative HRESULT. if result < 0 { return Err(AppDirsError::NotSupported); } // Ensures that the PWSTR is free when we leave this scope through // normal execution or a thread panic. let _cleanup = SafePwstr(raw_path); // Manually calculate length of wide C string. let mut length = 0; for i in 0.. { if *raw_path.offset(i) == 0 { length = i as usize; break; } } let wpath: &[u16] = slice::from_raw_parts(raw_path, length); let path: OsString = OsStringExt::from_wide(wpath); Ok(path) // _cleanup is deallocated, so raw_path is freed } } app_dirs2-2.5.2/src/lib.rs000064400000000000000000000052250072674642500134540ustar 00000000000000#![warn(missing_docs)] //! *Put your app's data in the right place on every platform* //! //! # Usage //! //! ```rust //! use app_dirs2::*; // or app_dirs::* if you've used package alias in Cargo.toml //! //! const APP_INFO: AppInfo = AppInfo{name: "CoolApp", author: "SuperDev"}; //! //! fn main () { //! // Where should I store my app's per-user configuration data? //! println!("{:?}", get_app_root(AppDataType::UserConfig, &APP_INFO)); //! // Windows: "%APPDATA%\SuperDev\CoolApp" //! // (e.g.: "C:\Users\Rusty\AppData\Roaming\SuperDev\CoolApp") //! // macOS: "$HOME/Library/Application Support/CoolApp" //! // (e.g.: "/Users/Rusty/Library/Application Support/CoolApp") //! // *nix: "$HOME/.config/CoolApp" (or "$XDG_CONFIG_HOME/CoolApp", if defined) //! // (e.g.: "/home/rusty/.config/CoolApp") //! // Android: "/data/user///CoolApp" //! // (e.g.: "/data/user/0/org.super_dev.cool_app/CoolApp") //! //! // How about nested cache data? //! println!("{:?}", get_app_dir(AppDataType::UserCache, &APP_INFO, "cache/images")); //! // Windows: "%LOCALAPPDATA%\SuperDev\CoolApp\cache\images" //! // (e.g.: "C:\Users\Rusty\AppData\Local\SuperDev\CoolApp\cache\images") //! // macOS: "$HOME/Library/Caches/CoolApp/cache/images" //! // (e.g.: "/Users/Rusty/Library/Caches/CoolApp/cache/images") //! // *nix: "$HOME/.cache/CoolApp/cache/images" //! // (or "$XDG_CACHE_HOME/CoolApp/cache/images", if defined) //! // (e.g.: "/home/rusty/.cache/CoolApp/cache/images") //! // Android: "/data/user///cache/CoolApp" //! // (e.g.: "/data/user/0/org.super_dev.cool_app/cache/CoolApp") //! //! // Remove "get_" prefix to recursively create nonexistent directories: //! // app_root(AppDataType::UserConfig, &APP_INFO) //! // app_dir(AppDataType::UserCache, &APP_INFO, "cache/images") //! } //! ``` mod common; pub use crate::common::*; mod imp; pub use crate::imp::*; mod utils; pub use crate::utils::*; #[cfg(test)] mod tests { use super::*; use crate::AppDataType::*; #[test] fn it_works() { let info = AppInfo { name: "Awesome App", author: "Dedicated Dev", }; let path = "/.not-hidden/subfolder!/with?/uni.code/¡Olé!/"; let types = [UserConfig, UserData, UserCache, SharedData, SharedConfig]; for &t in types.iter() { println!("{:?} data root = {:?}", t, get_data_root(t)); println!("{:?} app root = {:?}", t, get_app_root(t, &info)); println!("{:?} data dir = {:?}", t, get_app_dir(t, &info, path)); } } } app_dirs2-2.5.2/src/utils.rs000064400000000000000000000022630072674642500140450ustar 00000000000000/// Returns a cross-platform-filename-safe version of any string. /// /// This is used internally to generate app data directories based on app /// name/author. App developers can use it for consistency when dealing with /// file system operations. /// /// Do not apply this function to full paths, as it will sanitize '/' and '\'; /// it should only be used on directory or file names (i.e. path segments). pub fn sanitized(component: &str) -> String { let mut buf = String::with_capacity(component.len()); for (i, c) in component.chars().enumerate() { let is_lower = ('a'..='z').contains(&c); let is_upper = ('A'..='Z').contains(&c); let is_letter = is_upper || is_lower; let is_number = ('0'..='9').contains(&c); let is_space = c == ' '; let is_hyphen = c == '-'; let is_underscore = c == '_'; let is_period = c == '.' && i != 0; // Disallow accidentally hidden folders let is_valid = is_letter || is_number || is_space || is_hyphen || is_underscore || is_period; if is_valid { buf.push(c); } else { buf.push_str(&format!(",{},", c as u32)); } } buf } app_dirs2-2.5.2/tests/fs.rs000064400000000000000000000101220072674642500136610ustar 00000000000000#![cfg(all(unix, not(target_os = "macos"), not(target_os = "android")))] use std::env; use std::io; use std::path; use std::sync; use app_dirs2::AppDataType; use once_cell::sync::Lazy; use test_case::test_case; // This test suite checks the effects of the app_dirs2 crate on the file system. // // The functions with the prefix get_ should not touch the file system. The functions without the // prefix should create the returned directory if it doesn’t exist. // // As only the unix/XDG implementation supports changing the root configuration directory, we can // only run this test suite on this platform. As we use environment variables to set the // configuration root, we have to make sure that the tests are run in sequence and don’t overlap, // see the `ENV_MUTEX` mutex. // For test cases that depend on environment variables static ENV_MUTEX: Lazy> = Lazy::new(|| sync::Mutex::new(())); fn set_root_dir(path: &path::Path) -> path::PathBuf { let root = path.join("root"); env::set_var("HOME", &root.join("home")); env::set_var("XDG_CACHE_HOME", ""); env::set_var("XDG_CONFIG_HOME", ""); env::set_var("XDG_DATA_HOME", ""); env::set_var("XDG_DATA_DIRS", &root.join("data")); env::set_var("XDG_CONFIG_DIRS", &root.join("config")); root } #[test_case(AppDataType::UserCache; "user cache")] #[test_case(AppDataType::UserConfig; "user config")] #[test_case(AppDataType::UserData; "user data")] #[test_case(AppDataType::SharedConfig; "shared config")] #[test_case(AppDataType::SharedData; "shared data")] fn test_no_create(ty: AppDataType) -> io::Result<()> { let _env_guard = ENV_MUTEX.lock(); let dir = tempfile::tempdir()?; let root_dir = set_root_dir(dir.path()); let info = app_dirs2::AppInfo { name: "test-app", author: "test-author", }; let data_root = app_dirs2::get_data_root(ty).unwrap(); assert!( data_root.starts_with(&root_dir), "Data root does not start with root dir: data root = {}, root dir = {}", data_root.display(), root_dir.display() ); assert!(!root_dir.exists()); let app_root = app_dirs2::get_app_root(ty, &info).unwrap(); assert!( app_root.starts_with(&data_root), "App root does not start with data root: app root = {}, data root = {}", app_root.display(), data_root.display() ); assert!(!root_dir.exists()); let app_dir = app_dirs2::get_app_dir(ty, &info, "testdir").unwrap(); assert!( app_dir.starts_with(&app_root), "App dir does not start with app root: app dir = {}, app root = {}", app_dir.display(), app_root.display() ); assert!(!root_dir.exists()); dir.close() } #[test_case(AppDataType::UserCache; "user cache")] #[test_case(AppDataType::UserConfig; "user config")] #[test_case(AppDataType::UserData; "user data")] #[test_case(AppDataType::SharedConfig; "shared config")] #[test_case(AppDataType::SharedData; "shared data")] fn test_create(ty: AppDataType) -> io::Result<()> { let _env_guard = ENV_MUTEX.lock(); let dir = tempfile::tempdir()?; let root_dir = set_root_dir(dir.path()); let info = app_dirs2::AppInfo { name: "test-app", author: "test-author", }; let data_root = app_dirs2::data_root(ty).unwrap(); assert!( data_root.starts_with(&root_dir), "Data root does not start with root dir: data root = {}, root dir = {}", data_root.display(), root_dir.display() ); assert!(data_root.is_dir()); let app_root = app_dirs2::app_root(ty, &info).unwrap(); assert!( app_root.starts_with(&data_root), "App root does not start with data root: app root = {}, data root = {}", app_root.display(), data_root.display() ); assert!(app_root.is_dir()); let app_dir = app_dirs2::app_dir(ty, &info, "testdir").unwrap(); assert!( app_dir.starts_with(&app_root), "App dir does not start with app root: app dir = {}, app root = {}", app_dir.display(), app_root.display() ); assert!(app_dir.is_dir()); dir.close() } app_dirs2-2.5.2/tests/unix.rs000064400000000000000000000076120072674642500142460ustar 00000000000000#![cfg(all(unix, not(target_os = "macos"), not(target_os = "android")))] use std::env; use std::ffi; use std::path; use std::sync; use app_dirs2::AppDataType; use once_cell::sync::Lazy; use test_case::test_case; // For test cases that depend on environment variables static ENV_MUTEX: Lazy> = Lazy::new(|| sync::Mutex::new(())); fn reset_env() { env::set_var("HOME", ""); env::set_var("XDG_CACHE_HOME", ""); env::set_var("XDG_CONFIG_HOME", ""); env::set_var("XDG_DATA_HOME", ""); env::set_var("XDG_DATA_DIRS", ""); env::set_var("XDG_CONFIG_DIRS", ""); } #[test_case(AppDataType::UserCache, ".cache"; "user cache")] #[test_case(AppDataType::UserConfig, ".config"; "user config")] #[test_case(AppDataType::UserData, ".local/share"; "user data")] #[test_case(AppDataType::SharedConfig, "/etc/xdg"; "shared config")] #[test_case(AppDataType::SharedData, "/usr/local/share"; "shared data")] fn test_home(ty: AppDataType, path: impl AsRef) { let _env_guard = ENV_MUTEX.lock(); let dir = tempfile::tempdir().unwrap(); reset_env(); env::set_var("HOME", dir.path()); let data_root = app_dirs2::get_data_root(ty).unwrap(); if ty.is_shared() { assert_eq!(path.as_ref(), data_root.as_path()); } else { assert_eq!(dir.path().join(path.as_ref()), data_root); } let app_info = app_dirs2::AppInfo { name: "app-name", author: "app-author", }; let app_root = app_dirs2::get_app_root(ty, &app_info).unwrap(); assert_eq!(data_root.join(app_info.name), app_root); let subdir = "testdir"; let app_dir = app_dirs2::get_app_dir(ty, &app_info, subdir).unwrap(); assert_eq!(app_root.join(subdir), app_dir); } #[test_case(AppDataType::UserCache, "XDG_CACHE_HOME"; "user cache")] #[test_case(AppDataType::UserConfig, "XDG_CONFIG_HOME"; "user config")] #[test_case(AppDataType::UserData, "XDG_DATA_HOME"; "user data")] #[test_case(AppDataType::SharedConfig, "XDG_CONFIG_DIRS"; "shared config")] #[test_case(AppDataType::SharedData, "XDG_DATA_DIRS"; "shared data")] fn test_xdg_dirs(ty: AppDataType, env_var: impl AsRef) { let _env_guard = ENV_MUTEX.lock(); let dir = tempfile::tempdir().unwrap(); reset_env(); env::set_var(env_var.as_ref(), dir.path()); let data_root = app_dirs2::get_data_root(ty).unwrap(); assert_eq!(dir.path(), data_root.as_path()); let app_info = app_dirs2::AppInfo { name: "app-name", author: "app-author", }; let app_root = app_dirs2::get_app_root(ty, &app_info).unwrap(); assert_eq!(data_root.join(app_info.name), app_root); let subdir = "testdir"; let app_dir = app_dirs2::get_app_dir(ty, &app_info, subdir).unwrap(); assert_eq!(app_root.join(subdir), app_dir); } #[test_case(AppDataType::UserCache, "XDG_CACHE_HOME"; "user cache")] #[test_case(AppDataType::UserConfig, "XDG_CONFIG_HOME"; "user config")] #[test_case(AppDataType::UserData, "XDG_DATA_HOME"; "user data")] #[test_case(AppDataType::SharedConfig, "XDG_CONFIG_DIRS"; "shared config")] #[test_case(AppDataType::SharedData, "XDG_DATA_DIRS"; "shared data")] fn test_home_and_xdg_dirs(ty: AppDataType, env_var: impl AsRef) { let _env_guard = ENV_MUTEX.lock(); let home_dir = tempfile::tempdir().unwrap(); let xdg_dir = tempfile::tempdir().unwrap(); reset_env(); env::set_var("HOME", home_dir.path()); env::set_var(env_var.as_ref(), xdg_dir.path()); let data_root = app_dirs2::get_data_root(ty).unwrap(); assert_eq!(xdg_dir.path(), data_root.as_path()); let app_info = app_dirs2::AppInfo { name: "app-name", author: "app-author", }; let app_root = app_dirs2::get_app_root(ty, &app_info).unwrap(); assert_eq!(data_root.join(app_info.name), app_root); let subdir = "testdir"; let app_dir = app_dirs2::get_app_dir(ty, &app_info, subdir).unwrap(); assert_eq!(app_root.join(subdir), app_dir); }