diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..6e99047 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,19 @@ +name: 'Dependency Review' + +on: [ pull_request ] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v3 + + - name: 'Dependency Review' + uses: actions/dependency-review-action@v3 + with: + config-file: darbiadev/.github/.github/dependency-review-config.yaml@main diff --git a/.github/workflows/github-pages-rust-doc.yaml b/.github/workflows/github-pages-rust-doc.yaml new file mode 100644 index 0000000..75ed16c --- /dev/null +++ b/.github/workflows/github-pages-rust-doc.yaml @@ -0,0 +1,10 @@ +name: GitHub Pages - Rust doc + +on: + push: + branches: + - main + +jobs: + docs: + uses: darbiadev/.github/.github/workflows/github-pages-rust-doc.yaml@main diff --git a/Cargo.lock b/Cargo.lock index 9a35a46..014c1e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,677 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" + +[[package]] +name = "atomic" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39" +dependencies = [ + "bitflags", + "clap_lex", + "is-terminal", + "once_cell", + "strsim", + "termcolor", +] + +[[package]] +name = "clap_lex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + +[[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 = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "figment" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e56602b469b2201400dec66a66aec5a9b8761ee97cd1b8c96ab2483fcc16cc9" +dependencies = [ + "atomic", + "pear", + "serde", + "toml", + "uncased", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "inlinable_string" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" + +[[package]] +name = "io-lifetimes" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" +dependencies = [ + "hermit-abi", + "io-lifetimes", + "rustix", + "windows-sys", +] + +[[package]] +name = "itoa" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" + +[[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.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "once_cell" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" + +[[package]] +name = "os_str_bytes" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "pear" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" +dependencies = [ + "inlinable_string", + "pear_codegen", + "yansi", +] + +[[package]] +name = "pear_codegen" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "proc-macro2" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "version_check", + "yansi", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +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 = "rustix" +version = "0.36.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4feacf7db682c6c329c4ede12649cd36ecab0f3be5b7d74e6a20304725db4549" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "serde" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "sherbert" version = "0.2.0" +dependencies = [ + "anyhow", + "clap", + "dirs", + "figment", + "serde", + "tracing", + "tracing-appender", + "tracing-subscriber", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[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.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +dependencies = [ + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +dependencies = [ + "time-core", +] + +[[package]] +name = "toml" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +dependencies = [ + "serde", +] + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-appender" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e" +dependencies = [ + "crossbeam-channel", + "time", + "tracing-subscriber", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "uncased" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[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 = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Cargo.toml b/Cargo.toml index ed6cefd..d1660d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,21 @@ repository = "https://github.com/letsbuilda/sherbert/" keywords = ["cli"] categories = ["command-line-utilities"] +[lib] +name = "sherbert" +path = "src/sherbert/lib.rs" + +[[bin]] +name = "sherbert" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +clap = { version = "4.0.32", features = ["cargo"] } +tracing = "0.1" +tracing-subscriber = "0.3" +tracing-appender = "0.2" +figment = { version = "0.10.8", features = ["env", "toml"] } +dirs = "4.0.0" +serde = { version = "1.0", features = ["derive"] } +anyhow = "1.0.68" diff --git a/README.md b/README.md index 89aa82b..8c954d9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # sherbert + Opinionated project tooling diff --git a/src/bin/sherbert/cli.rs b/src/bin/sherbert/cli.rs new file mode 100644 index 0000000..497f88d --- /dev/null +++ b/src/bin/sherbert/cli.rs @@ -0,0 +1,90 @@ +//! CLI + +use clap::{command, Arg, ArgAction, ArgMatches, Command}; + +use sherbert::config::Config; +use sherbert::errors::CliResult; + +use crate::commands; + +/// Build the main CLI +pub(crate) fn build_cli() -> Command { + command!() + .infer_long_args(true) + .infer_subcommands(true) + .arg_required_else_help(true) + .arg( + Arg::new("verbose") + .short('v') + .long("verbose") + .conflicts_with("quiet") + .action(ArgAction::Count) + .help("Sets the level of verbosity") + .global(true), + ) + .arg( + Arg::new("quiet") + .short('q') + .long("quiet") + .conflicts_with("verbose") + .action(ArgAction::SetTrue) + .help("Suppresses all output") + .global(true), + ) + .subcommands(commands::builtin()) +} + +/// Init logging subscriber. +fn init_logging(log_level: tracing_subscriber::filter::LevelFilter) { + tracing_subscriber::fmt() + .event_format(tracing_subscriber::fmt::format().compact()) + .with_max_level(log_level) + .init(); +} + +/// Subcommand entrypoint. +fn execute_subcommand(config: &mut Config, cmd: &str, subcommand_args: &ArgMatches) -> CliResult { + if let Some(exec) = commands::builtin_exec(cmd) { + exec(config, subcommand_args) + } else { + Ok(()) + } + + // let mut ext_args: Vec<&OsStr> = vec![OsStr::new(cmd)]; + // ext_args.extend( + // subcommand_args + // .get_many::("") + // .unwrap_or_default() + // .map(OsString::as_os_str), + // ); + // super::execute_external_subcommand(config, cmd, &ext_args) +} + +/// CLI entrypoint. +pub fn main(config: &mut Config) -> CliResult { + let matches = build_cli().get_matches(); + + config.update_from_matches(&matches); + + init_logging(config.level_filter()); + + let (cmd, subcommand_args) = match matches.subcommand() { + Some((cmd, args)) => (cmd, args), + _ => { + return Ok(()); + } + }; + + // tracing::error!("{:#?}", "error"); + // tracing::warn!("{:#?}", "warn"); + // tracing::info!("{:#?}", "info"); + // tracing::debug!("{:#?}", "debug"); + // tracing::trace!("{:#?}", "trace"); + + execute_subcommand(config, cmd, subcommand_args) +} + +#[test] +fn verify_cli() { + build_cli().debug_assert(); +} diff --git a/src/bin/sherbert/commands.rs b/src/bin/sherbert/commands.rs new file mode 100644 index 0000000..c02de35 --- /dev/null +++ b/src/bin/sherbert/commands.rs @@ -0,0 +1,22 @@ +//! CLI subcommands + +use clap::{ArgMatches, Command}; + +use sherbert::config::Config; +use sherbert::errors::CliResult; + +pub mod metadata; + +/// Build all builtin commands +pub fn builtin() -> Vec { + vec![metadata::cli()] +} + +/// Find builtin executor to exec +pub fn builtin_exec(cmd: &str) -> Option CliResult> { + let function = match cmd { + "metadata" => metadata::exec, + _ => return None, + }; + Some(function) +} diff --git a/src/bin/sherbert/commands/metadata.rs b/src/bin/sherbert/commands/metadata.rs new file mode 100644 index 0000000..a225c47 --- /dev/null +++ b/src/bin/sherbert/commands/metadata.rs @@ -0,0 +1,24 @@ +//! Metadata. + +use std::env; + +use clap::{ArgMatches, Command}; + +use sherbert::config::Config; +use sherbert::errors::CliResult; +use sherbert::paths::find_file; + +/// Build CLI for `metadata` subcommand. +pub fn cli() -> Command { + Command::new("metadata").about("Output project metadata") +} + +/// Exec `metadata` action. +pub fn exec(config: &mut Config, _args: &ArgMatches) -> CliResult { + let path = env::current_dir()?; + let file = find_file(path, "Cargo.toml"); + if config.log_level != -1 { + println!("{file:?}"); + } + Ok(()) +} diff --git a/src/bin/sherbert/main.rs b/src/bin/sherbert/main.rs new file mode 100644 index 0000000..e310403 --- /dev/null +++ b/src/bin/sherbert/main.rs @@ -0,0 +1,36 @@ +#![forbid(clippy::missing_docs_in_private_items)] +#![warn(rust_2018_idioms)] + +//! # Sherbert +//! +//! Opinionated project tooling. + +use figment::providers::Serialized; +use figment::{ + providers::{Env, Format, Toml}, + Figment, +}; + +use sherbert::config::Config; + +mod cli; +mod commands; + +/// Entrypoint. +fn main() { + let mut config_toml_path = dirs::config_dir().expect("Failed to get user config directory"); + config_toml_path.push("letsbuilda"); + config_toml_path.push("sherbert.toml"); + + let mut config: Config = Figment::from(Serialized::defaults(Config::default())) + .merge(Toml::file(config_toml_path).nested()) + .merge(Env::prefixed("SHERBERT_")) + .extract() + .unwrap(); + + let result = cli::main(&mut config); + match result { + Ok(()) => {} + Err(err) => println!("{err:?}"), + } +} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index e7a11a9..0000000 --- a/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/src/sherbert/config.rs b/src/sherbert/config.rs new file mode 100644 index 0000000..81d531d --- /dev/null +++ b/src/sherbert/config.rs @@ -0,0 +1,53 @@ +//! Struct to hold internal config + +use clap::ArgMatches; +use serde::{Deserialize, Serialize}; + +/// Configuration information for sherbert. This is not specific to a build, it is information +/// relating to sherbert itself. +#[derive(Debug, Deserialize, Serialize)] +pub struct Config { + /// The level of messages to log. + pub log_level: i8, +} + +impl Config { + /// Creates a new config instance. + #[must_use] + pub fn new(log_level: i8) -> Config { + Config { log_level } + } + + /// # Update the config from the CLI matches. + /// + /// # Panics + /// + /// Will panic if it can't read the `quiet` bool from the matches. + pub fn update_from_matches(&mut self, matches: &ArgMatches) { + #![allow(clippy::cast_possible_wrap)] + self.log_level = if *matches.get_one::("quiet").unwrap() { + -1 + } else { + matches.get_count("verbose") as i8 + }; + } + + /// Get the configured log level. + #[must_use] + pub fn level_filter(&self) -> tracing_subscriber::filter::LevelFilter { + match self.log_level { + -1 => tracing_subscriber::filter::LevelFilter::OFF, + 0 => tracing_subscriber::filter::LevelFilter::ERROR, + 1 => tracing_subscriber::filter::LevelFilter::WARN, + 2 => tracing_subscriber::filter::LevelFilter::INFO, + 3 => tracing_subscriber::filter::LevelFilter::DEBUG, + _ => tracing_subscriber::filter::LevelFilter::TRACE, + } + } +} + +impl Default for Config { + fn default() -> Config { + Config::new(0) + } +} diff --git a/src/sherbert/errors.rs b/src/sherbert/errors.rs new file mode 100644 index 0000000..f5e9382 --- /dev/null +++ b/src/sherbert/errors.rs @@ -0,0 +1,57 @@ +//! Error types + +/// Result of a CLI function +pub type CliResult = Result<(), CliError>; + +#[derive(Debug)] +/// The CLI error is the error type used at Sherbert's CLI-layer. +/// +/// All errors from the lib side of Sherbert will get wrapped with this error. +/// Other errors (such as command-line argument validation) will create this +/// directly. +pub struct CliError { + /// The error to display. This can be `None` in rare cases to exit with a + /// code without displaying a message. + pub error: Option, + /// The process exit code. + pub exit_code: i32, +} + +impl CliError { + /// Create new error + #[must_use] + pub fn new(error: anyhow::Error, code: i32) -> CliError { + CliError { + error: Some(error), + exit_code: code, + } + } + + /// Create new error from code + #[must_use] + pub fn code(code: i32) -> CliError { + CliError { + error: None, + exit_code: code, + } + } +} + +impl From for CliError { + fn from(err: anyhow::Error) -> CliError { + CliError::new(err, 101) + } +} + +impl From for CliError { + fn from(err: clap::Error) -> CliError { + let code = i32::from(err.use_stderr()); + CliError::new(err.into(), code) + } +} + +impl From for CliError { + fn from(err: std::io::Error) -> CliError { + CliError::new(err.into(), 1) + } +} diff --git a/src/sherbert/lib.rs b/src/sherbert/lib.rs new file mode 100644 index 0000000..6e1af57 --- /dev/null +++ b/src/sherbert/lib.rs @@ -0,0 +1,10 @@ +#![forbid(clippy::missing_docs_in_private_items)] +#![warn(rust_2018_idioms)] + +//! # Sherbert as a library +//! +//! Sherbert's internal library is available on it's own. + +pub mod config; +pub mod errors; +pub mod paths; diff --git a/src/sherbert/paths.rs b/src/sherbert/paths.rs new file mode 100644 index 0000000..dccd643 --- /dev/null +++ b/src/sherbert/paths.rs @@ -0,0 +1,23 @@ +//! Path helpers. + +use std::path::{Path, PathBuf}; + +/// Search for file. +#[must_use] +pub fn find_file(starting_directory: PathBuf, filename: &str) -> Option { + let mut path: PathBuf = starting_directory; + let file = Path::new(filename); + + loop { + path.push(file); + + if path.is_file() { + break Some(path); + } + + if !(path.pop() && path.pop()) { + // remove file && remove parent + break None; + } + } +}