first commit
This commit is contained in:
commit
7d5812e192
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
630
Cargo.lock
generated
Normal file
630
Cargo.lock
generated
Normal file
|
@ -0,0 +1,630 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[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 = "arrayref"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"constant_time_eq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[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.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[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 = "cxx"
|
||||
version = "1.0.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90d59d9acd2a682b4e40605a242f6670eaa58c5957471cbf85e8aa6a0b97a5e8"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebfa40bda659dd5c864e65f4c9a2b0aff19bea56b017b9b77c73d3766a453a38"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "457ce6757c5c70dc6ecdbda6925b958aae7f959bda7d8fb9bde889e34a09dc03"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.90"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ebf883b7aacd7b2aeb2a7b338648ee19f57c140d4ee8e52c68979c6b2f7f2263"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "expanduser"
|
||||
version = "1.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14e0b79235da57db6b6c2beed9af6e5de867d63a973ae3e91910ddc33ba40bc0"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"lazy_static",
|
||||
"pwd",
|
||||
]
|
||||
|
||||
[[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 = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
|
||||
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 = "libc"
|
||||
version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[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 = "nom8"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[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-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pwd"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72c71c0c79b9701efe4e1e4b563b2016dd4ee789eb99badcb09d61ac4b92e4a2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[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.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"rust-argon2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"blake2b_simd",
|
||||
"constant_time_eq",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
|
||||
|
||||
[[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 = "serde_spanned"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "soyuz-cli"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"expanduser",
|
||||
"regex",
|
||||
"serde",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[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.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
||||
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 = "time"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e6a7712b49e1775fb9a7b998de6635b299237f48b404dde71704f2e0e7f37e5"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"nom8",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[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.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.84"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
|
||||
|
||||
[[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"
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "soyuz-cli"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.23"
|
||||
expanduser = "1.2.2"
|
||||
regex = "1.7.1"
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
toml = { version = "0.7.2", features = ["parse"] }
|
23
README.md
Normal file
23
README.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# soyuz-cli
|
||||
|
||||
This is the sister application to `soyuz-web`.
|
||||
|
||||
`soyuz-cli` can be used alone or on combination with `soyuz-web` to publish and syncronise a gemlog between your local machine and your gemini server.
|
||||
|
||||
It is essentially a wrapper around `rsync`. Additionally it will maintain an archive of posts for each year, and the latest 5 posts on your gemlog homepage.
|
||||
|
||||
## Assumptions
|
||||
|
||||
1. You are using MacOS locally and a unix-like OS on the server (it probably works on n*x locally but I haven't tested it)
|
||||
2. If you have text _under_ the list of latest posts on your homepage, you have at least 5 posts listed already (I could have put in some logic to deal with this but I am lazy)
|
||||
3. You have `rsync` installed on your local machine
|
||||
4. You have read and write permission for your gemlog files on the server, with the same username as your local machine (otherwise file permissions get weird)
|
||||
5. You have permission to install files at `/usr/local/bin` on your local machine
|
||||
|
||||
## Installation
|
||||
|
||||
The easiest way to install `soyuz-cli` is using the install script:
|
||||
|
||||
```sh
|
||||
curl https://hugh.run/install-soyuz | bash
|
||||
```
|
16
install.sh
Executable file
16
install.sh
Executable file
|
@ -0,0 +1,16 @@
|
|||
#!/bin/sh
|
||||
|
||||
# This script installs soyuz-cli
|
||||
# Download latest binary and save in /usr/local/bin
|
||||
curl -L https://github.com/hughrun/soyuz-cli/releases/download/latest/MacOS > /usr/local/bin/soyuz
|
||||
# make it executable
|
||||
chmod +x /usr/local/bin/yawp_test
|
||||
|
||||
cat 1>&2 << 'EOM'
|
||||
|
||||
🚀 soyuz-cli is now installed!
|
||||
|
||||
🔧 Get set up with 'soyuz settings'
|
||||
ℹ️ For help try 'soyuz help'
|
||||
|
||||
EOM
|
308
src/main.rs
Normal file
308
src/main.rs
Normal file
|
@ -0,0 +1,308 @@
|
|||
#![feature(file_create_new)]
|
||||
#![feature(fs_try_exists)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use chrono::prelude::*;
|
||||
use std::env;
|
||||
use expanduser::expanduser;
|
||||
use std::path::PathBuf;
|
||||
use regex::Regex;
|
||||
use serde::Deserialize;
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
use toml;
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Config {
|
||||
local_dir: String,
|
||||
remote_dir: String,
|
||||
editor: String,
|
||||
index_heading: String
|
||||
}
|
||||
|
||||
fn create_or_update_homepage(string: String) -> Result<(), std::io::Error> {
|
||||
let config = read_config().expect("cannot read config");
|
||||
let filepath = format!("{}{}", config.local_dir, "index.gmi");
|
||||
match fs::try_exists(&filepath) {
|
||||
Ok(true) => {
|
||||
let homepage = fs::read_to_string(&filepath)?;
|
||||
match homepage.find(&string) {
|
||||
Some(_s) => {
|
||||
// if it's already listed, do nothing and move on...
|
||||
},
|
||||
None => {
|
||||
let mut lines: Vec<&str> = homepage.lines().collect();
|
||||
if lines.contains(&config.index_heading.as_str()) {
|
||||
let i = lines.iter().position(|x| x == &config.index_heading).unwrap(); // ERROR here if the file exists but is empty
|
||||
let first_entry = format!("\n{}", string);
|
||||
lines[i + 1] = &first_entry;
|
||||
lines.remove(i + 6);
|
||||
fs::write(filepath, lines.join("\n"))?;
|
||||
} else {
|
||||
// if the file exists but is empty (or can't find the header) just write out the new entry
|
||||
// Note: this will overwrite the homepage if it doesn't contain the header string exactly as
|
||||
// per the config
|
||||
let contents = format!("{}\n\n{}", config.index_heading, string);
|
||||
fs::write(&filepath, contents)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Ok(false) => {
|
||||
// there's no homepage, create a new one
|
||||
let contents = format!("{}\n\n{}", config.index_heading, string);
|
||||
fs::write(&filepath, contents)?;
|
||||
},
|
||||
Err(err) => eprintln!("{}", err)
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn help() {
|
||||
println!("Союз (Soyuz) - v{}", option_env!("CARGO_PKG_VERSION").unwrap());
|
||||
println!("A command line program for publishing Gemini posts.\n");
|
||||
println!(" soyuz ( help | settings | write | publish | sync [ --overwrite | --delete ] )\n");
|
||||
println!(" help");
|
||||
println!(" - shows this help screen\n");
|
||||
println!(" settings");
|
||||
println!(" - create or edit the settings file\n");
|
||||
println!(" write");
|
||||
println!(" - create or edit today's gempost using the editor specified in the settings file\n");
|
||||
println!(" publish");
|
||||
println!(" - update the homepage and year archive lists of posts, and publish to server.");
|
||||
println!(" Syncs new or changed files from the server before updating indexes and syncing up.\n");
|
||||
println!(" sync");
|
||||
println!(" - synchronise files between local machine and server.");
|
||||
println!(" This is a wrapper around rsync, the default being 'rsync -rtOq'");
|
||||
println!(" Without arguments sync defaults to 'sync up' which is the equivalent of 'publish'\n");
|
||||
println!(" sync up");
|
||||
println!(" - syncronise new or changed files from local machine to server.\n");
|
||||
println!(" sync down");
|
||||
println!(" - syncronise new or changed files from server to local machine.\n");
|
||||
println!(" sync (down | up) --overwrite");
|
||||
println!(" - sync, and overwrite all files at the destination regardless of last edit date.");
|
||||
println!(" Without this flag, sync will ignore files at the destination edited more recently than the source.\n");
|
||||
println!(" sync (down | up) --delete");
|
||||
println!(" - sync, and delete any files at the destination that do not exist at the source.\n");
|
||||
}
|
||||
|
||||
fn open_file(filepath: std::path::PathBuf) {
|
||||
let editor = match read_config() {
|
||||
Ok(config) => config.editor,
|
||||
Err(_err) => String::from("nano")
|
||||
};
|
||||
|
||||
let mut open = Command::new(&editor)
|
||||
.arg(&filepath)
|
||||
.spawn()
|
||||
.expect(format!("Failed to run {} {:?} command", editor, filepath.into_os_string()).as_str());
|
||||
let _result = open.wait().expect("problem waiting for editor");
|
||||
}
|
||||
|
||||
fn publish() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let config = read_config()?;
|
||||
// sync down from server (only files that are newer on the server than local)
|
||||
let mut sync = Command::new("rsync")
|
||||
.args(["-rtOq", "--update", &config.remote_dir, &config.local_dir])
|
||||
.spawn()
|
||||
.expect("syncing from server failed");
|
||||
let _result = sync.wait().expect("problem waiting for rsync");
|
||||
// check for this year's directory
|
||||
let dt = Local::now();
|
||||
let year = &dt.format("%Y").to_string();
|
||||
let dirpath = format!("{}{}", &config.local_dir, year);
|
||||
let indexfilepath = format!("{}/{}", &dirpath, "index.gmi");
|
||||
if let Ok(entries) = fs::read_dir(&dirpath) {
|
||||
let mut most_recent: (i32, String) = (0,String::new());
|
||||
for entry in entries {
|
||||
if let Ok(entry) = entry {
|
||||
// if filename format yyyy-mm-dd.gmi
|
||||
let re = Regex::new(r"^\d{4}-\d{2}-\d{2}$").expect("Error creating regex");
|
||||
let file_string = entry.file_name().into_string().expect("Cannot parse filename");
|
||||
let ent = match &file_string.strip_suffix(".gmi") {
|
||||
Some(stripped) => stripped,
|
||||
None => ""
|
||||
};
|
||||
if re.is_match(&ent) {
|
||||
let allnums = ent.replace("-", "");
|
||||
let name_as_int: i32 = allnums.parse().unwrap();
|
||||
if most_recent.0 < name_as_int {
|
||||
most_recent = (name_as_int, file_string);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
if most_recent.0 > 0 {
|
||||
let filename = most_recent.1;
|
||||
let sliced = &filename.strip_suffix(".gmi").expect("file is not a gemini file!");
|
||||
let post = fs::read_to_string(format!("{}/{}", dirpath, &filename))?;
|
||||
let post_lines: Vec<&str> = post.lines().collect();
|
||||
let title = post_lines[0].strip_prefix("# ");
|
||||
let entry_string = format!("=> {} {} ({})", filename, sliced, title.unwrap());
|
||||
let home_entry_string = format!("=> /{}/{} {} ({})", &year, filename, sliced, title.unwrap());
|
||||
if let Ok(index) = fs::read_to_string(&indexfilepath) {
|
||||
// is the file listed in the archive?
|
||||
match index.find(&filename) {
|
||||
Some(_i) => {
|
||||
// the file is already listed in the year index
|
||||
// check that it's listed on the homepage too
|
||||
create_or_update_homepage(home_entry_string)?;
|
||||
},
|
||||
None => {
|
||||
let mut lines: Vec<&str> = index.lines().collect();
|
||||
if lines.len() > 2 {
|
||||
// there's an archive page, update it
|
||||
let first_value = format!("{}\n{}", &entry_string, lines[2]);
|
||||
lines[2] = &first_value;
|
||||
let new_string = lines.join("\n");
|
||||
fs::write(indexfilepath, &new_string)?;
|
||||
} else {
|
||||
// file is blank, overwrite it
|
||||
let contents = format!("# {}\n\n{}", &year, &entry_string);
|
||||
fs::write(indexfilepath, contents)?;
|
||||
}
|
||||
// update or create the homepage
|
||||
create_or_update_homepage(home_entry_string)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// year archive file doesn't exist, just create it
|
||||
let contents = format!("# {}\n\n{}", &year, &entry_string);
|
||||
fs::write(indexfilepath, contents)?;
|
||||
create_or_update_homepage(home_entry_string)?;
|
||||
}
|
||||
|
||||
} else {
|
||||
// dir has no files for some reason in
|
||||
// in this case there's nothing to do
|
||||
// except sync up any changes from other dirs
|
||||
}
|
||||
} else {
|
||||
// create new directory then try again
|
||||
// this will create an empty archive if used
|
||||
// before there are any new posts for the year
|
||||
fs::create_dir_all(dirpath)?;
|
||||
publish()?;
|
||||
}
|
||||
|
||||
// rsync to server (no del)
|
||||
let mut sync_up = Command::new("rsync")
|
||||
.args(["-rtOq", &config.local_dir, &config.remote_dir])
|
||||
.spawn()
|
||||
.expect("syncing to server failed");
|
||||
let _sync_up_result = sync_up.wait().expect("problem waiting for rsync up");
|
||||
println!("🎉 published!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn read_config() -> Result<Config, Box<dyn std::error::Error>> {
|
||||
let config_path: std::path::PathBuf = expanduser("~/.config/soyuz/config.toml")?;
|
||||
let vals = fs::read_to_string(config_path)?;
|
||||
|
||||
let mut config: Config = toml::from_str(&vals)?;
|
||||
let local: PathBuf = expanduser(config.local_dir).unwrap();
|
||||
let remote: PathBuf = expanduser(config.remote_dir).unwrap();
|
||||
let l_trimmed = local.to_str().unwrap().trim_end_matches("/");
|
||||
let r_trimmed = remote.to_str().unwrap().trim_end_matches("/");
|
||||
config.local_dir = format!("{}/", l_trimmed);
|
||||
config.remote_dir = format!("{}/", r_trimmed);
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
|
||||
fn settings() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let config_dir: std::path::PathBuf = expanduser("~/.config/soyuz")?;
|
||||
let config_path: std::path::PathBuf = expanduser("~/.config/soyuz/config.toml")?;
|
||||
fs::create_dir_all(config_dir)?;
|
||||
let _file = match fs::File::create_new(&config_path) {
|
||||
Ok(_file) => {
|
||||
fs::write(&config_path, "local_dir = \nremote_dir = \neditor = \"nano\"\nindex_heading =\"## Latest notes\"\n")
|
||||
},
|
||||
Err(_err) => Ok(()) // do nothing, this means the file exists already
|
||||
};
|
||||
Ok(open_file(config_path))
|
||||
}
|
||||
|
||||
fn sync(args: &Vec<String>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let config = read_config()?;
|
||||
let rsync_args = match args.len() {
|
||||
2 => ["-rtOq", "--update", &config.remote_dir, &config.local_dir],
|
||||
3 | 4 => {
|
||||
match args[2].as_str() {
|
||||
"down" => {
|
||||
if args.len() == 3 {
|
||||
["-rtOq", "--update", &config.remote_dir, &config.local_dir]
|
||||
} else {
|
||||
match args[3].as_str() {
|
||||
"--overwrite" => {
|
||||
["-rtO", "--quiet", &config.remote_dir, &config.local_dir]
|
||||
},
|
||||
"--delete" => {
|
||||
["-rtOq", "--delete", &config.remote_dir, &config.local_dir]
|
||||
},
|
||||
_ => ["", "", "", ""],
|
||||
}
|
||||
}
|
||||
},
|
||||
"up" => {
|
||||
if args.len() == 3 {
|
||||
["-rtOq", "--update", &config.local_dir, &config.remote_dir]
|
||||
} else {
|
||||
match args[3].as_str() {
|
||||
"--overwrite" => {
|
||||
["-rtO", "--quiet", &config.local_dir, &config.remote_dir]
|
||||
},
|
||||
"--delete" => {
|
||||
["-rtOq", "--delete", &config.local_dir, &config.remote_dir]
|
||||
},
|
||||
_ => ["", "", "", ""],
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => ["","","",""],
|
||||
}
|
||||
},
|
||||
_ => ["","","",""],
|
||||
};
|
||||
if rsync_args[0] == "" {
|
||||
Ok(help())
|
||||
} else {
|
||||
let mut sync = Command::new("rsync")
|
||||
.args(rsync_args)
|
||||
.spawn()
|
||||
.expect("syncing failed");
|
||||
let _sync_res = sync.wait().expect("problem waiting for rsync");
|
||||
Ok(println!("Sync complete."))
|
||||
}
|
||||
}
|
||||
|
||||
fn write() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let config = read_config()?;
|
||||
let dt = Local::now();
|
||||
let year = &dt.format("%Y").to_string();
|
||||
let local_dir: std::path::PathBuf = expanduser(config.local_dir)?;
|
||||
fs::create_dir_all(format!("{}{}", &local_dir.display(), &year))?;
|
||||
let filepath = format!("{}{}/{}.gmi", local_dir.display(), year, dt.format("%Y-%m-%d"));
|
||||
Ok(open_file(filepath.into()))
|
||||
}
|
||||
|
||||
fn match_single_arg(args: &Vec<String>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match args[1].as_str() {
|
||||
"write" => write(),
|
||||
"settings" => settings(),
|
||||
"publish" => publish(),
|
||||
"sync" => sync(args),
|
||||
_ => Ok(help())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>>{
|
||||
let args: Vec<String> = env::args().collect();
|
||||
match &args.len() {
|
||||
1 => Ok(help()),
|
||||
2 => match_single_arg(&args),
|
||||
3 | 4 => sync(&args),
|
||||
_ => Ok(help())
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue