diff --git a/Cargo.lock b/Cargo.lock index 6cb9070a..ef7aa03d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,18 +17,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -161,6 +149,21 @@ dependencies = [ "syn", ] +[[package]] +name = "async_zip" +version = "0.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b9f7252833d5ed4b00aa9604b563529dd5e11de9c23615de2dcdf91eb87b52" +dependencies = [ + "async-compression", + "crc32fast", + "futures-lite", + "pin-project", + "thiserror", + "tokio", + "tokio-util", +] + [[package]] name = "atomic" version = "0.5.3" @@ -201,7 +204,7 @@ dependencies = [ "pin-project-lite", "rustversion", "serde", - "sync_wrapper", + "sync_wrapper 0.1.2", "tower", "tower-layer", "tower-service", @@ -546,17 +549,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "displaydoc" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "either" version = "1.12.0" @@ -588,18 +580,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - [[package]] name = "fastrand" version = "2.1.0" @@ -712,6 +692,19 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -868,18 +861,6 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown 0.14.5", -] [[package]] name = "heck" @@ -957,9 +938,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.3" +version = "1.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" [[package]] name = "httpdate" @@ -1011,6 +992,23 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.3.1", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + [[package]] name = "hyper-timeout" version = "0.4.1" @@ -1059,134 +1057,14 @@ dependencies = [ "tracing", ] -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "idna" -version = "1.0.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "icu_normalizer", - "icu_properties", - "smallvec", - "utf8_iter", + "unicode-bidi", + "unicode-normalization", ] [[package]] @@ -1285,7 +1163,7 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ - "spin", + "spin 0.5.2", ] [[package]] @@ -1324,17 +1202,6 @@ dependencies = [ "libc", ] -[[package]] -name = "libsqlite3-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - [[package]] name = "libssh2-sys" version = "0.3.0" @@ -1367,12 +1234,6 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" -[[package]] -name = "litemap" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" - [[package]] name = "lock_api" version = "0.4.12" @@ -1420,9 +1281,9 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", ] @@ -1599,6 +1460,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.3" @@ -1769,9 +1636,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1951,9 +1818,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" dependencies = [ "base64 0.22.1", "bytes", @@ -1965,6 +1832,7 @@ dependencies = [ "http-body 1.0.0", "http-body-util", "hyper 1.3.1", + "hyper-rustls", "hyper-tls", "hyper-util", "ipnet", @@ -1979,7 +1847,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper", + "sync_wrapper 1.0.1", "system-configuration", "tokio", "tokio-native-tls", @@ -1991,6 +1859,21 @@ dependencies = [ "winreg", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "rsa" version = "0.9.6" @@ -2012,20 +1895,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "rusqlite" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" -dependencies = [ - "bitflags 2.5.0", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - [[package]] name = "rustc-demangle" version = "0.1.24" @@ -2045,6 +1914,19 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.23.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" +dependencies = [ + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "2.1.2" @@ -2061,6 +1943,17 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +[[package]] +name = "rustls-webpki" +version = "0.102.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.17" @@ -2246,6 +2139,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "spki" version = "0.7.3" @@ -2256,12 +2155,6 @@ dependencies = [ "der", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "strsim" version = "0.11.1" @@ -2270,15 +2163,15 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "0d0208408ba0c3df17ed26eb06992cb1a1268d41b2c0e12e65203fbe3972cee5" [[package]] name = "syn" -version = "2.0.66" +version = "2.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "ff8655ed1d86f3af4ee3fd3263786bc14245ad17c4c7e85ba7187fb3ae028c90" dependencies = [ "proc-macro2", "quote", @@ -2292,15 +2185,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] -name = "synstructure" -version = "0.13.1" +name = "sync_wrapper" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "system-configuration" @@ -2388,15 +2276,20 @@ dependencies = [ ] [[package]] -name = "tinystr" -version = "0.7.6" +name = "tinyvec" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ - "displaydoc", - "zerovec", + "tinyvec_macros", ] +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.38.0" @@ -2447,6 +2340,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.15" @@ -2481,6 +2385,7 @@ checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -2683,6 +2588,12 @@ dependencies = [ "unic-common", ] +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -2690,27 +2601,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "url" -version = "2.5.1" +name = "unicode-normalization" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", + "tinyvec", ] [[package]] -name = "utf16_iter" -version = "1.0.5" +name = "untrusted" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] -name = "utf8_iter" -version = "1.0.4" +name = "url" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] [[package]] name = "utf8parse" @@ -2752,11 +2666,10 @@ version = "0.1.0" dependencies = [ "anyhow", "async-compression", + "async_zip", "clap", "dirs", - "flate2", - "futures", - "futures-util", + "futures-lite", "git2", "hex", "infer", @@ -2765,12 +2678,12 @@ dependencies = [ "rand", "reqwest", "rsa", - "rusqlite", "sha256", "tera", "tokio", "tokio-stream", "tokio-tar", + "tokio-util", "tonic", "tonic-build", "tracing", @@ -3061,18 +2974,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - [[package]] name = "xattr" version = "1.3.1" @@ -3093,99 +2994,12 @@ dependencies = [ "lzma-sys", ] -[[package]] -name = "yoke" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.7.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zerofrom" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -[[package]] -name = "zerovec" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "zstd" version = "0.13.1" @@ -3206,9 +3020,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" +version = "2.0.11+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +checksum = "75652c55c0b6f3e6f12eb786fe1bc960396bf05a1eb3bf1f3691c3610ac2e6d4" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 93804d0d..251148cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,11 +10,10 @@ path = "src/bin/main.rs" [dependencies] anyhow = "1" async-compression = { version = "0", features = ["all"] } +async_zip = { version = "0", features = ["deflate", "tokio"] } clap = { version = "4", features = ["derive"] } dirs = "5" -flate2 = "1" -futures = "0" -futures-util = "0" +futures-lite = { version = "2", default-features = false, features = ["std"] } git2 = "0" hex = "0" infer = "0" @@ -22,13 +21,13 @@ process-stream = "0" prost = "0" rand = "0" rsa = { version = "0", features = ["sha2"] } -rusqlite = { version = "0", features = ["bundled"] } sha256 = "1" reqwest = { version = "0", features = ["json"] } tera = { version = "1", default-features = false } tokio = { version = "1", features = ["full"] } tokio-stream = "0" tokio-tar = "0" +tokio-util = { version = "0", features = ["compat"] } tonic = "0" url = "2" uuid = { version = "1", features = ["v7"] } diff --git a/api/v0/command/command.proto b/api/v0/command/command.proto deleted file mode 100644 index 29e6d68f..00000000 --- a/api/v0/command/command.proto +++ /dev/null @@ -1,34 +0,0 @@ -syntax = "proto3"; - -package vorpal.command.v0; - -service CommandService { - rpc Package (PackageRequest) returns (stream PackageResponse); -} - -enum PackageSourceKind { - UNKNOWN = 0; - LOCAL = 1; - HTTP = 2; - GIT = 3; -} - -message PackageSource { - PackageSourceKind kind = 1; - optional string hash = 2; - repeated string ignore_paths = 3; - string uri = 4; -} - -message PackageResponse { - string package_log = 1; -} - -message PackageRequest { - repeated PackageResponse build_deps = 1; - repeated PackageResponse install_deps = 2; - string build_phase = 4; - string install_phase = 5; - string name = 6; - PackageSource source = 7; -} diff --git a/api/v0/config/config.proto b/api/v0/config/config.proto new file mode 100644 index 00000000..4d0e48c7 --- /dev/null +++ b/api/v0/config/config.proto @@ -0,0 +1,45 @@ +syntax = "proto3"; + +package vorpal.config.v0; + +service ConfigService { + rpc Package (ConfigPackageRequest) returns (stream ConfigPackageResponse); + // rpc Secret (ConfigSecretRequest) returns (stream ConfigSecretResponse); +} + +enum ConfigPackageSourceKind { + UNKNOWN = 0; + LOCAL = 1; + HTTP = 2; + GIT = 3; +} + +message ConfigPackageOutput { + string name = 1; + string hash = 2; +} + +message ConfigPackageBuild { + bool sandbox = 1; + map environment = 2; + repeated ConfigPackageOutput packages = 3; + string script = 4; +} + +message ConfigPackageSource { + ConfigPackageSourceKind kind = 1; + optional string hash = 2; + repeated string ignore_paths = 3; + string uri = 4; +} + +message ConfigPackageRequest { + ConfigPackageBuild build = 1; + ConfigPackageSource source = 2; + string name = 3; +} + +message ConfigPackageResponse { + optional ConfigPackageOutput package_output = 1; + bytes log_output = 2; +} diff --git a/api/v0/package/package.proto b/api/v0/package/package.proto index afe16f3d..263714fd 100644 --- a/api/v0/package/package.proto +++ b/api/v0/package/package.proto @@ -3,38 +3,35 @@ syntax = "proto3"; package vorpal.package.v0; service PackageService { - rpc Prepare (stream PrepareRequest) returns (stream PrepareResponse); - rpc Build (BuildRequest) returns (stream BuildResponse); + rpc Prepare (stream PackagePrepareRequest) returns (stream PackagePrepareResponse); + rpc Build (PackageBuildRequest) returns (stream PackageBuildResponse); } -enum Status { - CREATED = 0; - COMPLETED = 1; - FAILED = 2; -} - -message PrepareRequest { +message PackagePrepareRequest { bytes source_data = 1; string source_hash = 2; string source_name = 3; string source_signature = 4; } -message PrepareResponse { - string source_log = 1; - int32 source_id = 2; +message PackagePrepareResponse { + bytes log_output = 1; +} + +message PrepareBuildPackage { + string hash = 1; + string name = 2; } -message BuildRequest { - repeated string build_deps = 1; - repeated string install_deps = 2; - string build_phase = 3; - string install_phase = 4; - int32 source_id = 5; +message PackageBuildRequest { + bool build_sandbox = 1; + map build_environment = 2; + repeated PrepareBuildPackage build_packages = 3; + string build_script = 4; + string source_hash = 5; + string source_name = 6; } -message BuildResponse { - bool is_archive = 1; - bytes package_data = 2; - string package_log = 3; +message PackageBuildResponse { + bytes log_output = 1; } diff --git a/api/v0/store/store.proto b/api/v0/store/store.proto new file mode 100644 index 00000000..ec990c24 --- /dev/null +++ b/api/v0/store/store.proto @@ -0,0 +1,28 @@ +syntax = "proto3"; + +package vorpal.store.v0; + +service StoreService { + rpc Fetch (StorePath) returns (stream StoreFetchResponse); + rpc Path (StorePath) returns (StorePathResponse); +} + +enum StorePathKind { + UNKNOWN = 0; + SOURCE = 1; + PACKAGE = 2; +} + +message StorePath { + StorePathKind kind = 1; + string hash = 2; + string name = 3; +} + +message StoreFetchResponse { + bytes data = 1; +} + +message StorePathResponse { + string uri = 1; +} diff --git a/build.rs b/build.rs index 902900bf..701bac89 100644 --- a/build.rs +++ b/build.rs @@ -1,6 +1,10 @@ fn main() -> Result<(), Box> { tonic_build::configure().compile( - &["command/command.proto", "package/package.proto"], + &[ + "config/config.proto", + "package/package.proto", + "store/store.proto", + ], &["api/v0"], )?; Ok(()) diff --git a/example/rust/.gitignore b/example/rust/.gitignore deleted file mode 100644 index ea8c4bf7..00000000 --- a/example/rust/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/example/rust/Cargo.lock b/example/rust/Cargo.lock deleted file mode 100644 index aa340a72..00000000 --- a/example/rust/Cargo.lock +++ /dev/null @@ -1,3225 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "anstream" -version = "0.6.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" - -[[package]] -name = "anstyle-parse" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - -[[package]] -name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "async-compression" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" -dependencies = [ - "brotli", - "bzip2", - "deflate64", - "flate2", - "futures-core", - "futures-io", - "memchr", - "pin-project-lite", - "tokio", - "xz2", - "zstd", - "zstd-safe", -] - -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-trait" -version = "0.1.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atomic" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core", - "bitflags 1.3.2", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.29", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "sync_wrapper", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.12", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - -[[package]] -name = "backtrace" -version = "0.3.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "brotli" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bstr" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "cc" -version = "1.0.99" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" -dependencies = [ - "jobserver", - "libc", - "once_cell", -] - -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - -[[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.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" - -[[package]] -name = "colorchoice" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - -[[package]] -name = "cpufeatures" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "deflate64" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ace6c86376be0b6cdcf3fb41882e81d94b31587573d1cfa9d01cd06bba210d" - -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "pem-rfc7468", - "zeroize", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", -] - -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.48.0", -] - -[[package]] -name = "displaydoc" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "either" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" - -[[package]] -name = "encoding_rs" -version = "0.8.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - -[[package]] -name = "fastrand" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" - -[[package]] -name = "filetime" -version = "0.2.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "flate2" -version = "1.0.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" - -[[package]] -name = "futures-executor" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" - -[[package]] -name = "futures-macro" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" - -[[package]] -name = "futures-task" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" - -[[package]] -name = "futures-util" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" - -[[package]] -name = "git2" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" -dependencies = [ - "bitflags 2.5.0", - "libc", - "libgit2-sys", - "log", - "openssl-probe", - "openssl-sys", - "url", -] - -[[package]] -name = "globset" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "globwalk" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" -dependencies = [ - "bitflags 2.5.0", - "ignore", - "walkdir", -] - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.2.6", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.1.0", - "indexmap 2.2.6", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown 0.14.5", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes", - "http 1.1.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" -dependencies = [ - "bytes", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper 0.14.29", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper 1.3.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http 1.1.0", - "http-body 1.0.0", - "hyper 1.3.1", - "pin-project-lite", - "socket2", - "tokio", - "tower", - "tower-service", - "tracing", -] - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "idna" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" -dependencies = [ - "icu_normalizer", - "icu_properties", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "ignore" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" -dependencies = [ - "crossbeam-deque", - "globset", - "log", - "memchr", - "regex-automata", - "same-file", - "walkdir", - "winapi-util", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" -dependencies = [ - "equivalent", - "hashbrown 0.14.5", -] - -[[package]] -name = "infer" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" -dependencies = [ - "cfb", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "jobserver" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin", -] - -[[package]] -name = "libc" -version = "0.2.155" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "libgit2-sys" -version = "0.17.0+1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" -dependencies = [ - "cc", - "libc", - "libssh2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", -] - -[[package]] -name = "libm" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.5.0", - "libc", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libssh2-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "libz-sys" -version = "1.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "litemap" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" - -[[package]] -name = "lzma-sys" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "multimap" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" - -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[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 = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "openssl" -version = "0.10.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" -dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.2", - "smallvec", - "windows-targets 0.52.5", -] - -[[package]] -name = "pem-rfc7468" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" -dependencies = [ - "base64ct", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pest" -version = "2.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" -dependencies = [ - "memchr", - "thiserror", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" -dependencies = [ - "once_cell", - "pest", - "sha2", -] - -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.2.6", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs1" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" -dependencies = [ - "der", - "pkcs8", - "spki", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "prettyplease" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.85" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "process-stream" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3393bf8403a4ca728aafcc4b7fd899c1db520c47d9273f2ab7d69e86d67c3390" -dependencies = [ - "async-stream", - "async-trait", - "futures", - "tap", - "tokio", - "tokio-stream", -] - -[[package]] -name = "prost" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-build" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" -dependencies = [ - "bytes", - "heck", - "itertools", - "log", - "multimap", - "once_cell", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn", - "tempfile", -] - -[[package]] -name = "prost-derive" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "prost-types" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" -dependencies = [ - "prost", -] - -[[package]] -name = "quote" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" -dependencies = [ - "bitflags 2.5.0", -] - -[[package]] -name = "redox_users" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" -dependencies = [ - "getrandom", - "libredox", - "thiserror", -] - -[[package]] -name = "regex" -version = "1.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "reqwest" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.0", - "http-body-util", - "hyper 1.3.1", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "rsa" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" -dependencies = [ - "const-oid", - "digest", - "num-bigint-dig", - "num-integer", - "num-traits", - "pkcs1", - "pkcs8", - "rand_core", - "sha2", - "signature", - "spki", - "subtle", - "zeroize", -] - -[[package]] -name = "rusqlite" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" -dependencies = [ - "bitflags 2.5.0", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustix" -version = "0.38.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" -dependencies = [ - "bitflags 2.5.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustls-pemfile" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" -dependencies = [ - "base64 0.22.1", - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" - -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" -dependencies = [ - "bitflags 2.5.0", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.203" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha256" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18278f6a914fa3070aa316493f7d2ddfb9ac86ebc06fa3b83bffda487e9065b0" -dependencies = [ - "async-trait", - "bytes", - "hex", - "sha2", - "tokio", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "digest", - "rand_core", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - -[[package]] -name = "syn" -version = "2.0.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "tera" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee" -dependencies = [ - "globwalk", - "lazy_static", - "pest", - "pest_derive", - "regex", - "serde", - "serde_json", - "unic-segment", -] - -[[package]] -name = "thiserror" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2", - "tokio-macros", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-io-timeout" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b74022ada614a1b4834de765f9bb43877f910cc8ce4be40e89042c9223a8bf" -dependencies = [ - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-macros" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-stream" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-tar" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5714c010ca3e5c27114c1cdeb9d14641ace49874aa5626d7149e47aedace75" -dependencies = [ - "filetime", - "futures-core", - "libc", - "redox_syscall 0.3.5", - "tokio", - "tokio-stream", - "xattr", -] - -[[package]] -name = "tokio-util" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tonic" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76c4eb7a4e9ef9d4763600161f12f5070b92a578e1b634db88a6887844c91a13" -dependencies = [ - "async-stream", - "async-trait", - "axum", - "base64 0.21.7", - "bytes", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "hyper 0.14.29", - "hyper-timeout", - "percent-encoding", - "pin-project", - "prost", - "tokio", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-build" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4ef6dd70a610078cb4e338a0f79d06bc759ff1b22d2120c2ff02ae264ba9c2" -dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "quote", - "syn", -] - -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "indexmap 1.9.3", - "pin-project", - "pin-project-lite", - "rand", - "slab", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "ucd-trie" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" -dependencies = [ - "unic-ucd-segment", -] - -[[package]] -name = "unic-ucd-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "url" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" -dependencies = [ - "atomic", - "getrandom", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "vorpal" -version = "0.1.0" -dependencies = [ - "anyhow", - "async-compression", - "clap", - "dirs", - "flate2", - "futures", - "futures-util", - "git2", - "hex", - "infer", - "process-stream", - "prost", - "rand", - "reqwest", - "rsa", - "rusqlite", - "sha256", - "tera", - "tokio", - "tokio-stream", - "tokio-tar", - "tonic", - "tonic-build", - "tracing", - "tracing-subscriber", - "url", - "uuid", - "walkdir", -] - -[[package]] -name = "vorpal-example" -version = "0.1.0" -dependencies = [ - "anyhow", - "tokio", - "tokio-stream", - "vorpal", -] - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "web-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[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.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" -dependencies = [ - "windows-sys 0.52.0", -] - -[[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.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.5", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" -dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", - "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" - -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - -[[package]] -name = "xattr" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" -dependencies = [ - "libc", - "linux-raw-sys", - "rustix", -] - -[[package]] -name = "xz2" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" -dependencies = [ - "lzma-sys", -] - -[[package]] -name = "yoke" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.7.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zerofrom" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zerovec" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zstd" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.10+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/example/rust/Cargo.toml b/example/rust/Cargo.toml deleted file mode 100644 index 2d51fffd..00000000 --- a/example/rust/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -edition = "2021" -name = "vorpal-example" -version = "0.1.0" - -[[bin]] -name = "vorpal" -path = "vorpal.rs" - -[dependencies] -anyhow = "1" -tokio = { version = "1" } -tokio-stream = "0" -vorpal = { path = "../../." } diff --git a/example/rust/src/main.rs b/example/rust/src/main.rs deleted file mode 100644 index e7a11a96..00000000 --- a/example/rust/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -} diff --git a/example/rust/vorpal.rs b/example/rust/vorpal.rs deleted file mode 100644 index 18f2af64..00000000 --- a/example/rust/vorpal.rs +++ /dev/null @@ -1,80 +0,0 @@ -use anyhow::Result; -use std::env; -use tokio_stream::StreamExt; -use vorpal::api::command_service_client::CommandServiceClient; -use vorpal::api::{PackageRequest, PackageSource, PackageSourceKind}; - -#[tokio::main] -pub async fn main() -> Result<(), anyhow::Error> { - let mut client = CommandServiceClient::connect("http://[::1]:15323").await?; - - let coreutils = client - .package(PackageRequest { - build_deps: Vec::new(), - build_phase: r#" - cd coreutils-9.5 - test -f configure || ./bootstrap - ./configure --prefix=$OUTPUT - make - "# - .to_string(), - install_phase: "make install".to_string(), - install_deps: Vec::new(), - name: "coreutils".to_string(), - source: Some(PackageSource { - hash: Some( - "af6d643afd6241ec35c7781b7f999b97a66c84bea4710ad2bb15e75a5caf11b4".to_string(), - ), - ignore_paths: vec![], - kind: PackageSourceKind::Http.into(), - uri: "https://ftp.gnu.org/gnu/coreutils/coreutils-9.5.tar.gz".to_string(), - }), - }) - .await?; - - let mut stream = coreutils.into_inner(); - while let Some(package_response) = stream.next().await { - let response = package_response?; - if !response.package_log.is_empty() { - println!("{}", response.package_log); - } - } - - let example = client - .package(PackageRequest { - build_deps: Vec::new(), - build_phase: r#" - mkdir -p $OUTPUT/bin - touch $OUTPUT/bin/example.txt - "# - .to_string(), - install_phase: r#" - echo "Hello, World!" >> $OUTPUT/bin/example.txt - cat $OUTPUT/bin/example.txt - "# - .to_string(), - install_deps: Vec::new(), - name: "example".to_string(), - source: Some(PackageSource { - hash: None, - ignore_paths: vec![ - ".git".to_string(), - ".gitignore".to_string(), - "target".to_string(), - ], - kind: PackageSourceKind::Local.into(), - uri: env::current_dir()?.to_string_lossy().to_string(), - }), - }) - .await?; - - let mut stream = example.into_inner(); - while let Some(package_response) = stream.next().await { - let response = package_response?; - if !response.package_log.is_empty() { - println!("{}", response.package_log); - } - } - - Ok(()) -} diff --git a/flake.lock b/flake.lock index 3faa66a5..0073abdc 100644 --- a/flake.lock +++ b/flake.lock @@ -17,31 +17,13 @@ "type": "indirect" } }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1705309234, - "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1718318537, - "narHash": "sha256-4Zu0RYRcAY/VWuu6awwq4opuiD//ahpc2aFHg2CWqFY=", + "lastModified": 1718895438, + "narHash": "sha256-k3JqJrkdoYwE3fHE6xGDY676AYmyh4U2Zw+0Bwe5DLU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e9ee548d90ff586a6471b4ae80ae9cfcbceb3420", + "rev": "d603719ec6e294f034936c0d0dc06f689d91b6c3", "type": "github" }, "original": { @@ -88,17 +70,16 @@ }, "rust-overlay": { "inputs": { - "flake-utils": "flake-utils", "nixpkgs": [ "nixpkgs" ] }, "locked": { - "lastModified": 1718417877, - "narHash": "sha256-s8QrTANEtY6UxzfkcBfoN93bgW9aCRIq54LPRVNu/4c=", + "lastModified": 1718936281, + "narHash": "sha256-jslEDCVFoRcNilJT0xYGSxqMjOe+USnLknpHIAZJ02A=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "7c2d603cb67c974ef8c5cfee1150060dbb299e04", + "rev": "c9a793a5278f711a59fe77b9bf54b215667022c6", "type": "github" }, "original": { @@ -106,21 +87,6 @@ "repo": "rust-overlay", "type": "github" } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 2ab77c8f..5681c2f2 100644 --- a/flake.nix +++ b/flake.nix @@ -50,7 +50,7 @@ packages = { default = buildRustPackage { buildInputs = [openssl] ++ lib.optionals pkgs.stdenv.isDarwin [CoreServices SystemConfiguration Security]; - cargoSha256 = "sha256-xUz6VQlnZlcDYf/I2yBVLaRc36dc2Lz/dWL4flI1480="; + cargoSha256 = "sha256-cXNAFYmmsc9S/IjfkQEW0P1Dirx36TYT5qZgWYgyoUY="; nativeBuildInputs = [pkg-config protobuf]; pname = "vorpal"; src = ./.; @@ -60,8 +60,8 @@ process-compose.start = { settings.processes = { - proxy-server.command = "${config.apps.default.program} services proxy"; - build-server.command = "${config.apps.default.program} services build"; + agent-server.command = "${config.apps.default.program} services agent"; + worker-server.command = "${config.apps.default.program} services worker"; }; }; }; diff --git a/justfile b/justfile index 3ca937dd..0b2a5aa2 100644 --- a/justfile +++ b/justfile @@ -18,6 +18,10 @@ clean: rm -rf $HOME/.vorpal rm -rf vorpal +# clean store cache +clean-cache: + rm -rf $HOME/.vorpal/store + # format code (cargo & nix) format: cargo fmt --check --package vorpal --verbose diff --git a/src/bin/main.rs b/src/bin/main.rs index bb339d5a..11518d5d 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -2,7 +2,7 @@ use anyhow::Result; use clap::{Parser, Subcommand}; use tracing::Level; use vorpal::notary; -use vorpal::service::{build, proxy}; +use vorpal::service::{agent, worker}; #[derive(Parser)] #[command(author, version, about, long_about = None)] @@ -31,12 +31,12 @@ pub enum Keys { #[derive(Subcommand)] enum Services { - Proxy { + Agent { #[clap(default_value = "15323", long, short)] port: u16, }, - Build { + Worker { #[clap(default_value = "23151", long, short)] port: u16, }, @@ -61,8 +61,8 @@ async fn main() -> Result<(), anyhow::Error> { Keys::Generate {} => notary::generate_keys().await, }, Command::Services(service) => match service { - Services::Build { port } => build::start(*port).await, - Services::Proxy { port } => proxy::start(*port).await, + Services::Agent { port } => agent::start(*port).await, + Services::Worker { port } => worker::start(*port).await, }, } } diff --git a/src/database/mod.rs b/src/database/mod.rs deleted file mode 100644 index 5efaba84..00000000 --- a/src/database/mod.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::api::Status; -use crate::store::paths; -use rusqlite::{Connection, Result}; -use std::path::Path; -use tracing::info; -use uuid::Uuid; - -pub struct Source { - pub id: i32, - pub hash: String, - pub name: String, -} - -pub struct Build { - pub build_phase: String, - pub error: Option, // populated on failed - pub id: Uuid, - pub ignore_paths: Vec, - pub install_phase: String, - pub package_id: Option, // populated on completed - pub source_id: Uuid, - pub status: Status, -} - -pub fn connect>(path: P) -> Result { - Connection::open(path) -} - -pub fn init() -> Result<(), anyhow::Error> { - let db_path = paths::get_database_path(); - let db = connect(&db_path)?; - - db.execute( - "CREATE TABLE IF NOT EXISTS source ( - id INTEGER PRIMARY KEY, - hash TEXT NOT NULL, - name TEXT NOT NULL - )", - [], - )?; - - info!("database: {:?}", db_path.display()); - - if let Err(e) = db.close() { - return Err(e.1.into()); - } - - Ok(()) -} - -pub fn insert_source(conn: &Connection, hash: &str, name: &str) -> Result { - conn.execute( - "INSERT INTO source (hash, name) VALUES (?1, ?2)", - [hash, name], - ) -} - -pub fn find_source_by_id(conn: &Connection, id: i32) -> Result { - let mut stmt = conn.prepare("SELECT * FROM source WHERE id = ?")?; - let mut rows = stmt.query([id])?; - - let row = rows - .next()? - .ok_or_else(|| rusqlite::Error::QueryReturnedNoRows)?; - - Ok(Source { - id: row.get(0)?, - hash: row.get(1)?, - name: row.get(2)?, - }) -} - -pub fn find_source(conn: &Connection, hash: &str, name: &str) -> Result { - let mut stmt = conn.prepare("SELECT * FROM source WHERE hash = ? AND name = ?")?; - let mut rows = stmt.query([hash, name])?; - - let row = rows - .next()? - .ok_or_else(|| rusqlite::Error::QueryReturnedNoRows)?; - - Ok(Source { - id: row.get(0)?, - hash: row.get(1)?, - name: row.get(2)?, - }) -} diff --git a/src/lib.rs b/src/lib.rs index acc4dcf8..d3c56b79 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,8 @@ pub mod api { - tonic::include_proto!("vorpal.command.v0"); + tonic::include_proto!("vorpal.config.v0"); tonic::include_proto!("vorpal.package.v0"); + tonic::include_proto!("vorpal.store.v0"); } -pub mod database; pub mod notary; pub mod service; pub mod store; diff --git a/src/service/proxy/mod.rs b/src/service/agent/mod.rs similarity index 74% rename from src/service/proxy/mod.rs rename to src/service/agent/mod.rs index 3c8e45e7..f1bec45c 100644 --- a/src/service/proxy/mod.rs +++ b/src/service/agent/mod.rs @@ -1,4 +1,4 @@ -use crate::api::command_service_server::CommandServiceServer; +use crate::api::config_service_server::ConfigServiceServer; use crate::notary; use crate::store; use tonic::transport::Server; @@ -17,7 +17,7 @@ pub async fn start(port: u16) -> Result<(), anyhow::Error> { info!("service listening on: {}", addr); Server::builder() - .add_service(CommandServiceServer::new(service::Proxy::default())) + .add_service(ConfigServiceServer::new(service::Agent::default())) .serve(addr) .await?; diff --git a/src/service/agent/package.rs b/src/service/agent/package.rs new file mode 100644 index 00000000..ea7acc03 --- /dev/null +++ b/src/service/agent/package.rs @@ -0,0 +1,812 @@ +use crate::api::package_service_client::PackageServiceClient; +use crate::api::store_service_client::StoreServiceClient; +use crate::api::{ + ConfigPackageBuild, ConfigPackageOutput, ConfigPackageRequest, ConfigPackageResponse, + ConfigPackageSource, ConfigPackageSourceKind, PackageBuildRequest, PackagePrepareRequest, + PrepareBuildPackage, StorePath, StorePathKind, +}; +use crate::notary; +use crate::store::{archives, hashes, paths, temps}; +use anyhow::Result; +use async_compression::tokio::bufread::{BzDecoder, GzipDecoder, XzDecoder}; +use git2::build::RepoBuilder; +use git2::{Cred, RemoteCallbacks}; +use reqwest; +use std::path::{Path, PathBuf}; +use tokio::fs; +use tokio::fs::{copy, create_dir_all, read, remove_file, write, File}; +use tokio::io::AsyncWriteExt; +use tokio::sync::mpsc::Sender; +use tokio::task; +use tokio_stream; +use tokio_tar::Archive; +use tonic::{Request, Status}; +use tracing::info; +use url::Url; + +pub async fn run( + tx: &Sender>, + request: Request, +) -> Result<(), anyhow::Error> { + let config = request.into_inner(); + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package config name: {}", config.name).into_bytes(), + package_output: None, + })) + .await?; + + let config_build = match config.build { + None => anyhow::bail!("package build config is required"), + Some(build) => build, + }; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package build config: {:?}", config_build).into_bytes(), + package_output: None, + })) + .await?; + + let config_source = match config.source { + None => anyhow::bail!("package source config is required"), + Some(source) => source, + }; + + let mut config_source_hash = config_source.hash.clone().unwrap_or_default(); + + match config_source.kind() { + ConfigPackageSourceKind::Unknown => anyhow::bail!("package source kind is unknown"), + ConfigPackageSourceKind::Git => {} + ConfigPackageSourceKind::Http => {} + ConfigPackageSourceKind::Local => { + if config_source_hash.is_empty() { + let source_path = Path::new(&config_source.uri).canonicalize()?; + let (source_hash, _) = validate_source(tx, &source_path, &config_source).await?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package source hash computed: {}", source_hash) + .into_bytes(), + package_output: None, + })) + .await?; + + config_source_hash = source_hash; + } + } + }; + + if config_source_hash.is_empty() { + anyhow::bail!("package source hash is required"); + } + + // check package_path exists in agent (local) cache + + let package_path = paths::get_package_path(&config.name, &config_source_hash); + + if package_path.exists() { + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package cache: {}", package_path.display()).into_bytes(), + package_output: Some(ConfigPackageOutput { + hash: config_source_hash, + name: config.name, + }), + })) + .await?; + + return Ok(()); + } + + // check package tar exists in agent (local) cache + + let package_tar_path = paths::get_package_tar_path(&config.name, &config_source_hash); + + if !package_path.exists() && package_tar_path.exists() { + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package tar cache: {}", package_tar_path.display()) + .into_bytes(), + package_output: None, + })) + .await?; + + fs::create_dir_all(&package_path).await?; + + archives::unpack_tar_gz(&package_path, &package_tar_path).await?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] package tar cache unpacked: {}", + package_path.display() + ) + .into_bytes(), + package_output: Some(ConfigPackageOutput { + hash: config_source_hash, + name: config.name, + }), + })) + .await?; + + return Ok(()); + } + + // check if package exists in worker (remote) cache + + let mut store_service = StoreServiceClient::connect("http://[::1]:23151").await?; + + let store_package_path = StorePath { + kind: StorePathKind::Package as i32, + name: config.name.clone(), + hash: config_source_hash.clone(), + }; + + if let Ok(res) = store_service.path(store_package_path.clone()).await { + let store_path = res.into_inner(); + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package tar cache (worker): {}", store_path.uri) + .into_bytes(), + package_output: None, + })) + .await?; + + if let Ok(res) = store_service.fetch(store_package_path.clone()).await { + let mut stream = res.into_inner(); + let mut stream_data = Vec::new(); + + while let Some(chunk) = stream.message().await? { + if !chunk.data.is_empty() { + stream_data.extend_from_slice(&chunk.data); + } + } + + if stream_data.is_empty() { + anyhow::bail!("failed to fetch package tar"); + } + + let mut package_tar = File::create(&package_tar_path).await?; + if let Err(e) = package_tar.write(&stream_data).await { + anyhow::bail!(e.to_string()); + } + + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] package tar cache (worker): {}", + package_tar_path.display() + ) + .into_bytes(), + package_output: None, + })) + .await?; + + fs::create_dir_all(&package_path).await?; + + archives::unpack_tar_gz(&package_path, &package_tar_path).await?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] package tar cache unpacked (worker): {}", + package_path.display() + ) + .into_bytes(), + package_output: Some(ConfigPackageOutput { + hash: config_source_hash, + name: config.name, + }), + })) + .await?; + + return Ok(()); + } + } + + // check if package source exists in worker cache + + let store_package_source_path = StorePath { + kind: StorePathKind::Source as i32, + name: config.name.clone(), + hash: config_source_hash.clone(), + }; + + if let Ok(res) = store_service.path(store_package_source_path.clone()).await { + let store_path = res.into_inner(); + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package source cache (worker): {}", store_path.uri) + .into_bytes(), + package_output: None, + })) + .await?; + + stream_build( + tx, + &config_build, + &config.name, + &config_source_hash, + &store_package_path, + &mut store_service, + ) + .await?; + + return Ok(()); + } + + let package_source_tar_path = + paths::get_package_source_tar_path(&config.name, &config_source_hash); + + if package_source_tar_path.exists() { + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] package source tar cache: {}", + package_source_tar_path.display() + ) + .into_bytes(), + package_output: None, + })) + .await?; + + stream_prepare( + tx, + &config.name, + &config_source_hash, + &package_source_tar_path, + ) + .await?; + + stream_build( + tx, + &config_build, + &config.name, + &config_source_hash, + &store_package_path, + &mut store_service, + ) + .await?; + + return Ok(()); + } + + let source_hash = source_prepare( + tx, + &config.name, + &config_source, + &config_source_hash, + &package_source_tar_path, + ) + .await?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] package source tar: {}", + package_source_tar_path.display() + ) + .into_bytes(), + package_output: None, + })) + .await?; + + // check if package source exists in worker cache (same as agent) + + if let Ok(res) = store_service.path(store_package_source_path).await { + let store_path = res.into_inner(); + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package source cache (worker): {}", store_path.uri) + .into_bytes(), + package_output: None, + })) + .await?; + + stream_build( + tx, + &config_build, + &config.name, + &config_source_hash, + &store_package_path, + &mut store_service, + ) + .await?; + + return Ok(()); + } + + stream_prepare(tx, &config.name, &source_hash, &package_source_tar_path).await?; + + stream_build( + tx, + &config_build, + &config.name, + &source_hash, + &store_package_path, + &mut store_service, + ) + .await?; + + Ok(()) +} + +async fn validate_source( + tx: &Sender>, + source_path: &Path, + source: &ConfigPackageSource, +) -> Result<(String, Vec), anyhow::Error> { + let workdir_files = paths::get_file_paths(source_path, &source.ignore_paths)?; + + if workdir_files.is_empty() { + return Err(anyhow::anyhow!("no source files found")); + } + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package source files: {}", workdir_files.len()).into_bytes(), + package_output: None, + })) + .await?; + + let workdir_files_hashes = hashes::get_files(&workdir_files)?; + let workdir_hash = hashes::get_source(&workdir_files_hashes)?; + + if workdir_hash.is_empty() { + return Err(anyhow::anyhow!("failed to get source hash")); + } + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package source hash computed: {}", workdir_hash).into_bytes(), + package_output: None, + })) + .await?; + + if let Some(request_hash) = &source.hash { + if &workdir_hash != request_hash { + let message = &format!( + "[agent] hash mismatch: {} != {}", + request_hash, workdir_hash + ); + + tx.send(Ok(ConfigPackageResponse { + log_output: message.clone().into_bytes(), + package_output: None, + })) + .await?; + + return Err(anyhow::anyhow!("{}", message)); + } + } + + Ok((workdir_hash, workdir_files)) +} + +async fn stream_build( + tx: &Sender>, + build: &ConfigPackageBuild, + name: &str, + source_hash: &str, + store_package_path: &StorePath, + store_service: &mut StoreServiceClient, +) -> Result<(), anyhow::Error> { + let mut build_packages = vec![]; + + for output in build.packages.clone().into_iter() { + build_packages.push(PrepareBuildPackage { + hash: output.hash, + name: output.name, + }); + } + + let build_config = PackageBuildRequest { + build_environment: build.environment.clone(), + build_sandbox: build.sandbox, + build_packages, + build_script: build.script.to_string(), + source_name: name.to_string(), + source_hash: source_hash.to_string(), + }; + + let package_path = paths::get_package_path(name, source_hash); + + let mut package_service = PackageServiceClient::connect("http://[::1]:23151").await?; + + if let Ok(res) = package_service.build(build_config).await { + let mut build_stream = res.into_inner(); + + while let Some(chunk) = build_stream.message().await? { + if !chunk.log_output.is_empty() { + tx.send(Ok(ConfigPackageResponse { + log_output: chunk.log_output, + package_output: None, + })) + .await?; + } + } + + let package_tar_path = paths::get_package_tar_path(name, source_hash); + + if !package_tar_path.exists() { + let fetch_response = store_service.fetch(store_package_path.clone()).await?; + let mut fetch_stream = fetch_response.into_inner(); + let mut fetch_stream_data = Vec::new(); + + while let Some(chunk) = fetch_stream.message().await? { + if !chunk.data.is_empty() { + fetch_stream_data.extend_from_slice(&chunk.data); + } + } + + let mut package_tar = File::create(&package_tar_path).await?; + if let Err(e) = package_tar.write(&fetch_stream_data).await { + anyhow::bail!(e.to_string()); + } + + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] package tar fetched (worker): {}", + package_tar_path.display() + ) + .into_bytes(), + package_output: None, + })) + .await?; + + fs::create_dir_all(package_path.clone()).await?; + + archives::unpack_tar_gz(&package_path, &package_tar_path).await?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package tar unpacked: {}", package_path.display()) + .into_bytes(), + package_output: Some(ConfigPackageOutput { + hash: source_hash.to_string(), + name: name.to_string(), + }), + })) + .await?; + } + + // TODO: check if build failed + } + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package output: {}", package_path.display()).into_bytes(), + package_output: Some(ConfigPackageOutput { + hash: source_hash.to_string(), + name: name.to_string(), + }), + })) + .await?; + + Ok(()) +} + +async fn stream_prepare( + tx: &Sender>, + name: &str, + source_hash: &str, + source_tar_path: &Path, +) -> Result<(), anyhow::Error> { + let data = read(&source_tar_path).await?; + + let signature = notary::sign(&data).await?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package source tar signature: {}", signature).into_bytes(), + package_output: None, + })) + .await?; + + let mut request_chunks = vec![]; + let request_chunks_size = 8192; // default grpc limit + + for chunk in data.chunks(request_chunks_size) { + request_chunks.push(PackagePrepareRequest { + source_data: chunk.to_vec(), + source_name: name.to_string(), + source_hash: source_hash.to_string(), + source_signature: signature.to_string(), + }); + } + + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] package source chunks send: {}", + request_chunks.len() + ) + .into_bytes(), + package_output: None, + })) + .await?; + + let mut client = PackageServiceClient::connect("http://[::1]:23151").await?; + let response = client.prepare(tokio_stream::iter(request_chunks)).await?; + let mut stream = response.into_inner(); + + while let Some(chunk) = stream.message().await? { + if !chunk.log_output.is_empty() { + tx.send(Ok(ConfigPackageResponse { + log_output: chunk.log_output, + package_output: None, + })) + .await?; + } + } + + Ok(()) +} + +async fn source_prepare( + tx: &Sender>, + name: &str, + source: &ConfigPackageSource, + source_hash: &str, + source_tar_path: &PathBuf, +) -> Result { + let temp_source_path = temps::create_dir().await?.canonicalize()?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing package source: {:?}", &temp_source_path) + .into_bytes(), + package_output: None, + })) + .await?; + + if source.kind == ConfigPackageSourceKind::Git as i32 { + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing git source: {:?}", &source.uri).into_bytes(), + package_output: None, + })) + .await?; + + let source_uri = source.uri.clone(); + let package_clone_path = temp_source_path.clone(); + + let result = task::spawn_blocking(move || { + let mut builder = RepoBuilder::new(); + let mut fetch_options = git2::FetchOptions::new(); + let mut remote_callbacks = RemoteCallbacks::new(); + + remote_callbacks.transfer_progress(|stats| { + info!( + "total: {}, indexed: {}, received: {}, local: {}, total deltas: {}, indexed deltas: {}", + stats.total_objects(), + stats.indexed_objects(), + stats.received_objects(), + stats.local_objects(), + stats.total_deltas(), + stats.indexed_deltas() + ); + true + }); + + fetch_options.depth(1); + + if source_uri.starts_with("git://") { + remote_callbacks.credentials(|_url, username_from_url, _allowed_types| { + Cred::ssh_key( + username_from_url.unwrap(), + None, + Path::new(&format!( + "{}/.ssh/id_rsa", + dirs::home_dir().unwrap().display() + )), + None, + ) + }); + + } + + fetch_options.remote_callbacks(remote_callbacks); + + builder.fetch_options(fetch_options); + + let repo = builder.clone(&source_uri, &package_clone_path)?; + let head = repo.head()?; + let head_commit = repo.find_commit(head.target().unwrap())?; + + Ok::(head_commit.id().to_string()) + }) + .await? + .map_err(|e| anyhow::anyhow!("Failed to clone git source: {}", e))?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing git source commit: {:?}", &result).into_bytes(), + package_output: None, + })) + .await?; + } + + if source.kind == ConfigPackageSourceKind::Http as i32 { + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing download source: {:?}", &source.uri) + .into_bytes(), + package_output: None, + })) + .await?; + + let url = Url::parse(&source.uri)?; + + if url.scheme() != "http" && url.scheme() != "https" { + return Err(anyhow::anyhow!("invalid HTTP source URL")); + } + + let response = reqwest::get(url.as_str()).await?.bytes().await?; + let response_bytes = response.as_ref(); + + if let Some(kind) = infer::get(response_bytes) { + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing download source kind: {:?}", kind) + .into_bytes(), + package_output: None, + })) + .await?; + + if let "application/gzip" = kind.mime_type() { + let gz_decoder = GzipDecoder::new(response_bytes); + let mut archive = Archive::new(gz_decoder); + archive.unpack(&temp_source_path).await?; + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] preparing download gzip source: {:?}", + temp_source_path + ) + .into_bytes(), + package_output: None, + })) + .await?; + } else if let "application/x-bzip2" = kind.mime_type() { + let bz_decoder = BzDecoder::new(response_bytes); + let mut archive = Archive::new(bz_decoder); + archive.unpack(&temp_source_path).await?; + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing bzip2 source: {:?}", temp_source_path) + .into_bytes(), + package_output: None, + })) + .await?; + } else if let "application/x-xz" = kind.mime_type() { + let xz_decoder = XzDecoder::new(response_bytes); + let mut archive = Archive::new(xz_decoder); + archive.unpack(&temp_source_path).await?; + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing xz source: {:?}", temp_source_path) + .into_bytes(), + package_output: None, + })) + .await?; + } else if let "application/zip" = kind.mime_type() { + let temp_zip_path = temps::create_file("zip").await?; + write(&temp_zip_path, response_bytes).await?; + archives::unpack_zip(&temp_zip_path, &temp_source_path).await?; + remove_file(&temp_zip_path).await?; + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing zip source: {:?}", temp_source_path) + .into_bytes(), + package_output: None, + })) + .await?; + } else { + let file_name = url.path_segments().unwrap().last(); + let file = file_name.unwrap(); + write(&file, response_bytes).await?; + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing source file: {:?}", file).into_bytes(), + package_output: None, + })) + .await?; + } + } + } + + let source_path = paths::get_package_source_path(name, source_hash); + + if source.kind == ConfigPackageSourceKind::Local as i32 { + let source_path = Path::new(&source.uri).canonicalize()?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing source path: {:?}", source_path).into_bytes(), + package_output: None, + })) + .await?; + + if let Ok(Some(source_kind)) = infer::get_from_path(&source_path) { + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing source kind: {:?}", source_kind) + .into_bytes(), + package_output: None, + })) + .await?; + + if source_kind.mime_type() == "application/gzip" { + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] preparing packed source: {:?}", temp_source_path) + .into_bytes(), + package_output: None, + })) + .await?; + + archives::unpack_tar_gz(&temp_source_path, &source_path).await?; + } + } + + if source_path.is_file() { + let dest = temp_source_path.join(source_path.file_name().unwrap()); + copy(&source_path, &dest).await?; + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] preparing source file: {:?} -> {:?}", + source_path.display(), + dest.display() + ) + .into_bytes(), + package_output: None, + })) + .await?; + } + + if source_path.is_dir() { + let file_paths = paths::get_file_paths(&source_path, &source.ignore_paths)?; + + if file_paths.is_empty() { + return Err(anyhow::anyhow!("No source files found")); + } + + for src in &file_paths { + if src.is_dir() { + let dest = temp_source_path.join(src.strip_prefix(&source_path)?); + create_dir_all(dest).await?; + continue; + } + + let dest = temp_source_path.join(src.strip_prefix(&source_path)?); + + copy(src, &dest).await?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] preparing source file: {:?} -> {:?}", + source_path.display(), + dest.display() + ) + .into_bytes(), + package_output: None, + })) + .await?; + } + } + } + + // At this point, any source URI should be a local file path + + let (source_hash, _) = validate_source(tx, &temp_source_path, source).await?; + + create_dir_all(&source_path).await?; + + paths::copy_files(&temp_source_path, &source_path).await?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!("[agent] package source: {}", source_path.display()).into_bytes(), + package_output: None, + })) + .await?; + + let source_path_files = paths::get_file_paths(&source_path, &Vec::<&str>::new())?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] package source tar packing: {}", + source_tar_path.display() + ) + .into_bytes(), + package_output: None, + })) + .await?; + + archives::compress_tar_gz(&source_path, &source_path_files, source_tar_path).await?; + + tx.send(Ok(ConfigPackageResponse { + log_output: format!( + "[agent] package source tar packed: {}", + source_tar_path.display() + ) + .into_bytes(), + package_output: None, + })) + .await?; + + Ok(source_hash) +} diff --git a/src/service/agent/service.rs b/src/service/agent/service.rs new file mode 100644 index 00000000..5a34430f --- /dev/null +++ b/src/service/agent/service.rs @@ -0,0 +1,27 @@ +use crate::api::config_service_server::ConfigService; +use crate::api::{ConfigPackageRequest, ConfigPackageResponse}; +use crate::service::agent::package; +use anyhow::Result; +use tokio::sync::mpsc; +use tokio_stream; +use tokio_stream::wrappers::ReceiverStream; +use tonic::{Request, Response, Status}; + +#[derive(Debug, Default)] +pub struct Agent {} + +#[tonic::async_trait] +impl ConfigService for Agent { + type PackageStream = ReceiverStream>; + + async fn package( + &self, + request: Request, + ) -> Result, Status> { + let (tx, rx) = mpsc::channel(4); + + tokio::spawn(async move { package::run(&tx, request).await }); + + Ok(Response::new(ReceiverStream::new(rx))) + } +} diff --git a/src/service/build/run_build.rs b/src/service/build/run_build.rs deleted file mode 100644 index f54b2ec6..00000000 --- a/src/service/build/run_build.rs +++ /dev/null @@ -1,308 +0,0 @@ -use crate::api::{BuildRequest, BuildResponse}; -use crate::database; -use crate::service::build::sandbox_default; -use crate::store::archives; -use crate::store::paths; -use crate::store::temps; -use process_stream::{Process, ProcessExt, StreamExt}; -use std::os::unix::fs::PermissionsExt; -use tera::Tera; -use tokio::fs; -use tokio::sync::mpsc; -use tokio_stream::wrappers::ReceiverStream; -use tonic::{Request, Response, Status}; -use walkdir::WalkDir; - -type BuildStream = ReceiverStream>; - -pub async fn run(request: Request) -> Result, Status> { - let (tx, rx) = mpsc::channel(4); - - tokio::spawn(async move { - let message = request.into_inner(); - - let db_path = paths::get_database_path(); - let db = database::connect(db_path) - .map_err(|e| Status::internal(format!("Failed to connect to database: {:?}", e)))?; - - let source = database::find_source_by_id(&db, message.source_id) - .map_err(|e| Status::internal(format!("Failed to find source by id: {:?}", e)))?; - - let store_path = paths::get_store_path(); - let store_output_path = store_path.join(format!("{}-{}", source.name, source.hash)); - let store_output_tar = store_output_path.with_extension("tar.gz"); - - let response_chunks_size = 8192; // default grpc limit - - if store_output_path.exists() { - tx.send(Ok(BuildResponse { - is_archive: true, - package_data: vec![], - package_log: format!("using cached output: {}", store_output_path.display()), - })) - .await - .unwrap(); - - let package_data = fs::read(&store_output_path) - .await - .map_err(|_| Status::internal("Failed to read cached output"))?; - - for package_chunk in package_data.chunks(response_chunks_size) { - tx.send(Ok(BuildResponse { - is_archive: false, - package_data: package_chunk.to_vec(), - package_log: "".to_string(), - })) - .await - .unwrap(); - } - - return Ok(()); - } - - if store_output_tar.exists() { - tx.send(Ok(BuildResponse { - is_archive: true, - package_data: vec![], - package_log: format!("using cached output: {}", store_output_tar.display()), - })) - .await - .unwrap(); - - let package_data = fs::read(&store_output_tar) - .await - .map_err(|_| Status::internal("Failed to read cached output"))?; - - for chunk in package_data.chunks(response_chunks_size) { - tx.send(Ok(BuildResponse { - is_archive: true, - package_data: chunk.to_vec(), - package_log: "".to_string(), - })) - .await - .unwrap(); - } - - return Ok(()); - } - - let source_tar_path = paths::get_package_source_tar_path(&source.name, &source.hash); - - tx.send(Ok(BuildResponse { - is_archive: false, - package_data: vec![], - package_log: format!("building source: {}", source_tar_path.display()), - })) - .await - .unwrap(); - - let source_temp_dir = temps::create_dir() - .await - .map_err(|_| Status::internal("Failed to create temp dir"))?; - let source_temp_dir_path = source_temp_dir.canonicalize()?; - - if let Err(err) = archives::unpack_tar_gz(&source_temp_dir_path, &source_tar_path).await { - return Err(Status::internal(format!( - "Failed to unpack source tar: {:?}", - err - ))); - } - - let source_temp_vorpal_dir = source_temp_dir_path.join(".vorpal"); - - fs::create_dir(&source_temp_vorpal_dir) - .await - .map_err(|_| Status::internal("Failed to create vorpal temp dir"))?; - - let build_phase_steps = message - .build_phase - .trim() - .split('\n') - .map(|line| line.trim()) - .collect::>() - .join("\n"); - let install_phase_steps = message - .install_phase - .trim() - .split('\n') - .map(|line| line.trim()) - .collect::>() - .join("\n"); - - let automation_script = [ - "#!/bin/bash", - "set -e pipefail", - "echo \"Starting build phase\"", - &build_phase_steps, - "echo \"Finished build phase\"", - "echo \"Starting install phase\"", - &install_phase_steps, - "echo \"Finished install phase\"", - ]; - - let automation_script_data = automation_script.join("\n"); - - tx.send(Ok(BuildResponse { - is_archive: false, - package_data: vec![], - package_log: format!("build script: {}", automation_script_data), - })) - .await - .unwrap(); - - let automation_script_path = source_temp_vorpal_dir.join("automation.sh"); - - fs::write(&automation_script_path, automation_script_data) - .await - .map_err(|_| Status::internal("Failed to write automation script"))?; - - let metadata = fs::metadata(&automation_script_path).await?; - let mut permissions = metadata.permissions(); - - permissions.set_mode(0o755); - - fs::set_permissions(&automation_script_path, permissions) - .await - .map_err(|_| Status::internal("Failed to set automation script permissions"))?; - - let os_type = std::env::consts::OS; - if os_type != "macos" { - return Err(Status::unimplemented("unsupported OS")); - } - - let sandbox_profile_path = source_temp_vorpal_dir.join("sandbox.sb"); - - let mut tera = Tera::default(); - tera.add_raw_template("sandbox_default", sandbox_default::SANDBOX_DEFAULT) - .unwrap(); - - let mut context = tera::Context::new(); - context.insert("tmpdir", source_temp_dir_path.to_str().unwrap()); - let sandbox_profile = tera.render("sandbox_default", &context).unwrap(); - - fs::write(&sandbox_profile_path, sandbox_profile) - .await - .map_err(|_| Status::internal("Failed to write sandbox profile"))?; - - let sandbox_command_args = [ - "-f", - sandbox_profile_path.to_str().unwrap(), - automation_script_path.to_str().unwrap(), - ]; - - tx.send(Ok(BuildResponse { - is_archive: false, - package_data: vec![], - package_log: format!("sandbox command args: {:?}", sandbox_command_args), - })) - .await - .unwrap(); - - let sandbox_output_path = source_temp_vorpal_dir.join("output"); - - tx.send(Ok(BuildResponse { - is_archive: false, - package_data: vec![], - package_log: format!("sandbox output path: {}", sandbox_output_path.display()), - })) - .await - .unwrap(); - - let mut sandbox_command = Process::new("/usr/bin/sandbox-exec"); - sandbox_command.args(sandbox_command_args); - sandbox_command.current_dir(&source_temp_dir_path); - // sandbox_command.env("PATH", "/usr/bin:/bin:/usr/sbin:/sbin"); - sandbox_command.env("OUTPUT", sandbox_output_path.to_str().unwrap()); - - let mut stream = sandbox_command.spawn_and_stream()?; - - while let Some(output) = stream.next().await { - tx.send(Ok(BuildResponse { - is_archive: false, - package_data: vec![], - package_log: format!("sandbox output: {}", output), - })) - .await - .unwrap(); - } - - if sandbox_output_path.is_file() { - fs::copy(&sandbox_output_path, &store_output_path).await?; - } - - if sandbox_output_path.is_dir() { - for entry in WalkDir::new(&sandbox_output_path) { - let entry = entry.map_err(|e| { - Status::internal(format!("Failed to walk sandbox output: {:?}", e)) - })?; - let output_path = entry.path().strip_prefix(&sandbox_output_path).unwrap(); - let output_store_path = store_output_path.join(output_path); - if entry.path().is_dir() { - fs::create_dir_all(&output_store_path) - .await - .map_err(|_| Status::internal("Failed to create sandbox output dir"))?; - } else { - fs::copy(&entry.path(), &output_store_path) - .await - .map_err(|_| Status::internal("Failed to copy sandbox output file"))?; - } - } - - let store_output_files = paths::get_file_paths(&store_output_path, &Vec::<&str>::new()) - .map_err(|_| Status::internal("Failed to get sandbox output files"))?; - - if let Err(err) = archives::compress_tar_gz( - &store_output_path, - &store_output_tar, - &store_output_files, - ) - .await - { - return Err(Status::internal(format!( - "Failed to compress sandbox output: {:?}", - err - ))); - } - } - - fs::remove_dir_all(&source_temp_dir_path).await?; - - let is_archive = store_output_tar.exists(); - let package_data_path = if is_archive { - store_output_tar - } else { - store_output_path - }; - - tx.send(Ok(BuildResponse { - is_archive: false, - package_data: vec![], - package_log: format!("build completed: {}", package_data_path.display()), - })) - .await - .unwrap(); - - let package_data = fs::read(&package_data_path).await?; - - for package_chunk in package_data.chunks(response_chunks_size) { - tx.send(Ok(BuildResponse { - is_archive, - package_data: package_chunk.to_vec(), - package_log: "".to_string(), - })) - .await - .unwrap(); - } - - if let Err(e) = db.close() { - return Err(Status::internal(format!( - "Failed to close database: {:?}", - e.1 - ))); - } - - Ok(()) - }); - - Ok(Response::new(ReceiverStream::new(rx))) -} diff --git a/src/service/build/run_prepare.rs b/src/service/build/run_prepare.rs deleted file mode 100644 index 8562b2d3..00000000 --- a/src/service/build/run_prepare.rs +++ /dev/null @@ -1,187 +0,0 @@ -use crate::api::{PrepareRequest, PrepareResponse}; -use crate::database; -use crate::notary; -use crate::store::archives; -use crate::store::hashes; -use crate::store::paths; -use futures_util::StreamExt; -use rsa::pss::{Signature, VerifyingKey}; -use rsa::sha2::Sha256; -use rsa::signature::Verifier; -use std::convert::TryFrom; -use std::os::unix::fs::PermissionsExt; -use tokio::fs; -use tokio::fs::File; -use tokio::io::AsyncWriteExt; -use tokio::sync::mpsc; -use tokio_stream::wrappers::ReceiverStream; -use tonic::{Response, Status, Streaming}; - -type PrepareStream = ReceiverStream>; - -pub async fn run(mut stream: Streaming) -> Result, Status> { - let (tx, rx) = mpsc::channel(4); - - tokio::spawn(async move { - let mut source_data: Vec = Vec::new(); - let mut source_hash = String::new(); - let mut source_name = String::new(); - let mut source_signature = String::new(); - let mut source_chunks = 0; - - while let Some(chunk) = stream.next().await { - let chunk = chunk.map_err(|e| Status::internal(format!("Stream error: {}", e)))?; - - if source_chunks == 0 { - source_hash = chunk.source_hash; - source_name = chunk.source_name; - source_signature = chunk.source_signature; - } - - source_chunks += 1; - source_data.extend_from_slice(&chunk.source_data); - } - - if source_hash.is_empty() { - return Err(Status::internal("source hash is empty")); - } - - if source_name.is_empty() { - return Err(Status::internal("source name is empty")); - } - - if source_signature.is_empty() { - return Err(Status::internal("source signature is empty")); - } - - tx.send(Ok(PrepareResponse { - source_id: 0, - source_log: format!("source chunks received: {}", source_chunks), - })) - .await - .unwrap(); - - let public_key = notary::get_public_key() - .await - .map_err(|_| Status::internal("failed to get public key"))?; - - let verifying_key = VerifyingKey::::new(public_key); - - let signature_decode = hex::decode(source_signature) - .map_err(|_| Status::internal("hex decode of signature failed"))?; - - let signature = Signature::try_from(signature_decode.as_slice()) - .map_err(|_| Status::internal("failed to decode signature"))?; - - verifying_key - .verify(&source_data, &signature) - .map_err(|_| Status::internal("failed to verify signature"))?; - - let package_source_path = paths::get_package_source_path(&source_name, &source_hash); - let package_source_tar_path = - paths::get_package_source_tar_path(&source_name, &source_hash); - - if !package_source_tar_path.exists() { - let mut source_tar = File::create(&package_source_tar_path).await?; - if let Err(e) = source_tar.write_all(&source_data).await { - return Err(Status::internal(format!( - "Failed to write source tar: {}", - e - ))); - } else { - let metadata = fs::metadata(&package_source_tar_path).await?; - let mut permissions = metadata.permissions(); - permissions.set_mode(0o444); - fs::set_permissions(package_source_tar_path.clone(), permissions).await?; - let file_name = package_source_tar_path.file_name().unwrap(); - tx.send(Ok(PrepareResponse { - source_id: 0, - source_log: format!("source tar created: {}", file_name.to_string_lossy()), - })) - .await - .unwrap(); - } - } - - fs::create_dir_all(&package_source_path).await?; - - if let Err(err) = - archives::unpack_tar_gz(&package_source_path, &package_source_tar_path).await - { - return Err(Status::internal(format!( - "Failed to unpack source tar: {}", - err - ))); - } - - let source_file_paths = paths::get_file_paths(&package_source_path, &Vec::<&str>::new()) - .map_err(|e| Status::internal(format!("Failed to get source files: {:?}", e)))?; - - tx.send(Ok(PrepareResponse { - source_id: 0, - source_log: format!("source files: {:?}", source_file_paths.len()), - })) - .await - .unwrap(); - - let source_files_hashes = hashes::get_files(&source_file_paths) - .map_err(|e| Status::internal(format!("Failed to get source file hashes: {:?}", e)))?; - - let source_hash_computed = hashes::get_source(&source_files_hashes) - .map_err(|e| Status::internal(format!("Failed to get source hash: {:?}", e)))?; - - tx.send(Ok(PrepareResponse { - source_id: 0, - source_log: format!("source hash: {}", source_hash), - })) - .await - .unwrap(); - - tx.send(Ok(PrepareResponse { - source_id: 0, - source_log: format!("source hash expected: {}", source_hash_computed), - })) - .await - .unwrap(); - - if source_hash != source_hash_computed { - return Err(Status::internal("source hash mismatch")); - } - - let db = database::connect(paths::get_database_path()) - .map_err(|_| Status::internal("failed to connect to database"))?; - - let mut source_id = database::find_source(&db, &source_hash, &source_name) - .map(|source| source.id) - .unwrap_or(0); - - if source_id == 0 { - database::insert_source(&db, &source_hash, &source_name) - .map_err(|e| Status::internal(format!("Failed to insert source: {:?}", e)))?; - - source_id = database::find_source(&db, &source_hash, &source_name) - .map(|source| source.id) - .map_err(|e| Status::internal(format!("Failed to find source: {:?}", e)))?; - } - - fs::remove_dir_all(package_source_path).await?; - - tx.send(Ok(PrepareResponse { - source_id, - source_log: "".to_string(), - })) - .await - .unwrap(); - - if let Err(e) = db.close() { - return Err(Status::internal(format!( - "Failed to close database: {:?}", - e.1 - ))); - } - - Ok(()) - }); - - Ok(Response::new(ReceiverStream::new(rx))) -} diff --git a/src/service/build/service.rs b/src/service/build/service.rs deleted file mode 100644 index cf57b508..00000000 --- a/src/service/build/service.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::api::package_service_server::PackageService; -use crate::api::{BuildRequest, BuildResponse, PrepareRequest, PrepareResponse}; -use crate::service::build::{run_build, run_prepare}; -use anyhow::Result; -use tokio_stream::wrappers::ReceiverStream; -use tonic::{Request, Response, Status, Streaming}; - -#[derive(Debug, Default)] -pub struct Package {} - -#[tonic::async_trait] -impl PackageService for Package { - type BuildStream = ReceiverStream>; - type PrepareStream = ReceiverStream>; - - async fn prepare( - &self, - request: Request>, - ) -> Result, Status> { - run_prepare::run(request.into_inner()).await - } - - async fn build( - &self, - request: Request, - ) -> Result, Status> { - run_build::run(request).await - } -} diff --git a/src/service/mod.rs b/src/service/mod.rs index 327996ca..9de4abf4 100644 --- a/src/service/mod.rs +++ b/src/service/mod.rs @@ -1,2 +1,2 @@ -pub mod build; -pub mod proxy; +pub mod agent; +pub mod worker; diff --git a/src/service/proxy/package/mod.rs b/src/service/proxy/package/mod.rs deleted file mode 100644 index 83910a89..00000000 --- a/src/service/proxy/package/mod.rs +++ /dev/null @@ -1,433 +0,0 @@ -use crate::api::package_service_client::PackageServiceClient; -use crate::api::{ - BuildRequest, PackageRequest, PackageResponse, PackageSource, PackageSourceKind, PrepareRequest, -}; -use crate::notary; -use crate::store::archives; -use crate::store::hashes; -use crate::store::paths; -use crate::store::temps; -use async_compression::tokio::bufread::BzDecoder; -use git2::build::RepoBuilder; -use git2::{Cred, RemoteCallbacks}; -use reqwest; -use std::fs::Permissions; -use std::os::unix::fs::PermissionsExt; -use std::path::{Path, PathBuf}; -use tokio::fs; -use tokio::fs::{ - copy, create_dir_all, read, remove_dir_all, remove_file, set_permissions, write, File, -}; -use tokio::io::AsyncWriteExt; -use tokio::sync::mpsc::Sender; -use tokio_stream; -use tokio_stream::StreamExt; -use tokio_tar::Archive; -use tonic::Status; -use url::Url; - -pub async fn validate_hashes( - tx: &Sender>, - workdir_path: &Path, - source: &PackageSource, -) -> Result<(String, Vec), anyhow::Error> { - let workdir_files = paths::get_file_paths(workdir_path, &source.ignore_paths)?; - - if workdir_files.is_empty() { - return Err(anyhow::anyhow!("No source files found")); - } - - tx.send(Ok(PackageResponse { - package_log: format!("preparing source files: {:?} found", workdir_files.len()), - })) - .await?; - - let workdir_files_hashes = hashes::get_files(&workdir_files)?; - let workdir_hash = hashes::get_source(&workdir_files_hashes)?; - - if workdir_hash.is_empty() { - return Err(anyhow::anyhow!("Failed to get source hash")); - } - - tx.send(Ok(PackageResponse { - package_log: format!("preparing source hash: {}", workdir_hash), - })) - .await?; - - if let Some(request_hash) = &source.hash { - if &workdir_hash != request_hash { - let message = format!("Hash mismatch: {} != {}", request_hash, workdir_hash); - return Err(anyhow::anyhow!("{}", message)); - } - } - - Ok((workdir_hash, workdir_files)) -} - -pub async fn send_source( - tx: &Sender>, - name: &str, - source_hash: &str, - source_tar_path: &Path, -) -> Result<(i32, String), anyhow::Error> { - tx.send(Ok(PackageResponse { - package_log: format!("preparing source tar: {}", source_tar_path.display()), - })) - .await?; - - let data = read(&source_tar_path).await?; - - let signature = notary::sign(&data).await?; - - tx.send(Ok(PackageResponse { - package_log: format!("preparing source tar signature: {}", signature), - })) - .await?; - - let mut request_chunks = vec![]; - let request_chunks_size = 8192; // default grpc limit - - for chunk in data.chunks(request_chunks_size) { - request_chunks.push(PrepareRequest { - source_data: chunk.to_vec(), - source_hash: source_hash.to_string(), - source_name: name.to_string(), - source_signature: signature.to_string(), - }); - } - - tx.send(Ok(PackageResponse { - package_log: format!("preparing source chunks: {}", request_chunks.len()), - })) - .await?; - - let mut client = PackageServiceClient::connect("http://[::1]:23151").await?; - let response = client.prepare(tokio_stream::iter(request_chunks)).await?; - let mut stream = response.into_inner(); - let mut source_id = 0; - - while let Some(chunk) = stream.message().await? { - tx.send(Ok(PackageResponse { - package_log: chunk.source_log.to_string(), - })) - .await?; - - if chunk.source_id != 0 { - source_id = chunk.source_id; - } - } - - if source_id == 0 { - return Err(anyhow::anyhow!("Failed to get source id")); - } - - tx.send(Ok(PackageResponse { - package_log: format!("source id: {}", source_id).to_string(), - })) - .await?; - - Ok((source_id, source_hash.to_string())) -} - -pub async fn prepare( - tx: &Sender>, - name: &str, - source: &PackageSource, -) -> Result<(i32, String), anyhow::Error> { - if source.kind == PackageSourceKind::Unknown as i32 { - return Err(anyhow::anyhow!("unknown source kind")); - } - - let mut source_hash = source.hash.clone().unwrap_or("".to_string()); - - if source_hash.is_empty() && source.kind == PackageSourceKind::Local as i32 { - let source_path = Path::new(&source.uri).canonicalize()?; - let (source_path_hash, _) = validate_hashes(tx, &source_path, source).await?; - - source_hash = source_path_hash; - } - - if source_hash.is_empty() { - return Err(anyhow::anyhow!("source hash is empty")); - } - - let workdir = temps::create_dir().await?; - let workdir_path = workdir.canonicalize()?; - - let source_tar_path = paths::get_package_source_tar_path(name, &source_hash); - - if source_tar_path.exists() { - tx.send(Ok(PackageResponse { - package_log: format!("using existing source tar: {:?}", source_tar_path.display()), - })) - .await?; - - return send_source(tx, name, &source_hash, &source_tar_path).await; - } - - if source.kind == PackageSourceKind::Git as i32 { - let mut builder = RepoBuilder::new(); - - if source.uri.starts_with("git://") { - let mut callbacks = RemoteCallbacks::new(); - - callbacks.credentials(|_url, username_from_url, _allowed_types| { - Cred::ssh_key( - username_from_url.unwrap(), - None, - Path::new(&format!( - "{}/.ssh/id_rsa", - dirs::home_dir().unwrap().display() - )), - None, - ) - }); - - let mut fetch_options = git2::FetchOptions::new(); - - fetch_options.remote_callbacks(callbacks); - - builder.fetch_options(fetch_options); - } - - let _ = builder.clone(&source.uri, &workdir_path)?; - } - - if source.kind == PackageSourceKind::Http as i32 { - tx.send(Ok(PackageResponse { - package_log: format!("preparing download source: {:?}", &source.uri), - })) - .await?; - - let url = Url::parse(&source.uri)?; - - if url.scheme() != "http" && url.scheme() != "https" { - return Err(anyhow::anyhow!("invalid HTTP source URL")); - } - - let response = reqwest::get(url.as_str()).await?.bytes().await?; - let response_bytes = response.as_ref(); - - if let Some(source_kind) = infer::get(response_bytes) { - tx.send(Ok(PackageResponse { - package_log: format!("preparing download source kind: {:?}", source_kind), - })) - .await?; - - if let "application/gzip" = source_kind.mime_type() { - let temp_file = temps::create_file("tar.gz").await?; - write(&temp_file, response_bytes).await?; - archives::unpack_tar_gz(&workdir_path, &temp_file).await?; - remove_file(&temp_file).await?; - tx.send(Ok(PackageResponse { - package_log: format!("preparing download gzip source: {:?}", workdir_path), - })) - .await?; - } else if let "application/x-bzip2" = source_kind.mime_type() { - let bz_decoder = BzDecoder::new(response_bytes); - let mut archive = Archive::new(bz_decoder); - archive.unpack(&workdir_path).await?; - tx.send(Ok(PackageResponse { - package_log: format!("preparing bzip2 source: {:?}", workdir_path), - })) - .await?; - } else { - let source_file_name = url.path_segments().unwrap().last(); - let source_file = source_file_name.unwrap(); - write(&source_file, response_bytes).await?; - tx.send(Ok(PackageResponse { - package_log: format!("preparing source file: {:?}", source_file), - })) - .await?; - } - } - } - - if source.kind == PackageSourceKind::Local as i32 { - let source_path = Path::new(&source.uri).canonicalize()?; - - tx.send(Ok(PackageResponse { - package_log: format!("preparing source path: {:?}", source_path), - })) - .await?; - - if let Ok(Some(source_kind)) = infer::get_from_path(&source_path) { - tx.send(Ok(PackageResponse { - package_log: format!("preparing source kind: {:?}", source_kind), - })) - .await?; - - if source_kind.mime_type() == "application/gzip" { - tx.send(Ok(PackageResponse { - package_log: format!("preparing packed source: {:?}", workdir), - })) - .await?; - - archives::unpack_tar_gz(&workdir_path, &source_path).await?; - } - } - - if source_path.is_file() { - let dest = workdir_path.join(source_path.file_name().unwrap()); - copy(&source_path, &dest).await?; - tx.send(Ok(PackageResponse { - package_log: format!( - "preparing source file: {:?} -> {:?}", - source_path.display(), - dest.display() - ), - })) - .await?; - } - - if source_path.is_dir() { - let file_paths = paths::get_file_paths(&source_path, &source.ignore_paths)?; - - if file_paths.is_empty() { - return Err(anyhow::anyhow!("No source files found")); - } - - for src in &file_paths { - if src.is_dir() { - let dest = workdir_path.join(src.strip_prefix(&source_path)?); - create_dir_all(dest).await?; - continue; - } - - let dest = workdir_path.join(src.file_name().unwrap()); - copy(src, &dest).await?; - tx.send(Ok(PackageResponse { - package_log: format!( - "preparing source file: {:?} -> {:?}", - source_path.display(), - dest.display() - ), - })) - .await?; - } - } - } - - // At this point, any source URI should be a local file path - - let (workdir_hash, workdir_files) = validate_hashes(tx, &workdir_path, source).await?; - - archives::compress_tar_gz(&workdir_path, &source_tar_path, &workdir_files).await?; - - set_permissions(&source_tar_path, Permissions::from_mode(0o444)).await?; - - remove_dir_all(&workdir_path).await?; - - send_source(tx, name, &workdir_hash, &source_tar_path).await -} - -pub async fn build( - tx: &Sender>, - source_id: i32, - source_hash: &str, - request: &PackageRequest, -) -> Result<(), anyhow::Error> { - let package = paths::get_package_path(&request.name, source_hash); - - if package.exists() { - tx.send(Ok(PackageResponse { - package_log: format!("using existing package: {}", package.display()), - })) - .await?; - - return Ok(()); - } - - let package_tar = package.with_extension("tar.gz"); - - if package_tar.exists() { - tx.send(Ok(PackageResponse { - package_log: format!("unpacking existing package tar: {}", package_tar.display()), - })) - .await?; - - fs::create_dir_all(&package).await?; - - archives::unpack_tar_gz(&package, &package_tar).await?; - - tx.send(Ok(PackageResponse { - package_log: format!("unpacked existing package tar: {}", package.display()), - })) - .await?; - - return Ok(()); - } - - let build_args = tonic::Request::new(BuildRequest { - build_deps: Vec::new(), - build_phase: request.build_phase.to_string(), - install_deps: Vec::new(), - install_phase: request.install_phase.to_string(), - source_id, - }); - - let mut client = PackageServiceClient::connect("http://[::1]:23151").await?; - let response = client.build(build_args).await?; - let mut response_stream = response.into_inner(); - let mut package_archived = false; - let mut package_data = Vec::new(); - - while let Some(build_response) = response_stream.next().await { - let response = build_response?; - - tx.send(Ok(PackageResponse { - package_log: response.package_log, - })) - .await?; - - if !response.package_data.is_empty() { - package_data.extend_from_slice(&response.package_data); - } - - if response.is_archive { - package_archived = true; - } - } - - if package_archived { - let mut store_tar = File::create(&package_tar).await?; - if let Err(e) = store_tar.write(&package_data).await { - return Err(anyhow::anyhow!("Failed to write tar: {:?}", e)); - } else { - let metadata = fs::metadata(&package_tar).await?; - let mut permissions = metadata.permissions(); - - permissions.set_mode(0o440); - - fs::set_permissions(&package_tar, permissions).await?; - } - - tx.send(Ok(PackageResponse { - package_log: format!("stored package tar: {}", package_tar.display()), - })) - .await?; - - fs::create_dir_all(&package).await?; - - archives::unpack_tar_gz(&package, &package_tar).await?; - - tx.send(Ok(PackageResponse { - package_log: format!("unpacked package: {}", package.display()), - })) - .await?; - - return Ok(()); - } - - let mut store_file = File::create(&package).await?; - if let Err(e) = store_file.write(&package_data).await { - return Err(anyhow::anyhow!("Failed to file: {:?}", e)); - } else { - let metadata = fs::metadata(&package_tar).await?; - let mut permissions = metadata.permissions(); - permissions.set_mode(0o440); - fs::set_permissions(&package, permissions).await?; - } - - Ok(()) -} diff --git a/src/service/proxy/service.rs b/src/service/proxy/service.rs deleted file mode 100644 index 4b73e5b0..00000000 --- a/src/service/proxy/service.rs +++ /dev/null @@ -1,53 +0,0 @@ -use crate::api::command_service_server::CommandService; -use crate::api::{PackageRequest, PackageResponse}; -use crate::service::proxy::package; -use anyhow::Result; -use tokio::sync::mpsc; -use tokio_stream::wrappers::ReceiverStream; -use tonic::{Request, Response, Status}; - -#[derive(Debug, Default)] -pub struct Proxy {} - -#[tonic::async_trait] -impl CommandService for Proxy { - type PackageStream = ReceiverStream>; - - async fn package( - &self, - request: Request, - ) -> Result, Status> { - let (tx, rx) = mpsc::channel(4); - - tokio::spawn(async move { - let req = request.into_inner(); - - let req_source = req - .source - .as_ref() - .ok_or_else(|| Status::invalid_argument("source is required"))?; - - tx.send(Ok(PackageResponse { - package_log: format!("preparing package: {}", req.name), - })) - .await - .map_err(|e| Status::internal(e.to_string()))?; - - let (source_id, source_hash) = package::prepare(&tx, &req.name, req_source) - .await - .map_err(|e| Status::internal(e.to_string()))?; - - tx.send(Ok(PackageResponse { - package_log: format!("building package: {}-{}", req.name, source_hash), - })) - .await - .map_err(|e| Status::internal(e.to_string()))?; - - package::build(&tx, source_id, &source_hash, &req) - .await - .map_err(|e| Status::internal(format!("Failed to build package: {}", e))) - }); - - Ok(Response::new(ReceiverStream::new(rx))) - } -} diff --git a/src/service/build/mod.rs b/src/service/worker/mod.rs similarity index 64% rename from src/service/build/mod.rs rename to src/service/worker/mod.rs index fb89669d..4618dc5e 100644 --- a/src/service/build/mod.rs +++ b/src/service/worker/mod.rs @@ -1,28 +1,28 @@ use crate::api::package_service_server::PackageServiceServer; -use crate::database; +use crate::api::store_service_server::StoreServiceServer; use crate::notary; use crate::store; use anyhow::Result; use tonic::transport::Server; use tracing::info; -mod run_build; -mod run_prepare; mod sandbox_default; -pub mod service; +mod service; pub async fn start(port: u16) -> Result<(), anyhow::Error> { store::check_dirs().await?; + notary::check_keys()?; - database::init()?; let addr = format!("[::1]:{}", port).parse()?; - let packager = service::Package::default(); + let package = service::Package::default(); + let store = service::Store::default(); info!("service listening on: {}", addr); Server::builder() - .add_service(PackageServiceServer::new(packager)) + .add_service(PackageServiceServer::new(package)) + .add_service(StoreServiceServer::new(store)) .serve(addr) .await?; diff --git a/src/service/build/sandbox_default.rs b/src/service/worker/sandbox_default.rs similarity index 91% rename from src/service/build/sandbox_default.rs rename to src/service/worker/sandbox_default.rs index 1508f9a2..9a15d689 100644 --- a/src/service/build/sandbox_default.rs +++ b/src/service/worker/sandbox_default.rs @@ -8,5 +8,5 @@ pub const SANDBOX_DEFAULT: &str = r#" (allow process-fork) ; Global denies -(deny network*) +; (deny network*) "#; diff --git a/src/service/worker/service.rs b/src/service/worker/service.rs new file mode 100644 index 00000000..babc9891 --- /dev/null +++ b/src/service/worker/service.rs @@ -0,0 +1,718 @@ +use crate::api::package_service_server::PackageService; +use crate::api::store_service_server::StoreService; +use crate::api::{ + PackageBuildRequest, PackageBuildResponse, PackagePrepareRequest, PackagePrepareResponse, + StoreFetchResponse, StorePath, StorePathKind, StorePathResponse, +}; +use crate::notary; +use crate::service::worker::sandbox_default; +use crate::store::{archives, hashes, paths, temps}; +use anyhow::Result; +use process_stream::{Process, ProcessExt}; +use rsa::pss::{Signature, VerifyingKey}; +use rsa::sha2::Sha256; +use rsa::signature::Verifier; +use std::collections::HashMap; +use std::convert::TryFrom; +use std::env; +use std::fs; +use std::os::unix::fs::PermissionsExt; +use tera::Tera; +use tokio::fs::{create_dir_all, metadata, read, remove_dir_all, set_permissions, write, File}; +use tokio::io::AsyncWriteExt; +use tokio::sync::mpsc; +use tokio_stream::wrappers::ReceiverStream; +use tokio_stream::StreamExt; +use tonic::{Request, Response, Status, Streaming}; +use tracing::info; + +#[derive(Debug, Default)] +pub struct Package {} + +#[derive(Debug, Default)] +pub struct Store {} + +#[tonic::async_trait] +impl StoreService for Store { + type FetchStream = ReceiverStream>; + + async fn fetch( + &self, + request: Request, + ) -> Result, Status> { + let (tx, rx) = mpsc::channel(4); + + tokio::spawn(async move { + let req = request.into_inner(); + + let package_chunks_size = 8192; + + if req.kind == StorePathKind::Unknown as i32 { + return Err(Status::invalid_argument("invalid store path kind")); + } + + if req.kind == StorePathKind::Package as i32 { + let package_tar_path = paths::get_package_tar_path(&req.name, &req.hash); + + if !package_tar_path.exists() { + return Err(Status::not_found("package archive not found")); + } + + info!("serving package: {}", package_tar_path.display()); + + let data = read(&package_tar_path) + .await + .map_err(|_| Status::internal("failed to read cached package"))?; + + for package_chunk in data.chunks(package_chunks_size) { + tx.send(Ok(StoreFetchResponse { + data: package_chunk.to_vec(), + })) + .await + .unwrap(); + } + + return Ok(()); + } + + let package_source_tar_path = paths::get_package_source_tar_path(&req.name, &req.hash); + + if !package_source_tar_path.exists() { + return Err(Status::not_found("package source tar not found")); + } + + info!( + "serving package source: {}", + package_source_tar_path.display() + ); + + let data = read(&package_source_tar_path) + .await + .map_err(|_| Status::internal("failed to read cached package"))?; + + for package_chunk in data.chunks(package_chunks_size) { + tx.send(Ok(StoreFetchResponse { + data: package_chunk.to_vec(), + })) + .await + .unwrap(); + } + + Ok(()) + }); + + Ok(Response::new(ReceiverStream::new(rx))) + } + + async fn path( + &self, + request: Request, + ) -> Result, Status> { + let req = request.into_inner(); + + if req.kind == StorePathKind::Unknown as i32 { + return Err(Status::invalid_argument("invalid store path kind")); + } + + if req.kind == StorePathKind::Package as i32 { + let package_path = paths::get_package_path(&req.name, &req.hash); + + if !package_path.exists() { + return Err(Status::not_found("package archive not found")); + } + + return Ok(Response::new(StorePathResponse { + uri: package_path.to_string_lossy().to_string(), + })); + } + + let package_source_tar_path = paths::get_package_source_tar_path(&req.name, &req.hash); + + if !package_source_tar_path.exists() { + return Err(Status::not_found("package source tar not found")); + } + + Ok(Response::new(StorePathResponse { + uri: package_source_tar_path.to_string_lossy().to_string(), + })) + } +} + +#[tonic::async_trait] +impl PackageService for Package { + type BuildStream = ReceiverStream>; + type PrepareStream = ReceiverStream>; + + async fn prepare( + &self, + request: Request>, + ) -> Result, Status> { + let (tx, rx) = mpsc::channel(4); + + tokio::spawn(async move { + let mut source_data: Vec = Vec::new(); + let mut source_hash = String::new(); + let mut source_name = String::new(); + let mut source_signature = String::new(); + let mut source_chunks = 0; + + let mut stream = request.into_inner(); + + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(|e| Status::internal(format!("stream error: {}", e)))?; + + source_chunks += 1; + source_data.extend_from_slice(&chunk.source_data); + source_hash = chunk.source_hash; + source_name = chunk.source_name; + source_signature = chunk.source_signature; + } + + if source_hash.is_empty() { + return Err(Status::internal("source hash is empty")); + } + + if source_name.is_empty() { + return Err(Status::internal("source name is empty")); + } + + if source_signature.is_empty() { + return Err(Status::internal("source signature is empty")); + } + + tx.send(Ok(PackagePrepareResponse { + log_output: format!("package source chunks received: {}", source_chunks) + .into_bytes(), + })) + .await + .unwrap(); + + let package_source_path = paths::get_package_path(&source_name, &source_hash); + + if package_source_path.exists() { + tx.send(Ok(PackagePrepareResponse { + log_output: format!( + "package source already prepared: {}", + package_source_path.display() + ) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + return Err(Status::already_exists("package source already prepared")); + } + + let package_source_tar_path = + paths::get_package_source_tar_path(&source_name, &source_hash); + + if package_source_tar_path.exists() { + tx.send(Ok(PackagePrepareResponse { + log_output: format!( + "package source tar already prepared: {}", + package_source_tar_path.display() + ) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + return Err(Status::already_exists( + "package source tar already prepared", + )); + } + + // at this point we should be ready to prepare the source + + let public_key = notary::get_public_key() + .await + .map_err(|_| Status::internal("failed to get public key"))?; + + let verifying_key = VerifyingKey::::new(public_key); + + let signature_decode = hex::decode(source_signature) + .map_err(|_| Status::internal("hex decode of signature failed"))?; + + let signature = Signature::try_from(signature_decode.as_slice()) + .map_err(|_| Status::internal("failed to decode signature"))?; + + verifying_key + .verify(&source_data, &signature) + .map_err(|_| Status::internal("failed to verify signature"))?; + + tx.send(Ok(PackagePrepareResponse { + log_output: format!( + "source tar not found: {}", + package_source_tar_path.display() + ) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + + let mut source_tar = File::create(&package_source_tar_path).await?; + if let Err(e) = source_tar.write_all(&source_data).await { + return Err(Status::internal(format!( + "failed to write source tar: {}", + e + ))); + } else { + let metadata = metadata(&package_source_tar_path).await?; + let mut permissions = metadata.permissions(); + permissions.set_mode(0o444); + set_permissions(package_source_tar_path.clone(), permissions).await?; + let file_name = package_source_tar_path.file_name().unwrap(); + tx.send(Ok(PackagePrepareResponse { + log_output: format!("source tar created: {}", file_name.to_string_lossy()) + .into_bytes(), + })) + .await + .unwrap(); + } + + let temp_source_path = temps::create_dir() + .await + .map_err(|_| Status::internal("failed to create temp dir"))?; + + create_dir_all(&temp_source_path).await?; + + tx.send(Ok(PackagePrepareResponse { + log_output: format!("package source unpacking: {}", temp_source_path.display()) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + + if let Err(err) = + archives::unpack_tar_gz(&temp_source_path, &package_source_tar_path).await + { + return Err(Status::internal(format!( + "failed to unpack source tar: {}", + err + ))); + } + + let temp_file_paths = paths::get_file_paths(&temp_source_path, &Vec::<&str>::new()) + .map_err(|e| Status::internal(format!("failed to get source files: {:?}", e)))?; + + tx.send(Ok(PackagePrepareResponse { + log_output: format!("source files: {:?}", temp_file_paths.len()).into_bytes(), + })) + .await + .unwrap(); + + let temp_files_hashes = hashes::get_files(&temp_file_paths).map_err(|e| { + Status::internal(format!("failed to get source file hashes: {:?}", e)) + })?; + + let temp_hash_computed = hashes::get_source(&temp_files_hashes) + .map_err(|e| Status::internal(format!("failed to get source hash: {:?}", e)))?; + + tx.send(Ok(PackagePrepareResponse { + log_output: format!("source hash: {}", source_hash).into_bytes(), + })) + .await + .unwrap(); + + tx.send(Ok(PackagePrepareResponse { + log_output: format!("source hash expected: {}", temp_hash_computed).into_bytes(), + })) + .await + .unwrap(); + + if source_hash != temp_hash_computed { + return Err(Status::internal("package source hash mismatch")); + } + + remove_dir_all(temp_source_path).await?; + + Ok(()) + }); + + Ok(Response::new(ReceiverStream::new(rx))) + } + + async fn build( + &self, + request: Request, + ) -> Result, Status> { + let (tx, rx) = mpsc::channel(4); + + tokio::spawn(async move { + let req = request.into_inner(); + + let package_path = paths::get_package_path(&req.source_name, &req.source_hash); + + if package_path.exists() { + tx.send(Ok(PackageBuildResponse { + log_output: format!("package already built: {}", package_path.display()) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + return Err(Status::already_exists("package already built")); + } + + let package_tar_path = paths::get_package_tar_path(&req.source_name, &req.source_hash); + + if !package_path.exists() && package_tar_path.exists() { + tx.send(Ok(PackageBuildResponse { + log_output: format!( + "package tar found (unpacking): {}", + package_tar_path.display() + ) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + + create_dir_all(&package_path) + .await + .map_err(|_| Status::internal("failed to create package dir"))?; + + if let Err(err) = archives::unpack_tar_gz(&package_path, &package_tar_path).await { + return Err(Status::internal(format!( + "failed to unpack source tar: {:?}", + err + ))); + } + + return Err(Status::internal("package already built")); + } + + let build_path = temps::create_dir() + .await + .map_err(|_| Status::internal("failed to create temp dir"))?; + + let package_source_path = + paths::get_package_source_path(&req.source_name, &req.source_hash); + + if package_source_path.exists() { + tx.send(Ok(PackageBuildResponse { + log_output: format!("package source found: {}", package_source_path.display()) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + + paths::copy_files(&package_source_path, &build_path) + .await + .map_err(|e| { + Status::internal(format!("failed to copy source files: {:?}", e)) + })?; + + tx.send(Ok(PackageBuildResponse { + log_output: format!("package source copied: {}", build_path.display()) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + } + + let package_source_tar_path = + paths::get_package_source_tar_path(&req.source_name, &req.source_hash); + + if !package_source_path.exists() && package_source_tar_path.exists() { + tx.send(Ok(PackageBuildResponse { + log_output: format!( + "package source tar found: {}", + package_source_tar_path.display() + ) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + + create_dir_all(&package_source_path) + .await + .map_err(|_| Status::internal("failed to create package source dir"))?; + + tx.send(Ok(PackageBuildResponse { + log_output: format!( + "package source unpacking: {}", + package_source_path.display() + ) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + + if let Err(err) = + archives::unpack_tar_gz(&package_source_path, &package_source_tar_path).await + { + return Err(Status::internal(format!( + "failed to unpack source tar: {:?}", + err + ))); + } + + tx.send(Ok(PackageBuildResponse { + log_output: format!( + "package source copying: {}", + package_source_path.display() + ) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + + paths::copy_files(&package_source_path, &build_path) + .await + .map_err(|e| { + Status::internal(format!("failed to copy source files: {:?}", e)) + })?; + + tx.send(Ok(PackageBuildResponse { + log_output: format!("package source copied: {}", build_path.display()) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + } + + let build_source_file_paths = paths::get_file_paths(&build_path, &Vec::<&str>::new()) + .map_err(|e| { + Status::internal(format!("failed to get source files: {:?}", e)) + })?; + + if build_source_file_paths.is_empty() { + return Err(Status::internal("no source files found")); + } + + // at this point we should be ready to build with source files + + tx.send(Ok(PackageBuildResponse { + log_output: format!("package building: {}", build_path.display()).into_bytes(), + })) + .await + .unwrap(); + + let build_vorpal_path = build_path.join(".vorpal"); + + create_dir_all(&build_vorpal_path) + .await + .map_err(|_| Status::internal("failed to create build vorpal dir"))?; + + let package_build_script = req + .build_script + .trim() + .split('\n') + .map(|line| line.trim()) + .collect::>() + .join("\n"); + + let build_script = [ + "#!/bin/bash", + "set -e pipefail", + "echo \"PATH: $PATH\"", + "echo \"Starting build script\"", + &package_build_script, + "echo \"Finished build script\"", + ]; + + let build_script_data = build_script.join("\n"); + + tx.send(Ok(PackageBuildResponse { + log_output: format!("package build script: {}", build_script_data).into_bytes(), + })) + .await + .unwrap(); + + let build_script_path = build_vorpal_path.join("build.sh"); + + write(&build_script_path, build_script_data) + .await + .map_err(|_| Status::internal("failed to write build script"))?; + + set_permissions(&build_script_path, fs::Permissions::from_mode(0o755)) + .await + .map_err(|_| Status::internal("failed to set build script permissions"))?; + + let build_profile_path = build_vorpal_path.join("sandbox.sb"); + + let mut tera = Tera::default(); + tera.add_raw_template("sandbox_default", sandbox_default::SANDBOX_DEFAULT) + .unwrap(); + + let mut context = tera::Context::new(); + context.insert("tmpdir", build_path.to_str().unwrap()); + let default_profile = tera.render("sandbox_default", &context).unwrap(); + + write(&build_profile_path, default_profile) + .await + .map_err(|_| Status::internal("failed to write sandbox profile"))?; + + if !build_profile_path.exists() { + return Err(Status::internal("build profile not found")); + } + + if !build_script_path.exists() { + return Err(Status::internal("build script not found")); + } + + let build_command_args = [ + "-f", + build_profile_path.to_str().unwrap(), + build_script_path.to_str().unwrap(), + ]; + + tx.send(Ok(PackageBuildResponse { + log_output: format!("build args: {:?}", build_command_args).into_bytes(), + })) + .await + .unwrap(); + + let mut build_environment = HashMap::new(); + + for (key, value) in req.build_environment.clone() { + build_environment.insert(key, value); + } + + tx.send(Ok(PackageBuildResponse { + log_output: format!("build packages: {:?}", req.build_packages).into_bytes(), + })) + .await + .unwrap(); + + let mut build_store_paths = vec![]; + + for path in req.build_packages { + let build_package = paths::get_package_path(&path.name, &path.hash); + if !build_package.exists() { + return Err(Status::internal("build package not found")); + } + + let package_bin_path = build_package.join("bin"); + if package_bin_path.exists() { + build_store_paths.push(package_bin_path.canonicalize()?.display().to_string()); + } + + build_environment.insert( + path.name.replace('-', "_").to_string(), + build_package.canonicalize()?.display().to_string(), + ); + } + + let os_type = env::consts::OS; + + if os_type != "macos" { + return Err(Status::unimplemented("unsupported os (macos only)")); + } + + if os_type == "macos" { + build_store_paths.push("/usr/bin".to_string()); + build_store_paths.push("/bin".to_string()); + build_store_paths.push("/Library/Developer/CommandLineTools/usr/bin".to_string()); + } + + tx.send(Ok(PackageBuildResponse { + log_output: format!("build store paths: {:?}", build_store_paths).into_bytes(), + })) + .await + .unwrap(); + + build_environment.insert("PATH".to_string(), build_store_paths.join(":")); + + let build_output_dir = temps::create_dir() + .await + .map_err(|_| Status::internal("failed to create temp dir"))?; + + let build_output_path = build_output_dir.canonicalize()?; + + build_environment.insert( + "output".to_string(), + build_output_path.display().to_string(), + ); + + tx.send(Ok(PackageBuildResponse { + log_output: format!("build output path: {}", build_output_path.display()) + .into_bytes(), + })) + .await + .unwrap(); + + tx.send(Ok(PackageBuildResponse { + log_output: format!("build environment: {:?}", build_environment).into_bytes(), + })) + .await + .unwrap(); + + let mut sandbox_command = Process::new("/usr/bin/sandbox-exec"); + sandbox_command.args(build_command_args); + sandbox_command.current_dir(&build_path); + + for (key, value) in build_environment { + sandbox_command.env(key, value); + } + + let mut stream = sandbox_command.spawn_and_stream()?; + + while let Some(output) = stream.next().await { + tx.send(Ok(PackageBuildResponse { + log_output: output.as_bytes().to_vec(), + })) + .await + .unwrap(); + } + + // TODO: properly handle error when sandbox command fails + + if let Err(err) = sandbox_command.status().await { + tx.send(Ok(PackageBuildResponse { + log_output: format!("build failed: {:?}", err).into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + return Err(Status::internal("sandbox command failed")); + } + + let build_output_files = paths::get_file_paths(&build_output_path, &Vec::<&str>::new()) + .map_err(|_| Status::internal("failed to get sandbox output files"))?; + + if build_output_files.is_empty() { + tx.send(Ok(PackageBuildResponse { + log_output: format!( + "no build output files found: {}", + build_output_path.display() + ) + .into_bytes(), + })) + .await + .map_err(|_| Status::internal("failed to send response"))?; + return Err(Status::internal("no build output files found")); + } + + create_dir_all(&package_path) + .await + .map_err(|_| Status::internal("failed to create package dir"))?; + + paths::copy_files(&build_output_path, &package_path) + .await + .map_err(|e| Status::internal(format!("failed to copy source files: {:?}", e)))?; + + if let Err(err) = archives::compress_tar_gz( + &build_output_path, + &build_output_files, + &package_tar_path, + ) + .await + { + return Err(Status::internal(format!( + "failed to compress sandbox output: {:?}", + err + ))); + } + + tx.send(Ok(PackageBuildResponse { + log_output: format!("package tar created: {}", package_tar_path.display()) + .into_bytes(), + })) + .await + .unwrap(); + + remove_dir_all(&build_path).await?; + + Ok(()) + }); + + Ok(Response::new(ReceiverStream::new(rx))) + } +} diff --git a/src/store/archives.rs b/src/store/archives.rs index 8fdbb97c..89da5508 100644 --- a/src/store/archives.rs +++ b/src/store/archives.rs @@ -1,30 +1,31 @@ use anyhow::Result; use async_compression::tokio::{bufread::GzipDecoder, write::GzipEncoder}; +use async_zip::tokio::read::seek::ZipFileReader; use std::path::{Path, PathBuf}; -use tokio::fs::File; use tokio::io::AsyncWriteExt; -use tokio::io::BufReader; -use tokio_tar::Archive; +use tokio::{ + fs::{create_dir_all, File, OpenOptions}, + io::BufReader, +}; +use tokio_tar::ArchiveBuilder; use tokio_tar::Builder; -use tracing::info; +use tokio_util::compat::TokioAsyncWriteCompatExt; pub async fn compress_tar_gz( - source: &PathBuf, - source_tar_path: &PathBuf, + source_path: &PathBuf, source_files: &[PathBuf], + output_tar_path: &PathBuf, ) -> Result { - let tar = File::create(source_tar_path).await?; + let tar = File::create(output_tar_path).await?; let tar_encoder = GzipEncoder::new(tar); let mut tar_builder = Builder::new(tar_encoder); for path in source_files { - if path == source { + if path == source_path { continue; } - let relative_path = path.strip_prefix(source)?; - - info!("packing: {:?}", relative_path); + let relative_path = path.strip_prefix(source_path)?; if path.is_file() { tar_builder @@ -36,6 +37,7 @@ pub async fn compress_tar_gz( } let mut output = tar_builder.into_inner().await?; + output.shutdown().await?; Ok(output.into_inner()) @@ -45,7 +47,70 @@ pub async fn unpack_tar_gz(target_dir: &PathBuf, source_tar: &Path) -> Result<() let tar_gz = File::open(source_tar).await?; let buf_reader = BufReader::new(tar_gz); let gz_decoder = GzipDecoder::new(buf_reader); - let mut archive = Archive::new(gz_decoder); + let archive_builder = ArchiveBuilder::new(gz_decoder) + .set_preserve_permissions(true) + .set_ignore_zeros(true); + let mut archive = archive_builder.build(); Ok(archive.unpack(target_dir).await?) } + +pub async fn unpack_zip(source_path: &PathBuf, out_dir: &Path) -> Result<(), anyhow::Error> { + let archive_file = File::open(source_path) + .await + .expect("Failed to open zip file"); + + let mut archive = BufReader::new(archive_file); + + let mut reader = ZipFileReader::with_tokio(&mut archive) + .await + .expect("Failed to read zip file"); + + for index in 0..reader.file().entries().len() { + let entry = reader.file().entries().get(index).unwrap(); + let path = out_dir.join(entry.filename().as_str().unwrap()); + // If the filename of the entry ends with '/', it is treated as a directory. + // This is implemented by previous versions of this crate and the Python Standard Library. + // https://docs.rs/async_zip/0.0.8/src/async_zip/read/mod.rs.html#63-65 + // https://github.com/python/cpython/blob/820ef62833bd2d84a141adedd9a05998595d6b6d/Lib/zipfile.py#L528 + let entry_is_dir = entry.dir().unwrap(); + + let mut entry_reader = reader + .reader_without_entry(index) + .await + .expect("Failed to read ZipEntry"); + + if entry_is_dir { + if !path.exists() { + create_dir_all(&path) + .await + .expect("Failed to create extracted directory"); + } + } else { + let parent = path + .parent() + .expect("A file entry should have parent directories"); + + if !parent.is_dir() { + create_dir_all(parent) + .await + .expect("Failed to create parent directories"); + } + + let writer = OpenOptions::new() + .write(true) + .create_new(true) + .open(&path) + .await + .expect("Failed to create extracted file"); + + futures_lite::io::copy(&mut entry_reader, &mut writer.compat_write()) + .await + .expect("Failed to copy to extracted file"); + + // Closes the file and manipulates its metadata here if you wish to preserve its metadata from the archive. + } + } + + Ok(()) +} diff --git a/src/store/paths.rs b/src/store/paths.rs index 7c76ef63..67109f31 100644 --- a/src/store/paths.rs +++ b/src/store/paths.rs @@ -2,6 +2,7 @@ use anyhow::Result; use std::env; use std::ffi::OsStr; use std::path::{Path, PathBuf}; +use tokio::fs::{copy, create_dir_all}; use uuid::Uuid; use walkdir::WalkDir; @@ -40,6 +41,10 @@ pub fn get_package_path(name: &str, hash: &str) -> PathBuf { get_store_path().join(store_dir_name) } +pub fn get_package_tar_path(name: &str, hash: &str) -> PathBuf { + get_package_path(name, hash).with_extension("tar.gz") +} + pub fn get_package_source_path(source_name: &str, source_hash: &str) -> PathBuf { get_package_path(source_name, source_hash).with_extension("source") } @@ -79,6 +84,32 @@ where Ok(files) } +pub async fn copy_files( + source_path: &PathBuf, + destination_path: &Path, +) -> Result<(), anyhow::Error> { + let file_paths = get_file_paths(source_path, &Vec::<&str>::new()) + .map_err(|e| anyhow::anyhow!("failed to get source files: {:?}", e))?; + + if file_paths.is_empty() { + return Err(anyhow::anyhow!("no source files found")); + } + + for src in &file_paths { + if src.is_dir() { + let dest = destination_path.join(src.strip_prefix(source_path).unwrap()); + create_dir_all(dest).await?; + continue; + } + + let dest = destination_path.join(src.strip_prefix(source_path).unwrap()); + + copy(src, dest).await?; + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*;