diff --git a/Cargo.lock b/Cargo.lock index e5d9157..4f92d39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,17 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98" -dependencies = [ - "getrandom 0.2.3", - "once_cell", - "version_check", -] - [[package]] name = "aho-corasick" version = "0.7.18" @@ -56,71 +45,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - [[package]] name = "base64" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" -[[package]] -name = "bcrypt" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f691e63585950d8c1c43644d11bab9073e40f5060dd2822734ae7c3dc69a3a80" -dependencies = [ - "base64 0.13.0", - "blowfish", - "getrandom 0.2.3", -] - -[[package]] -name = "bindle" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33160a91230f96b0150defcea8f8320e457091055ba58834f6d8ae75080fc595" -dependencies = [ - "anyhow", - "async-trait", - "base64 0.13.0", - "bcrypt", - "bytes", - "chrono", - "dirs 3.0.2", - "ed25519-dalek", - "either", - "futures", - "hyper", - "indexmap", - "jsonwebtoken", - "lru", - "mime", - "mime_guess", - "oauth2", - "rand 0.7.3", - "reqwest", - "semver", - "serde", - "serde_cbor", - "serde_json", - "sha2", - "sled", - "tempfile", - "thiserror", - "tokio", - "tokio-stream", - "tokio-util", - "toml", - "tracing", - "tracing-futures", - "url", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -136,29 +66,12 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blowfish" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe3ff3fc1de48c1ac2e3341c4df38b0d1bfb8fdf04632a187c8b75aaa319a7ab" -dependencies = [ - "byteorder", - "cipher", - "opaque-debug", -] - [[package]] name = "bumpalo" version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "bytes" version = "1.1.0" @@ -186,20 +99,10 @@ dependencies = [ "libc", "num-integer", "num-traits", - "serde", "time", "winapi", ] -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - [[package]] name = "clap" version = "3.0.11" @@ -281,51 +184,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crc32fast" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" -dependencies = [ - "cfg-if", - "lazy_static", -] - -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest", - "rand_core 0.5.1", - "subtle", - "zeroize", -] - [[package]] name = "dialoguer" version = "0.9.0" @@ -347,15 +205,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "dirs" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" -dependencies = [ - "dirs-sys", -] - [[package]] name = "dirs" version = "4.0.0" @@ -382,29 +231,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541" -[[package]] -name = "ed25519" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc" -dependencies = [ - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand 0.7.3", - "serde", - "sha2", - "zeroize", -] - [[package]] name = "either" version = "1.6.1" @@ -470,16 +296,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fs2" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "futures" version = "0.3.17" @@ -574,15 +390,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" version = "0.14.4" @@ -593,17 +400,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.3" @@ -611,10 +407,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi 0.10.2+wasi-snapshot-preview1", - "wasm-bindgen", ] [[package]] @@ -642,27 +436,12 @@ dependencies = [ "tracing", ] -[[package]] -name = "half" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" - [[package]] name = "hashbrown" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - [[package]] name = "heck" version = "0.4.0" @@ -684,12 +463,11 @@ version = "0.10.0" dependencies = [ "anyhow", "async-trait", - "bindle", "chrono", "clap", "colored", "dialoguer", - "dirs 4.0.0", + "dirs", "dunce", "env_logger", "futures", @@ -785,21 +563,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" -dependencies = [ - "futures-util", - "hyper", - "log", - "rustls", - "tokio", - "tokio-rustls", - "webpki", -] - [[package]] name = "hyper-tls" version = "0.5.0" @@ -831,16 +594,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" dependencies = [ "autocfg", - "hashbrown 0.9.1", -] - -[[package]] -name = "instant" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" -dependencies = [ - "cfg-if", + "hashbrown", ] [[package]] @@ -873,20 +627,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "jsonwebtoken" -version = "7.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afabcc15e437a6484fc4f12d0fd63068fe457bf93f1c148d3d9649c60b103f32" -dependencies = [ - "base64 0.12.3", - "pem", - "ring", - "serde", - "serde_json", - "simple_asn1", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -895,15 +635,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.101" +version = "0.2.122" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21" +checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259" [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] @@ -917,15 +657,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "lru" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea2d928b485416e8908cff2d97d621db22b27f7b3b6729e438bcf42c671ba91" -dependencies = [ - "hashbrown 0.11.2", -] - [[package]] name = "matches" version = "0.1.9" @@ -938,15 +669,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" -[[package]] -name = "memoffset" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" -dependencies = [ - "autocfg", -] - [[package]] name = "mime" version = "0.3.16" @@ -965,14 +687,15 @@ dependencies = [ [[package]] name = "mio" -version = "0.7.13" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" +checksum = "52da4364ffb0e4fe33a9841a98a3f3014fb964045ce4f7a45a398243c8d6b0c9" dependencies = [ "libc", "log", "miow", "ntapi", + "wasi 0.11.0+wasi-snapshot-preview1", "winapi", ] @@ -1012,17 +735,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "num-bigint" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-integer" version = "0.1.44" @@ -1044,34 +756,14 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", ] -[[package]] -name = "oauth2" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e47cfc4c0a1a519d9a025ebfbac3a2439d1b5cdf397d72dcb79b11d9920dab" -dependencies = [ - "base64 0.13.0", - "chrono", - "getrandom 0.2.3", - "http", - "rand 0.8.4", - "reqwest", - "serde", - "serde_json", - "serde_path_to_error", - "sha2", - "thiserror", - "url", -] - [[package]] name = "once_cell" version = "1.8.0" @@ -1128,38 +820,25 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" dependencies = [ - "instant", "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "995f667a6c822200b0433ac218e05582f0e2efa1b922a3fd2fbaadc5f87bab37" dependencies = [ "cfg-if", - "instant", "libc", "redox_syscall", "smallvec", - "winapi", -] - -[[package]] -name = "pem" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" -dependencies = [ - "base64 0.13.0", - "once_cell", - "regex", + "windows-sys", ] [[package]] @@ -1177,26 +856,6 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "pin-project" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.7" @@ -1275,19 +934,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - [[package]] name = "rand" version = "0.8.4" @@ -1295,19 +941,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.3", - "rand_hc 0.3.1", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", + "rand_hc", ] [[package]] @@ -1317,16 +953,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -1335,16 +962,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.3", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] @@ -1353,7 +971,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.6.3", + "rand_core", ] [[package]] @@ -1371,7 +989,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom 0.2.3", + "getrandom", "redox_syscall", ] @@ -1407,7 +1025,7 @@ version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22" dependencies = [ - "base64 0.13.0", + "base64", "bytes", "encoding_rs", "futures-core", @@ -1415,7 +1033,6 @@ dependencies = [ "http", "http-body", "hyper", - "hyper-rustls", "hyper-tls", "ipnet", "js-sys", @@ -1426,49 +1043,18 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", - "rustls", "serde", "serde_json", "serde_urlencoded", "tokio", "tokio-native-tls", - "tokio-rustls", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", "winreg", ] -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "rustls" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" -dependencies = [ - "base64 0.13.0", - "log", - "ring", - "sct", - "webpki", -] - [[package]] name = "ryu" version = "1.0.5" @@ -1491,16 +1077,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "sct" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "security-framework" version = "2.4.2" @@ -1552,16 +1128,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - [[package]] name = "serde_derive" version = "1.0.130" @@ -1584,15 +1150,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_path_to_error" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f6109f0506e20f7e0f910e51a0079acf41da8e0694e6442527c4ddf5a2b158" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.0" @@ -1627,79 +1184,34 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19772be3c4dd2ceaacf03cb41d5885f2a02c4d8804884918e3a258480803335" - -[[package]] -name = "simple_asn1" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692ca13de57ce0613a363c8c2f1de925adebc81b04c923ac60c5488bb44abe4b" -dependencies = [ - "chrono", - "num-bigint", - "num-traits", -] - [[package]] name = "slab" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590" -[[package]] -name = "sled" -version = "0.34.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0132f3e393bcb7390c60bb45769498cf4550bcb7a21d7f95c02b69f6362cdc" -dependencies = [ - "crc32fast", - "crossbeam-epoch", - "crossbeam-utils", - "fs2", - "fxhash", - "libc", - "log", - "parking_lot", -] - [[package]] name = "smallvec" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "socket2" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", "winapi", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - [[package]] name = "syn" version = "1.0.75" @@ -1711,18 +1223,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "synstructure" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "474aaa926faa1603c40b7885a9eaea29b444d1cb2850cb7c0e37bb1a4182f4fa" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - [[package]] name = "tempfile" version = "3.2.0" @@ -1731,7 +1231,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if", "libc", - "rand 0.8.4", + "rand", "redox_syscall", "remove_dir_all", "winapi", @@ -1762,26 +1262,6 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" -[[package]] -name = "thiserror" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "283d5230e63df9608ac7d9691adc1dfb6e701225436eb64d0b9a7f0a5a04f6ec" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa3884228611f5cd3608e2d409bf7dce832e4eb3135e3f11addbd7e41bd68e71" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "time" version = "0.1.43" @@ -1809,11 +1289,10 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.11.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4efe6fc2395938c8155973d7be49fe8d03a843726e285e100a8a383cc0154ce" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" dependencies = [ - "autocfg", "bytes", "libc", "memchr", @@ -1823,15 +1302,16 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", + "socket2", "tokio-macros", "winapi", ] [[package]] name = "tokio-macros" -version = "1.3.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" +checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" dependencies = [ "proc-macro2", "quote", @@ -1848,28 +1328,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" -dependencies = [ - "rustls", - "tokio", - "webpki", -] - -[[package]] -name = "tokio-stream" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.6.7" @@ -1906,23 +1364,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ "cfg-if", - "log", "pin-project-lite", - "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-attributes" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42e6fa53307c8a17e4ccd4dc81cf5ec38db9209f59b222210375b54ee40d1e2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tracing-core" version = "0.1.19" @@ -1932,16 +1377,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "try-lock" version = "0.2.3" @@ -1996,12 +1431,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "url" version = "2.2.2" @@ -2012,7 +1441,6 @@ dependencies = [ "idna", "matches", "percent-encoding", - "serde", ] [[package]] @@ -2039,15 +1467,15 @@ dependencies = [ [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" @@ -2127,25 +1555,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" -dependencies = [ - "webpki", -] - [[package]] name = "winapi" version = "0.3.9" @@ -2177,6 +1586,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5acdd78cb4ba54c0045ac14f62d8f94a03d10047904ae2a40afa1e99d8f70825" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" + +[[package]] +name = "windows_i686_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" + +[[package]] +name = "windows_i686_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" + [[package]] name = "winreg" version = "0.7.0" @@ -2191,18 +1643,3 @@ name = "zeroize" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "377db0846015f7ae377174787dd452e1c5f5a9050bc6f954911d01f116daa0cd" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2c1e130bebaeab2f23886bf9acbaca14b092408c452543c857f66399cd6dab1" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] diff --git a/Cargo.toml b/Cargo.toml index 464fd3f..61d4a44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ edition = "2018" [dependencies] anyhow = "1.0" async-trait = "0.1" -bindle = { version = "0.5.0", features = ["client"], default-features = false } chrono = "0.4" clap = { version = "3.0", features = ["derive", "env"] } colored = "2.0.0" @@ -30,5 +29,5 @@ semver = { version = "0.11", features = ["serde"] } serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" sha2 = "0.9" -tokio = {version = "1.8", features = ["time"]} +tokio = {version = "1.17", features = ["full"]} toml = "0.5" diff --git a/README.md b/README.md index 66f1c24..032504b 100644 --- a/README.md +++ b/README.md @@ -1,298 +1,111 @@ # Hippo Client -`hippo` is an **experimental** client for the [Hippo PaaS](https://github.com/deislabs/hippo) and [Bindle](https://github.com/deislabs/bindle). +`hippo` is an **experimental** client for the [Hippo +PaaS](https://github.com/deislabs/hippo). -The `hippo` tool processes an application's `HIPPOFACTS` (Hippo -artifacts) file and generates a bindle that it can either push directly -or can later be uploaded using `bindle push`. +The `hippo` tool interacts directly with the Hippo API. Its primary purpose is +to interact with the various endpoints provided by the +[hippo-openapi](https://github.com/fermyon/hippo-openapi) project. -## The HIPPOFACTS file +Users seeking to build, deploy, and run applications should look at +[spin](https://github.com/fermyon/spin/). -HIPPOFACTS is a TOML file with the following structure: +## Using the Hippo Client -```toml -[bindle] -name = "birdsondemand" -version = "1.2.3" -description = "provides birds as a service" # optional -authors = ["Joan Q Programmer"] # optional +### Logging in -[[handler]] -route = "/birds/flightless" -name = "bin/penguin.wasm" -files = ["photo/adelie.png", "photo/rockhopper.png", "stock/*.jpg"] - -[[handler]] -route = "/birds/irritable/fighty" -name = "bin/cassowary.wasm" -# entrypoint key is optional -# files key is optional - -[[handler]] -route = "/birds/naughty" -name = "bin/kea.wasm" -entrypoint = "steal_wipers" -files = ["stock/kea.jpg", "stock/wipers.jpg"] +```console +$ hippo login +Enter username: bacongobbler +Enter password: [hidden] +Logged in as bacongobbler ``` -The `bindle` section is copied directly to `invoice.toml`, _except_ that in development -mode a prerelease segment is appended to the version to make it unique. - -Each `handler` table is processed as follows: +Authentication is handled through `hippo login`, which logs into Hippo. With +`hippo login`, the Hippo URL is specified in the `--url` flag. Hippo requires +authentication: if `--username` or `--password` are not provided, the CLI will +prompt for that information. -* A group for the handler is added to the invoice -* The `name` value is looked up in the file system, and a parcel is entered into the invoice - for the corresponding file. The parcel's `conditions.requires` is set to the handler group. -* If the handler has a `files` key, all patterns in that array are matched against the file - system, and a parcel is entered into the invoice for the corresponding file. The parcel - `label.name` is the relative path of the file to the `HIPPOFACTS` file.The parcel's - `conditions.memberOf` is set to a list of _all_ handler groups that contained patterns that - the file matched - this may be more than one if multiple handler file patterns matched the - same file. +Logging out can be performed with `hippo logout`, which logs out of Hippo. -For example, given the following file structure: - -``` -|- HIPPOFACTS -|- src -| |- main.rs -| |- utils.rs -|- bin -| |- cassowary.wasm -| |- kea.wasm -| |- kokako.wasm -| |- penguin.wasm -|- photo -| |- adelie.png -| |- emperor.png -| |- rockhopper.png -|- stock - |- kea.jpg - |- little-blue.jpg - |- little-blue.png - |- wipers.jpg +```console +$ hippo logout +Logged out ``` -the previous `HIPPOFACTS` would create the following invoice (omitting some details -and adding comments): - -```toml -bindleVersion = '1.0.0' - -[bindle] -name = 'birdsondemand' -version = '1.2.3-ivan-2021.05.31.16.49.09.990' -description = 'provides birds as a service' -authors = ['Joan Q Programmer'] - -# Parcels representing handler WASM modules have a `requires` attribute -# and a `wagi.route` feature, and a `wagi.entrypoint` if specified in -# the source spec - -[[parcel]] -[parcel.label] -sha256 = '0a4346f806b28b3ce94905c3ac56fcd5ee2337d8613161696aba52eb0c3551cc' -name = 'bin/penguin.wasm' -[parcel.label.feature.wagi] -file = 'false' -route = '/birds/flightless' -[parcel.conditions] -requires = ['bin/penguin.wasm-files'] +If you want to skip server TLS verification, pass the `-k` flag to `hippo +login`. This can be useful if you are running development services with +self-signed certificates. -[[parcel]] -[parcel.label] -sha256 = '1f71511371129511321c45be058c60e23cf9ba898d8a3f3309555985b5027490' -name = 'bin/cassowary.wasm' -[parcel.label.feature.wagi] -file = 'false' -route = '/birds/irritable/fighty' -[parcel.conditions] -requires = ['bin/cassowary.wasm-files'] +**Note: the `-k` and `--danger-accept-invalid-certs` flags are a security risk. +Do not use them in production.** -[[parcel]] -[parcel.label] -sha256 = 'bab02c178882085bf20defd15c0e8971edd95488a1ecb4a6273e6afcfb3c4030' -name = 'bin/kea.wasm' -[parcel.label.feature.wagi] -entrypoint = 'steal_wipers' -file = 'false' -route = '/birds/naughty' -[parcel.conditions] -requires = ['bin/kea.wasm-files'] +### Creating an Application -# Parcels derived from `files` patterns have a `memberOf` attribute and a -# `wagi.file` feature of "true" - -[[parcel]] -[parcel.label] -sha256 = 'e99f19705a23cbeeeade5d2b4f8b83fff09beb093552e82073cdb302ee10eb76' -name = 'photo/adelie.png' -[parcel.label.feature.wagi] -file = 'true' -[parcel.conditions] -memberOf = ['bin/penguin.wasm-files'] - -[[parcel]] -[parcel.label] -sha256 = 'e8f7b60dfe5ee560edd1ac616463a0682a0e7c57a5ce2a8fe5c0990e500d0ac5' -name = 'photo/rockhopper.png' -[parcel.label.feature.wagi] -file = 'true' -[parcel.conditions] -memberOf = ['bin/penguin.wasm-files'] - -[[parcel]] -[parcel.label] -sha256 = '843baaf5a63cbc38d4d4c00036b95e435254eece7480fb717c8a17dcdc2aeefc' -name = 'stock/little-blue.jpg' -[parcel.label.feature.wagi] -file = 'true' -[parcel.conditions] -memberOf = ['bin/penguin.wasm-files'] - -# Some files are matched by more than one handler's patterns - -[[parcel]] -[parcel.label] -sha256 = '6451ab5be799a6aa52ce8b8a084a12066bb2dd8e1a73a692627bb96b4b9a72f0' -name = 'stock/wipers.jpg' -[parcel.label.feature.wagi] -file = 'true' -[parcel.conditions] -memberOf = [ - 'bin/penguin.wasm-files', - 'bin/kea.wasm-files', -] - -[[parcel]] -[parcel.label] -sha256 = '93c3a391d842e3b8032d560db4870b5426c5c05a9f2a60b187e567ae69d8e658' -name = 'stock/kea.jpg' -[parcel.label.feature.wagi] -file = 'true' -[parcel.conditions] -memberOf = [ - 'bin/penguin.wasm-files', - 'bin/kea.wasm-files', -] - -# Group per handler - -[[group]] -name = 'bin/penguin.wasm-files' +```console +$ hippo app add helloworld helloworld +Added App helloworld (ID = 'e4a30d14-4536-4f4a-81d5-80e961e7710c') +IMPORTANT: save this App ID for later - you will need it to update and/or delete the App +``` -[[group]] -name = 'bin/cassowary.wasm-files' +### Creating a Channel -[[group]] -name = 'bin/kea.wasm-files' +```console +$ hippo channel add latest e4a30d14-4536-4f4a-81d5-80e961e7710c +Added Channel latest (ID = '685ff7d8-7eef-456f-ad5a-4c5c39975588') +IMPORTANT: save this Channel ID for later - you will need it to update and/or delete the Channel ``` -`hippo` does not currently support Bindle's `parcel.label.feature` or `signature` features. +If not specified, Hippo to deploys the latest revision. This can be changed by +either providing a different `--range-rule`, or by specifying a `--revision-id`. -### External handlers +By default, Hippo will bind the channel to a domain with the address +`..`. In this case, +`latest.helloworld.hippofactory.local`. If you want to change this domain, +use the `--domain` flag. -It is sometimes useful to have routes handled by 'library' parcels that perform common -functions like serving static assets from the filesystem. To do this, rather than -copying the Wasm handler locally, you can reference it directly from your HIPPOFACTS. -To do this: +### Creating a Revision -* The library parcel but have an annotation named `wagi_handler_id`. This is the ID by - which HIPPOFACTS will refer to it - this decouples the reference from volatile details - like parcel name or SHA. -* Instead of a `name` in your `handler` table, you specify a `bindleId` and `handlerId`. -* Do not specify an `entrypoint` - this is defined by the library parcel. +If you pushed a bindle to bindle-server called `helloworld/1.0.0`: -For example: - -```toml -[[handler]] -external.bindleId = "deislabs/fileserver/1.0.0" -external.handlerId = "static" -route = "/images" -files = ["birds/*.jpg"] +```console +$ hippo revision add helloworld 1.0.0 +Added Revision 1.0.0 ``` -The Hippo client will locate the specified `wagi_handler_id` in the given bindle, and create a -parcel in your invoice that points to the same blob but with a `requires` condition for -the handler group. It also creates parcels for any parcels that the handler `requires` -in its original bindle. - -### Reusable library modules +If any applications use that storage ID, all its channels will be re-evaluated +to determine if they need to be re-schedule the new revision to the job +scheduler. -To create a 'library' parcel that can be referenced as an external handler, provide an -`export` section. This is similar to a local handler except instead of a `route` it -has an `id` - this is the name by which it can be referenced (it gets mapped to the -`wagi_handler_id` annotation). For example: +### Adding an Environment Variable -```toml -[[export]] -name = "gallery.wasm" -id = "gallery" -files = ["cache/*.db"] +```console +$ hippo env add HELLO world 685ff7d8-7eef-456f-ad5a-4c5c39975588 +Added Environment Variable HELLO (ID = 'c97f9855-d998-4dac-889b-11b553f53bea') +IMPORTANT: save this Environment Variable ID for later - you will need it to update and/or delete the Environment Variable ``` -**NOTE:** If your spec consists only of exports, you should not notify Hippo, because -there will be no application mapped to the resultant bindle. Pass `-a bindle` to -push to the Bindle server but not register it with Hippo. - -## Running the Hippo Client - -As a developer you can run `hippo push .` in your `HIPPOFACTS` directory to -assemble all matching files and publish them as a bindle. In this mode, -`hippo`: - -* Mangles the version with a prerelease segment -* Stages to a temporary directory -* Pushes to the Bindle server -* Notifies Hippo that a new bindle version is available - -Authentication is handled through two commands: - -- `hippo auth login`, which logs into Hippo -- `hippo bindle login`, which logs into Bindle - -With `hippo auth login`, the Hippo URL is specified in the `--url` flag. Hippo requires authentication: -if `--username` or `--password` are not provided, the CLI will prompt for that information. - -With `hippo bindle login`, the Bindle server is specified with the `--url` flag. If the Bindle server -requires authentication, specify this via the `--username` and `--password` options. Note that Bindle -authentication is independent of Hippo authentication, and in some cases (e.g. if `bindle-server` is -provided the `--unauthenticated` flag), no authentication is necessary! - -If you want to review the proposed bindle rather than pushing it, pass -`hippo bindle prepare -d .`. This will stage the bindle to the specified directory but -_not_ push it. If you want to push the generated bindle but not notify Hippo, use -`hippo bindle push .`. - -In a CI environment you can supply the `-v production` option to suppress version mangling. -This will create and upload the bindle with the version from `HIPPOFACTS`, without the -prerelease segment. - -If you want to skip server TLS verification, pass the `-k` flag to either `login` command. This can be -useful if you are running development services with self-signed certificates. -**This is a security risk: do not use it in production.** - -Logging out can be performed with - -- `hippo auth logout`, which logs out of Hippo -- `hippo bindle logout`, which logs out of Bindle - ## Building from source -* Known link failure on WSL: workaround is to build once with `RUSTFLAGS='-C opt-level=0' cargo build` -(after which plain `cargo build` seems to work) +```console +cargo build --release +``` ## Contributing -This project welcomes contributions and suggestions. Most contributions require you to agree to a -Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us -the rights to use your contribution. For details, visit https://cla.microsoft.com. - -When you submit a pull request, a CLA-bot will automatically determine whether you need to provide -a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions -provided by the bot. You will only need to do this once across all repos using our CLA. - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). -For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or -contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +This project welcomes contributions and suggestions. Most contributions require +you to agree to a Contributor License Agreement (CLA) declaring that you have +the right to, and actually do, grant us the rights to use your contribution. For +details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether +you need to provide a CLA and decorate the PR appropriately (e.g., label, +comment). Simply follow the instructions provided by the bot. You will only need +to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of +Conduct](https://opensource.microsoft.com/codeofconduct/). For more information +see the [Code of Conduct +FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact +[opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional +questions or comments. diff --git a/src/bindle/client.rs b/src/bindle/client.rs deleted file mode 100644 index 333790a..0000000 --- a/src/bindle/client.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::sync::Arc; - -use bindle::client::{ - tokens::{HttpBasic, NoToken, TokenManager}, - Client, ClientBuilder, -}; - -pub struct ConnectionInfo { - base_url: String, - allow_insecure: bool, - token_manager: AnyAuth, -} - -impl ConnectionInfo { - pub fn new>( - base_url: I, - allow_insecure: bool, - username: Option, - password: Option, - ) -> Self { - let token_manager: Box = match (username, password) { - (Some(u), Some(p)) => Box::new(HttpBasic::new(&u, &p)), - _ => Box::new(NoToken::default()), - }; - - Self { - base_url: base_url.into(), - allow_insecure, - token_manager: AnyAuth { - token_manager: Arc::new(token_manager), - }, - } - } - - pub fn client(&self) -> bindle::client::Result> { - let builder = ClientBuilder::default() - .http2_prior_knowledge(false) - .danger_accept_invalid_certs(self.allow_insecure); - builder.build(&self.base_url, self.token_manager.clone()) - } -} - -#[derive(Clone)] -pub struct AnyAuth { - token_manager: Arc>, -} - -#[async_trait::async_trait] -impl TokenManager for AnyAuth { - async fn apply_auth_header( - &self, - builder: reqwest::RequestBuilder, - ) -> bindle::client::Result { - self.token_manager.apply_auth_header(builder).await - } -} diff --git a/src/bindle/mod.rs b/src/bindle/mod.rs deleted file mode 100644 index ca3b5a8..0000000 --- a/src/bindle/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod client; -pub mod pusher; -pub mod util; -pub mod writer; diff --git a/src/bindle/pusher.rs b/src/bindle/pusher.rs deleted file mode 100644 index 30daacf..0000000 --- a/src/bindle/pusher.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::path::Path; - -use bindle::standalone::StandaloneRead; - -use super::client::ConnectionInfo; - -pub async fn push_all( - path: impl AsRef, - bindle_id: &bindle::Id, - bindle_connection: &ConnectionInfo, -) -> anyhow::Result<()> { - let reader = StandaloneRead::new(&path, bindle_id).await?; - let client = bindle_connection.client()?; - reader - .push(&client) - .await - .map_err(|e| anyhow::anyhow!("Error pushing bindle to server: {}", e))?; - Ok(()) -} diff --git a/src/bindle/util.rs b/src/bindle/util.rs deleted file mode 100644 index 31e1032..0000000 --- a/src/bindle/util.rs +++ /dev/null @@ -1,80 +0,0 @@ -use itertools::Itertools; - -pub trait ParcelHelpers { - fn has_annotation(&self, key: &str) -> bool; - fn requires(&self) -> Vec; - fn is_member_of(&self, group: &str) -> bool; -} - -pub trait InvoiceHelpers { - fn parcels_in(&self, group: &str) -> Vec; - fn parcels_required_by(&self, parcel: &bindle::Parcel) -> Vec; -} - -impl ParcelHelpers for bindle::Parcel { - fn has_annotation(&self, key: &str) -> bool { - match self.label.annotations.as_ref() { - None => false, - Some(map) => map.contains_key(key), - } - } - - fn requires(&self) -> Vec { - match self.conditions.as_ref() { - None => vec![], - Some(conditions) => match conditions.requires.as_ref() { - None => vec![], - Some(groups) => groups.clone(), - }, - } - } - - fn is_member_of(&self, group: &str) -> bool { - match self.conditions.as_ref() { - None => false, - Some(conditions) => match conditions.member_of.as_ref() { - None => false, - Some(groups) => groups.contains(&group.to_owned()), - }, - } - } -} - -impl InvoiceHelpers for bindle::Invoice { - fn parcels_in(&self, group: &str) -> Vec { - match self.parcel.as_ref() { - None => vec![], - Some(parcels) => parcels - .iter() - .filter(|p| p.is_member_of(group)) - .cloned() - .collect(), - } - } - - fn parcels_required_by(&self, parcel: &bindle::Parcel) -> Vec { - parcels_required_by_acc(self, parcel.requires(), vec![]) - .into_iter() - .unique_by(|p| p.label.sha256.clone()) - .collect_vec() - } -} - -fn parcels_required_by_acc( - invoice: &bindle::Invoice, - mut groups: Vec, - mut acc: Vec, -) -> Vec { - match groups.pop() { - None => acc, - Some(group) => { - let mut members = invoice.parcels_in(&group); - let mut required_groups: Vec<_> = - members.iter().flat_map(|p| p.requires()).unique().collect(); - acc.append(&mut members); - groups.append(&mut required_groups); - let new_groups = groups.into_iter().unique().collect(); - parcels_required_by_acc(invoice, new_groups, acc) - } - } -} diff --git a/src/bindle/writer.rs b/src/bindle/writer.rs deleted file mode 100644 index cc687b0..0000000 --- a/src/bindle/writer.rs +++ /dev/null @@ -1,69 +0,0 @@ -use bindle::{Invoice, Parcel}; - -use std::path::{Path, PathBuf}; - -use super::util::ParcelHelpers; - -pub struct Writer { - source_base_path: PathBuf, - dest_base_path: PathBuf, -} - -impl Writer { - pub fn new(source_base_path: impl AsRef, dest_base_path: impl AsRef) -> Self { - Self { - source_base_path: source_base_path.as_ref().to_path_buf(), - dest_base_path: dest_base_path.as_ref().to_path_buf(), - } - } - - pub async fn write(&self, invoice: &Invoice) -> anyhow::Result<()> { - // This is very similar to bindle::StandaloneWrite::write but... not quite the same - let bindle_id_hash = invoice.bindle.id.sha(); - let bindle_dir = self.dest_base_path.join(bindle_id_hash); - let parcels_dir = bindle_dir.join("parcels"); - tokio::fs::create_dir_all(&parcels_dir).await?; - - self.write_invoice_file(invoice, &bindle_dir).await?; - self.write_parcel_files(invoice, &parcels_dir).await?; - Ok(()) - } - - async fn write_invoice_file(&self, invoice: &Invoice, bindle_dir: &Path) -> anyhow::Result<()> { - let invoice_text = toml::to_string_pretty(&invoice)?; - let invoice_file = bindle_dir.join("invoice.toml"); - tokio::fs::write(&invoice_file, &invoice_text).await?; - Ok(()) - } - - async fn write_parcel_files( - &self, - invoice: &Invoice, - parcels_dir: &Path, - ) -> anyhow::Result<()> { - let parcels = match &invoice.parcel { - Some(p) => p, - None => return Ok(()), - }; - - let parcel_writes = parcels - .iter() - .map(|parcel| self.write_one_parcel(parcels_dir, parcel)); - futures::future::join_all(parcel_writes) - .await - .into_iter() - .collect::>>()?; - Ok(()) - } - - async fn write_one_parcel(&self, parcels_dir: &Path, parcel: &Parcel) -> anyhow::Result<()> { - if parcel.has_annotation("hippos_do_not_stage") { - return Ok(()); - } - let source_file = self.source_base_path.join(&parcel.label.name); - let hash = &parcel.label.sha256; - let dest_file = parcels_dir.join(format!("{}.dat", hash)); - tokio::fs::copy(&source_file, &dest_file).await?; - Ok(()) - } -} diff --git a/src/cli/commands/auth.rs b/src/cli/commands/auth.rs deleted file mode 100644 index 21ba0aa..0000000 --- a/src/cli/commands/auth.rs +++ /dev/null @@ -1,42 +0,0 @@ -use clap::Subcommand; - -#[derive(Subcommand)] -pub(crate) enum Commands { - /// Create a new Hippo account - Register { - /// The Hippo URL - #[clap(env = "HIPPO_URL", long, default_value = "https://localhost:5309")] - url: String, - /// The username - #[clap(env = "HIPPO_USERNAME", long)] - username: Option, - /// The password - #[clap(env = "HIPPO_PASSWORD", long)] - password: Option, - /// Should invalid TLS certificates be accepted by the client? - #[clap(env, short = 'k', long)] - danger_accept_invalid_certs: bool, - }, - - /// Log into Hippo - Login { - /// The URL to log into Hippo - #[clap(env = "HIPPO_URL", long, default_value = "https://localhost:5309")] - url: String, - /// The username to log into Hippo - #[clap(env = "HIPPO_USERNAME", long)] - username: Option, - /// The password to log into Hippo - #[clap(env = "HIPPO_PASSWORD", long)] - password: Option, - /// Should invalid TLS certificates be accepted by the client? - #[clap(env, short = 'k', long)] - danger_accept_invalid_certs: bool, - }, - - /// End the current Hippo login session - Logout {}, - - /// prints the logged in user - Whoami {}, -} diff --git a/src/cli/commands/bindle.rs b/src/cli/commands/bindle.rs deleted file mode 100644 index 49b76be..0000000 --- a/src/cli/commands/bindle.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::path::PathBuf; - -use clap::Subcommand; - -#[derive(Subcommand)] -#[clap(alias ="b")] -pub(crate) enum Commands { - /// Prepare a bindle, but write it to disk instead of sending it over the network - #[clap(alias ="prep")] - Prepare { - /// The artifacts spec (file or directory containing HIPPOFACTS file) - #[clap(parse(from_os_str), default_value = ".")] - path: PathBuf, - - /// How to version the generated invoice - #[clap( - short = 'v', - long, - default_value = "development", - possible_values(super::INVOICE_VERSION_ACCEPTED_VALUES) - )] - invoice_version: String, - - /// Where should the bindle be written to - #[clap(short, long, parse(from_os_str), default_value = ".hippo")] - destination: PathBuf, - }, - - /// Package and upload Hippo artifacts without notifying Hippo - #[clap(alias ="p")] - Push { - /// The artifacts spec (file or directory containing HIPPOFACTS file) - #[clap(parse(from_os_str), default_value = ".")] - path: PathBuf, - - /// How to version the generated invoice - #[clap( - short = 'v', - long, - default_value = "development", - possible_values(super::INVOICE_VERSION_ACCEPTED_VALUES) - )] - invoice_version: String, - }, - /// Log into Bindle - Login { - /// The URL to log into Bindle - #[clap(env = "BINDLE_URL", long, default_value = "http://localhost:8080/v1")] - url: String, - /// The username to log into Bindle - #[clap(env = "BINDLE_USERNAME", long)] - username: Option, - /// The password to log into Bindle - #[clap(env = "BINDLE_PASSWORD", long)] - password: Option, - /// Should invalid TLS certificates be accepted by the client? - #[clap(env, short = 'k', long)] - danger_accept_invalid_certs: bool, - }, - - /// End the current Bindle login session - Logout {}, -} diff --git a/src/cli/commands/mod.rs b/src/cli/commands/mod.rs index 25d1598..e1decc7 100644 --- a/src/cli/commands/mod.rs +++ b/src/cli/commands/mod.rs @@ -1,16 +1,10 @@ pub(crate) mod app; -pub(crate) mod auth; -pub(crate) mod bindle; pub(crate) mod certificate; pub(crate) mod channel; pub(crate) mod environment_variable; -pub(crate) mod new; pub(crate) mod revision; -use clap::{AppSettings, Subcommand}; -use std::path::PathBuf; - -const INVOICE_VERSION_ACCEPTED_VALUES: &[&str] = &["dev", "development", "prod", "production"]; +use clap::Subcommand; #[derive(Subcommand)] pub(crate) enum Commands { @@ -18,14 +12,6 @@ pub(crate) enum Commands { #[clap(subcommand)] App(app::Commands), - /// Register new accounts and log in/out of Hippo - #[clap(subcommand)] - Auth(auth::Commands), - - /// Register new accounts and log in/out of Hippo - #[clap(subcommand)] - Bindle(bindle::Commands), - /// Add, update, and remove TLS Certificate #[clap(subcommand)] Certificate(certificate::Commands), @@ -38,28 +24,45 @@ pub(crate) enum Commands { #[clap(subcommand)] Env(environment_variable::Commands), - /// Create project-specific files - #[clap(subcommand)] - New(new::Commands), + /// Log into Hippo + Login { + /// The URL to log into Hippo + #[clap(env = "HIPPO_URL", long, default_value = "https://localhost:5309")] + url: String, + /// The username to log into Hippo + #[clap(env = "HIPPO_USERNAME", long)] + username: Option, + /// The password to log into Hippo + #[clap(env = "HIPPO_PASSWORD", long)] + password: Option, + /// Should invalid TLS certificates be accepted by the client? + #[clap(env, short = 'k', long)] + danger_accept_invalid_certs: bool, + }, + + /// End the current Hippo login session + Logout {}, + + /// Create a new Hippo account + Register { + /// The Hippo URL + #[clap(env = "HIPPO_URL", long, default_value = "https://localhost:5309")] + url: String, + /// The username + #[clap(env = "HIPPO_USERNAME", long)] + username: Option, + /// The password + #[clap(env = "HIPPO_PASSWORD", long)] + password: Option, + /// Should invalid TLS certificates be accepted by the client? + #[clap(env, short = 'k', long)] + danger_accept_invalid_certs: bool, + }, /// Add and remove revisions #[clap(subcommand)] Revision(revision::Commands), - /// Package and upload Hippo artifacts, notifying Hippo - #[clap(setting(AppSettings::ArgRequiredElseHelp))] - Push { - /// The artifacts spec (file or directory containing HIPPOFACTS file) - #[clap(parse(from_os_str), default_value = ".")] - path: PathBuf, - - /// How to version the generated invoice - #[clap( - short = 'v', - long, - default_value = "development", - possible_values(INVOICE_VERSION_ACCEPTED_VALUES) - )] - invoice_version: String, - }, + /// prints the logged in user + Whoami {}, } diff --git a/src/cli/commands/new.rs b/src/cli/commands/new.rs deleted file mode 100644 index 5270aeb..0000000 --- a/src/cli/commands/new.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::path::PathBuf; - -use clap::Subcommand; - -#[derive(Subcommand)] -pub(crate) enum Commands { - /// Creates a new hippo project with a HIPPOFACTS file - Hippofacts { - // The name of the new application - name: String, - - /// The directory or file into which the HIPPOFACTS file should be written. - /// - /// If this is a directory, a HIPPOFACTS file will be written to the directory. Otherwise, a new file will be created with the given name. - #[clap( - short, - long, - parse(from_os_str), - value_name = "FILE_OR_DIR", - default_value = "." - )] - destination: PathBuf, - - /// The name(s) and email(s) of the author(s): 'First Last ' - #[clap(short, long)] - authors: Vec, - - /// The path to the Wasm module. Example: 'bin/main.wasm' - #[clap( - short, - long, - parse(from_os_str), - value_name = "MODULE.WASM", - default_value = "main.wasm" - )] - module: PathBuf, - }, -} diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 0be339c..0b6218a 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -1,30 +1,20 @@ mod commands; use commands::{ - app::Commands as AppCommands, auth::Commands as AuthCommands, - bindle::Commands as BindleCommands, - certificate::Commands as CertificateCommands, channel::Commands as ChannelCommands, - environment_variable::Commands as EnvCommands, new::Commands as NewCommands, + app::Commands as AppCommands, certificate::Commands as CertificateCommands, + channel::Commands as ChannelCommands, environment_variable::Commands as EnvCommands, revision::Commands as RevisionCommands, Commands, }; -use itertools::Itertools; -use crate::{ - bindle::{client::ConnectionInfo as BindleConnectionInfo, pusher::push_all, writer::Writer}, - expander::{ExpansionContext, InvoiceVersioning}, - hippo::{Client, ConnectionInfo}, - hippofacts::{BindleSpec, HippoFacts, HippoFactsEntry, RawHandler, RawHippoFacts}, -}; +use crate::hippo::{Client, ConnectionInfo}; use clap::Parser; use dialoguer::{Input, Password}; use dirs::config_dir; use hippo_openapi::models::{ChannelRevisionSelectionStrategy, TokenInfo}; -use log::{warn, LevelFilter}; +use log::LevelFilter; use serde::{Deserialize, Serialize}; use std::{ - collections::HashMap, - env::{current_dir, temp_dir}, fs::{self, File}, io::BufReader, path::PathBuf, @@ -59,25 +49,6 @@ impl Default for HippoConfig { } } -#[derive(Serialize, Deserialize)] -struct BindleConfig { - danger_accept_invalid_certs: bool, - username: Option, - password: Option, - url: String, -} - -impl Default for BindleConfig { - fn default() -> Self { - Self { - url: "http://localhost:8080/v1".to_owned(), - username: None, - password: None, - danger_accept_invalid_certs: false, - } - } -} - /// The Hippo commandline client #[derive(Parser)] #[clap(name = "hippo")] @@ -106,15 +77,6 @@ impl Cli { ), }; - let bindle_config_path = match &self.config { - Some(p) => p.clone(), - None => PathBuf::from( - config_dir() - .map(|h| h.join("hippo").join("bindle.json")) - .unwrap(), - ), - }; - // TODO: switch from std::fs to tokio::fs once serde_json implements tokio support // https://github.com/serde-rs/json/issues/316 let mut hippo_conf: HippoConfig = Default::default(); @@ -124,13 +86,6 @@ impl Cli { hippo_conf = serde_json::from_reader(reader)?; } - let mut bindle_conf: BindleConfig = Default::default(); - if bindle_config_path.exists() { - let file = File::open(bindle_config_path.clone())?; - let reader = BufReader::new(file); - bindle_conf = serde_json::from_reader(reader)?; - } - let mut builder = env_logger::builder(); builder.parse_default_env(); builder.filter_level(match self.verbose { @@ -150,20 +105,13 @@ impl Cli { api_key: hippo_conf.token_info.map_or(None, |t| t.token), }); - let bindle_connection_info = BindleConnectionInfo::new( - bindle_conf.url, - bindle_conf.danger_accept_invalid_certs, - bindle_conf.username, - bindle_conf.password, - ); - match &self.command { Commands::App(AppCommands::Add { name, storage_id }) => { let id = hippo_client .add_app(name.to_owned(), storage_id.to_owned()) .await?; println!("Added App {} (ID = '{}')", name, id); - println!("IMPORTANT: save this App ID for later - you will need it to update and/or delete the App (for now)"); + println!("IMPORTANT: save this App ID for later - you will need it to update and/or delete the App"); } Commands::App(AppCommands::Remove { id }) => { @@ -171,126 +119,6 @@ impl Cli { println!("Removed App {}", id); } - Commands::Auth(AuthCommands::Register { - url, - username, - password, - danger_accept_invalid_certs, - }) => { - let uname: String = match username { - Some(u) => u.to_owned(), - None => Input::new().with_prompt("Enter username").interact_text()?, - }; - let pword: String = match password { - Some(p) => p.to_owned(), - None => Password::new() - .with_prompt("Enter password") - .with_confirmation("Confirm password", "Passwords do not match") - .interact()?, - }; - let hippo_client = Client::new(ConnectionInfo { - url: url.to_owned(), - danger_accept_invalid_certs: *danger_accept_invalid_certs, - api_key: None, - }); - hippo_client.register(uname.clone(), pword).await?; - println!("Registered {}", uname); - } - - Commands::Auth(AuthCommands::Login { - url, - username, - password, - danger_accept_invalid_certs, - }) => { - let h_username: String = match username { - Some(u) => u.to_owned(), - None => Input::new() - .with_prompt("Enter username") - .interact_text()?, - }; - let h_password: String = match password { - Some(p) => p.to_owned(), - None => Password::new() - .with_prompt("Enter password") - .interact()?, - }; - let hippo_client = Client::new(ConnectionInfo { - url: url.to_owned(), - danger_accept_invalid_certs: *danger_accept_invalid_certs, - api_key: None, - }); - let token = hippo_client.login(h_username.clone(), h_password).await?; - hippo_conf.danger_accept_invalid_certs = *danger_accept_invalid_certs; - hippo_conf.username = h_username; - hippo_conf.url = url.to_owned(); - hippo_conf.token_info = Some(token); - if !hippo_config_path.exists() && hippo_config_path.ancestors().count() != 0 { - fs::create_dir_all(hippo_config_path.parent().unwrap())?; - } - serde_json::to_writer(File::create(hippo_config_path)?, &hippo_conf)?; - println!("Logged in as {}", hippo_conf.username); - } - - Commands::Auth(AuthCommands::Logout {}) => { - hippo_conf = Default::default(); - if !hippo_config_path.exists() && hippo_config_path.ancestors().count() != 0 { - fs::create_dir_all(hippo_config_path.parent().unwrap())?; - } - serde_json::to_writer(File::create(hippo_config_path)?, &hippo_conf)?; - } - - Commands::Auth(AuthCommands::Whoami {}) => { - println!("{}", hippo_conf.username); - } - - Commands::Bindle(BindleCommands::Login { url, username, password, danger_accept_invalid_certs }) => { - bindle_conf.danger_accept_invalid_certs = *danger_accept_invalid_certs; - bindle_conf.username = username.to_owned(); - bindle_conf.password = password.to_owned(); - bindle_conf.url = url.to_owned(); - if !bindle_config_path.exists() && bindle_config_path.ancestors().count() != 0 { - fs::create_dir_all(bindle_config_path.parent().unwrap())?; - } - serde_json::to_writer(File::create(&bindle_config_path)?, &bindle_conf)?; - println!("Configuration written to {}", bindle_config_path.as_path().to_string_lossy()); - } - - Commands::Bindle(BindleCommands::Logout {}) => { - bindle_conf = Default::default(); - if !bindle_config_path.exists() && bindle_config_path.ancestors().count() != 0 { - fs::create_dir_all(bindle_config_path.parent().unwrap())?; - } - serde_json::to_writer(File::create(bindle_config_path)?, &bindle_conf)?; - } - - Commands::Bindle(BindleCommands::Prepare { - path, - invoice_version, - destination, - }) => { - let invoice = - prepare(path, invoice_version, &bindle_connection_info, destination).await?; - - println!( - "Wrote {} to {}", - &invoice.bindle.id, - destination.as_os_str().to_string_lossy() - ); - } - - Commands::Bindle(BindleCommands::Push { - path, - invoice_version, - }) => { - let destination = temp_dir().join("hippo-staging"); - let invoice = - prepare(path, invoice_version, &bindle_connection_info, &destination).await?; - - push_all(&destination, &invoice.bindle.id, &bindle_connection_info).await?; - println!("Pushed {}", &invoice.bindle.id); - } - Commands::Certificate(CertificateCommands::Add { name, public_key_path, @@ -303,7 +131,7 @@ impl Cli { .add_certificate(name.to_owned(), public_key, private_key) .await?; println!("Added Certificate {} (ID = '{}')", name, id); - println!("IMPORTANT: save this Certificate ID for later - you will need it to update and/or delete the Certificate (for now)"); + println!("IMPORTANT: save this Certificate ID for later - you will need it to update and/or delete the Certificate"); } Commands::Certificate(CertificateCommands::Remove { id }) => { @@ -325,7 +153,7 @@ impl Cli { let revision_selection_strategy = match (range_rule, revision_id) { (Some(_), None) => ChannelRevisionSelectionStrategy::_0, (None, Some(_)) => ChannelRevisionSelectionStrategy::_1, - _ => ChannelRevisionSelectionStrategy::_0 + _ => ChannelRevisionSelectionStrategy::_0, }; let id = hippo_client .add_channel( @@ -339,7 +167,7 @@ impl Cli { ) .await?; println!("Added Channel {} (ID = '{}')", name, id); - println!("IMPORTANT: save this Channel ID for later - you will need it to update and/or delete the Channel (for now)"); + println!("IMPORTANT: save this Channel ID for later - you will need it to update and/or delete the Channel"); } Commands::Channel(ChannelCommands::Remove { id }) => { @@ -360,7 +188,7 @@ impl Cli { ) .await?; println!("Added Environment Variable {} (ID = '{}')", key, id); - println!("IMPORTANT: save this Environment Variable ID for later - you will need it to update and/or delete the Environment Variable (for now)"); + println!("IMPORTANT: save this Environment Variable ID for later - you will need it to update and/or delete the Environment Variable"); } Commands::Env(EnvCommands::Remove { id }) => { @@ -370,52 +198,70 @@ impl Cli { println!("Removed Environment Variable {}", id); } - Commands::New(NewCommands::Hippofacts { - name, - destination, - authors, - module, - }) => { - let handler = RawHandler { - name: Some(module.as_os_str().to_string_lossy().to_string()), - entrypoint: None, - route: "/".to_owned(), - files: None, - external: None, + Commands::Login { + url, + username, + password, + danger_accept_invalid_certs, + } => { + let h_username: String = match username { + Some(u) => u.to_owned(), + None => Input::new().with_prompt("Enter username").interact_text()?, }; - // if dir is a directory, join with HIPPOFACTS. Otherwise, use it as a file name. - let md = tokio::fs::metadata(&destination).await?; - let dest = if md.is_dir() { - PathBuf::from(&destination).join("HIPPOFACTS") - } else { - PathBuf::from(&destination) + let h_password: String = match password { + Some(p) => p.to_owned(), + None => Password::new().with_prompt("Enter password").interact()?, }; + let hippo_client = Client::new(ConnectionInfo { + url: url.to_owned(), + danger_accept_invalid_certs: *danger_accept_invalid_certs, + api_key: None, + }); + let token = hippo_client.login(h_username.clone(), h_password).await?; + hippo_conf.danger_accept_invalid_certs = *danger_accept_invalid_certs; + hippo_conf.username = h_username; + hippo_conf.url = url.to_owned(); + hippo_conf.token_info = Some(token); + if !hippo_config_path.exists() && hippo_config_path.ancestors().count() != 0 { + fs::create_dir_all(hippo_config_path.parent().unwrap())?; + } + serde_json::to_writer(File::create(hippo_config_path)?, &hippo_conf)?; + println!("Logged in as {}", hippo_conf.username); + } - // Don't overwrite an existing HIPPOFACTS - match tokio::fs::metadata(&dest).await { - Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()), - Err(e) => Err(e), - Ok(_) => { - anyhow::bail!( - "Cowardly refusing to overwrite file. Remove HIPPOFACTS first." - ) - } - }?; + Commands::Logout {} => { + hippo_conf = Default::default(); + if !hippo_config_path.exists() && hippo_config_path.ancestors().count() != 0 { + fs::create_dir_all(hippo_config_path.parent().unwrap())?; + } + serde_json::to_writer(File::create(hippo_config_path)?, &hippo_conf)?; + println!("Logged out"); + } - let hippofacts = RawHippoFacts { - bindle: BindleSpec { - name: name.to_owned(), - version: "0.1.0".to_owned(), - description: None, - authors: Some(authors.to_owned()), - }, - annotations: None, - export: None, - handler: Some(vec![handler]), + Commands::Register { + url, + username, + password, + danger_accept_invalid_certs, + } => { + let uname: String = match username { + Some(u) => u.to_owned(), + None => Input::new().with_prompt("Enter username").interact_text()?, }; - - let data = toml::to_vec(&hippofacts)?; - tokio::fs::write(dest, data).await?; + let pword: String = match password { + Some(p) => p.to_owned(), + None => Password::new() + .with_prompt("Enter password") + .with_confirmation("Confirm password", "Passwords do not match") + .interact()?, + }; + let hippo_client = Client::new(ConnectionInfo { + url: url.to_owned(), + danger_accept_invalid_certs: *danger_accept_invalid_certs, + api_key: None, + }); + hippo_client.register(uname.clone(), pword).await?; + println!("Registered {}", uname); } Commands::Revision(RevisionCommands::Add { @@ -428,155 +274,11 @@ impl Cli { println!("Added Revision {}", revision_number); } - Commands::Push { - path, - invoice_version, - } => { - let destination = temp_dir().join("hippo-staging"); - let invoice = - prepare(path, invoice_version, &bindle_connection_info, &destination).await?; - - push_all(&destination, &invoice.bindle.id, &bindle_connection_info).await?; - hippo_client - .add_revision( - invoice.bindle.id.name().to_string(), - invoice.bindle.id.version_string(), - ) - .await?; - - println!("Pushed {}", &invoice.bindle.id); + Commands::Whoami {} => { + println!("{}", hippo_conf.username); } } Ok(()) } } - -async fn prepare( - path: &PathBuf, - invoice_version: &String, - bindle_connection_info: &BindleConnectionInfo, - destination: &PathBuf, -) -> Result { - let path = current_dir()?.join(path); - let invoice_versioning = InvoiceVersioning::parse(invoice_version)?; - let hippofacts_filepath = hippofacts_file_path(path.to_path_buf())?; - let spec = HippoFacts::read_from(hippofacts_filepath)?; - let external_invoices = prefetch_required_invoices(&spec, Some(bindle_connection_info)).await?; - let expansion_context = ExpansionContext { - relative_to: path.clone(), - invoice_versioning, - external_invoices, - }; - let (invoice, warnings) = crate::expander::expand(&spec, &expansion_context)?.into(); - for warning in &warnings { - warn!("{}", warning); - } - let writer = Writer::new(&path, &destination); - writer.write(&invoice).await?; - Ok(invoice) -} - -fn hippofacts_file_path(source: PathBuf) -> anyhow::Result { - if source.is_dir() { - find_hippofacts_file_in(&source) - } else if source.is_file() { - Ok(source) - } else { - Err(anyhow::anyhow!( - "Artifacts spec not found: file {} does not exist", - source.to_string_lossy() - )) - } -} - -// The list of filenames to look for has to take case sensitivity -// into account. -#[cfg(target_os = "windows")] -const SPEC_FILENAMES: &[&str] = &["HIPPOFACTS", "hippofacts.toml"]; -// TODO: apparently there is a config option to make Mac filesystems -// case sensitive; fml. -#[cfg(target_os = "macos")] -const SPEC_FILENAMES: &[&str] = &["HIPPOFACTS", "hippofacts.toml"]; -#[cfg(target_os = "linux")] -const SPEC_FILENAMES: &[&str] = &[ - "HIPPOFACTS", - "hippofacts", - "Hippofacts", - "HIPPOFACTS.toml", - "hippofacts.toml", - "Hippofacts.toml", -]; - -fn find_hippofacts_file_in(source_dir: &PathBuf) -> anyhow::Result { - let candidates = SPEC_FILENAMES - .iter() - .flat_map(|f| { - let source = source_dir.join(f); - if source.is_file() { - Some(source) - } else { - None - } - }) - .collect_vec(); - - match candidates.len() { - 0 => Err(anyhow::anyhow!( - "No artifacts spec not found in directory {}: create a HIPPOFACTS file", - source_dir.to_string_lossy() - )), - 1 => Ok(candidates[0].clone()), - _ => Err(anyhow::anyhow!( - "Multiple artifacts specs found in directory {}: pass a specific file", - source_dir.to_string_lossy() - )), - } -} - -/// Pre-fetch any invoices that are referenced in the HIPPOFACTS. -async fn prefetch_required_invoices( - hippofacts: &HippoFacts, - bindle_client_factory: Option<&BindleConnectionInfo>, -) -> anyhow::Result> { - let mut map = HashMap::new(); - - let external_refs: Vec = hippofacts - .entries - .iter() - .flat_map(external_bindle_id) - .collect(); - if external_refs.is_empty() { - return Ok(map); - } - - let client = bindle_client_factory - .as_ref() - .ok_or_else(|| { - anyhow::anyhow!( - "Spec file contains external references but Bindle server URL is not set" - ) - })? - .client()?; - - for external_ref in external_refs { - let invoice = client - .get_yanked_invoice(&external_ref) - .await - .map_err(|e| { - anyhow::anyhow!( - "Error retrieving external reference {}: {}", - external_ref, - e - ) - })?; - map.insert(external_ref, invoice); - } - - Ok(map) -} - -/// Calculate the external Bindle ID from hippofacts data. -fn external_bindle_id(entry: &HippoFactsEntry) -> Option { - entry.external_ref().map(|ext| ext.bindle_id) -} diff --git a/src/expander.rs b/src/expander.rs deleted file mode 100644 index 40a3dd6..0000000 --- a/src/expander.rs +++ /dev/null @@ -1,1124 +0,0 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; -use std::convert::TryFrom; -use std::iter::FromIterator; -use std::path::{Path, PathBuf}; - -use bindle::{AnnotationMap, BindleSpec, Condition, Group, Invoice, Label, Parcel}; -use glob::GlobError; -use itertools::Itertools; -use sha2::{Digest, Sha256}; - -use crate::bindle::util::InvoiceHelpers; -use crate::hippofacts::{ - Export, ExternalHandler, ExternalRef, HippoFacts, HippoFactsEntry, LocalHandler, -}; -use crate::warnings::{Unwarn, WarnContext, Warned}; - -pub struct ExpansionContext { - pub relative_to: PathBuf, - pub invoice_versioning: InvoiceVersioning, - pub external_invoices: HashMap, -} - -impl ExpansionContext { - pub fn to_absolute(&self, pattern: &str) -> String { - let absolute = self.relative_to.join(pattern); - absolute.to_string_lossy().to_string() - } - - pub fn to_relative(&self, path: impl AsRef) -> anyhow::Result { - let relative_path = path.as_ref().strip_prefix(&self.relative_to)?; - let relative_path_string = relative_path - .to_str() - .ok_or_else(|| anyhow::Error::msg("Can't convert back to relative path"))? - .to_owned() - .replace("\\", "/"); // TODO: a better way - Ok(relative_path_string) - } - - pub fn mangle_version(&self, version: &str) -> String { - match self.invoice_versioning { - InvoiceVersioning::Dev => { - let user = current_user() - .map(|s| format!("-{}", s)) - .unwrap_or_else(|| "".to_owned()); - let timestamp = chrono::Local::now() - // We format the timestamp without separators/subsections, in order - // to avoid the possibility of a subsection leading with a zero, which - // breaks semver compliance. - .format("-%Y%m%d%H%M%S%3f") - .to_string(); - format!("{}{}{}", version, user, timestamp) - } - InvoiceVersioning::Production => version.to_owned(), - } - } -} - -pub enum InvoiceVersioning { - Dev, - Production, -} - -impl InvoiceVersioning { - pub fn parse(text: &str) -> anyhow::Result { - if text == "production" || text == "prod" { - Ok(InvoiceVersioning::Production) - } else if text == "development" || text == "dev" { - Ok(InvoiceVersioning::Dev) - } else { - Err(anyhow::anyhow!( - "Invalid invoice versioning strategy: choose 'dev' or 'production'" - )) - } - } -} - -pub fn expand( - hippofacts: &HippoFacts, - expansion_context: &ExpansionContext, -) -> anyhow::Result> { - WarnContext::run(|wc| { - let groups = expand_all_entries_to_groups(hippofacts)?; - let handler_parcels = expand_module_entries_to_parcels(hippofacts, expansion_context)?; - let external_dependent_parcels = - expand_all_external_ref_dependencies_to_parcels(hippofacts, expansion_context)?; - let file_parcels = expand_all_files_to_parcels(hippofacts, expansion_context)?.unwarn(wc); - check_for_name_clashes(&external_dependent_parcels, &file_parcels)?; - let parcels = handler_parcels - .into_iter() - .chain(external_dependent_parcels) - .chain(file_parcels) - .collect(); - - let invoice = Invoice { - bindle_version: "1.0.0".to_owned(), - yanked: None, - yanked_signature: None, - bindle: BindleSpec { - id: expand_id(&hippofacts.bindle, expansion_context)?, - description: hippofacts.bindle.description.clone(), - authors: hippofacts.bindle.authors.clone(), - }, - annotations: hippofacts.annotations.clone(), - parcel: Some(parcels), - group: Some(groups), - signature: None, - }; - - Ok(invoice) - }) -} - -fn expand_id( - bindle_spec: &crate::hippofacts::BindleSpec, - expansion_context: &ExpansionContext, -) -> anyhow::Result { - let name = bindle_spec.name.clone(); - let version = expansion_context.mangle_version(&bindle_spec.version); - let id = bindle::Id::try_from(format!("{}/{}", &name, &version))?; - Ok(id) -} - -fn expand_all_entries_to_groups(hippofacts: &HippoFacts) -> anyhow::Result> { - let groups = hippofacts.entries.iter().map(expand_to_group).collect(); - Ok(groups) -} - -fn expand_to_group(entry: &HippoFactsEntry) -> Group { - Group { - name: group_name(entry), - required: None, - satisfied_by: None, - } -} - -fn group_name(entry: &HippoFactsEntry) -> String { - match entry { - HippoFactsEntry::LocalHandler(h) => format!("{}-files", h.name), - HippoFactsEntry::ExternalHandler(h) => format!( - "import:{}:{}-at-{}-files", - &h.external.bindle_id, &h.external.handler_id, &h.route - ), - HippoFactsEntry::Export(e) => format!("{}-{}-files", e.name, e.id), - } -} - -fn expand_module_entries_to_parcels( - hippofacts: &HippoFacts, - expansion_context: &ExpansionContext, -) -> anyhow::Result> { - let parcels = hippofacts - .entries - .iter() - .map(|handler| expand_one_module_entry_to_parcel(handler, expansion_context)); - parcels.collect() -} - -fn expand_one_module_entry_to_parcel( - entry: &HippoFactsEntry, - expansion_context: &ExpansionContext, -) -> anyhow::Result { - match &entry { - HippoFactsEntry::LocalHandler(h) => convert_one_match_to_parcel( - PathBuf::from(expansion_context.to_absolute(&h.name)), - expansion_context, - h.wagi_features(), - None, - None, - Some(&group_name(entry)), - ), - HippoFactsEntry::ExternalHandler(e) => convert_one_ref_to_parcel( - &e.external, - expansion_context, - e.wagi_features(), - None, - Some(&group_name(entry)), - ), - HippoFactsEntry::Export(e) => convert_one_match_to_parcel( - PathBuf::from(expansion_context.to_absolute(&e.name)), - expansion_context, - e.wagi_features(), - Some(vec![("wagi_handler_id", &e.id)]), - None, - Some(&group_name(entry)), - ), - } -} - -fn expand_all_external_ref_dependencies_to_parcels( - hippofacts: &HippoFacts, - expansion_context: &ExpansionContext, -) -> anyhow::Result> { - let parcel_lists = hippofacts.entries.iter().map(|handler| match &handler { - HippoFactsEntry::ExternalHandler(e) => expand_one_external_ref_dependencies_to_parcels( - &e.external, - expansion_context, - &group_name(handler), - ), - _ => Ok(vec![]), - }); - let parcels = flatten_or_fail(parcel_lists)?; - Ok(merge_memberships(parcels)) -} - -fn expand_one_external_ref_dependencies_to_parcels( - external_ref: &ExternalRef, - expansion_context: &ExpansionContext, - dest_group_name: &str, -) -> anyhow::Result> { - let parcels = (|| { - let invoice = expansion_context - .external_invoices - .get(&external_ref.bindle_id) - .ok_or_else(|| anyhow::anyhow!("external invoice not found on server"))?; - let main_parcel = find_handler_parcel(invoice, &external_ref.handler_id) - .ok_or_else(|| anyhow::anyhow!("external invoice does not contain specified parcel"))?; - let required_parcels = invoice.parcels_required_by(main_parcel); - let parcel_copies = required_parcels.iter().map(|p| Parcel { - label: Label { - annotations: annotation_do_not_stage_file(), - ..p.label.clone() - }, - conditions: Some(Condition { - member_of: Some(vec![dest_group_name.to_owned()]), - requires: None, - }), - }); - Ok(parcel_copies.collect()) - })(); - parcels.map_err(|e: anyhow::Error| { - anyhow::anyhow!( - "Could not copy dependency tree for external ref {}:{}: {}", - external_ref.bindle_id, - external_ref.handler_id, - e - ) - }) -} - -fn expand_all_files_to_parcels( - hippofacts: &HippoFacts, - expansion_context: &ExpansionContext, -) -> anyhow::Result>> { - WarnContext::run(|wc| { - let parcel_lists = hippofacts - .entries - .iter() - .map(|handler| expand_files_to_parcels(handler, expansion_context).unwarn(wc)); - let parcels = flatten_or_fail(parcel_lists)?; - Ok(merge_memberships(parcels)) - }) -} - -fn expand_files_to_parcels( - entry: &HippoFactsEntry, - expansion_context: &ExpansionContext, -) -> anyhow::Result>> { - WarnContext::run(|wc| { - let patterns = entry.files(); - let parcels = patterns - .iter() - .map(|f| expand_file_to_parcels(f, expansion_context, &group_name(entry)).unwarn(wc)); - flatten_or_fail(parcels) - }) -} - -fn expand_file_to_parcels( - pattern: &str, - expansion_context: &ExpansionContext, - member_of: &str, -) -> anyhow::Result>> { - let paths = glob::glob(&expansion_context.to_absolute(pattern))?; - let parcels = paths - .into_iter() - .filter_map(|p| try_convert_one_match_to_parcel(p, expansion_context, member_of)) - .collect::>>()?; - let warned_parcels = if parcels.is_empty() { - Warned::from((parcels, format!("No files matched pattern {}", pattern))) - } else { - Warned::from(parcels) - }; - Ok(warned_parcels) -} - -fn try_convert_one_match_to_parcel( - path: Result, - expansion_context: &ExpansionContext, - member_of: &str, -) -> Option> { - match path { - Err(e) => Some(Err(anyhow::anyhow!("Couldn't expand pattern: {}", e))), - Ok(path) => { - if path.is_dir() { - None - } else { - let features = vec![("file", "true")]; - Some(convert_one_match_to_parcel( - path, - expansion_context, - features, - None, - Some(member_of), - None, - )) - } - } - } -} - -fn convert_one_match_to_parcel( - path: PathBuf, - expansion_context: &ExpansionContext, - wagi_features: Vec<(&str, &str)>, - wagi_annotations: Option>, - member_of: Option<&str>, - requires: Option<&str>, -) -> anyhow::Result { - // Immediate-call closure allows us to use the try operator - let parcel = (|| { - let mut file = std::fs::File::open(&path)?; - - let name = expansion_context.to_relative(&path)?; - let size = file.metadata()?.len(); - - let mut sha = Sha256::new(); - std::io::copy(&mut file, &mut sha)?; - let digest_value = sha.finalize(); - let digest_string = format!("{:x}", digest_value); - - let media_type = mime_guess::from_path(&path) - .first_or_octet_stream() - .to_string(); - - let annotations = wagi_annotations.map(map_of); - let feature = Some(wagi_feature_of(wagi_features)); - - Ok(Parcel { - label: Label { - name, - sha256: digest_string, - media_type, - size, - feature, - annotations, - origin: None, - }, - conditions: Some(Condition { - member_of: vector_of(member_of), - requires: vector_of(requires), - }), - }) - })(); - parcel.map_err(|e: anyhow::Error| { - anyhow::anyhow!( - "Could not assemble parcel for file {}: {}", - path.to_string_lossy(), - e - ) - }) -} - -fn convert_one_ref_to_parcel( - external_ref: &ExternalRef, - expansion_context: &ExpansionContext, - wagi_features: Vec<(&str, &str)>, - member_of: Option<&str>, - requires: Option<&str>, -) -> anyhow::Result { - // Immediate-call closure allows us to use the try operator - let parcel = (|| { - // We don't need to give the IDs in these messages because these will be prepended when - // mapping errors that escape the closure (the parcel.map_err below) - let invoice = expansion_context - .external_invoices - .get(&external_ref.bindle_id) - .ok_or_else(|| anyhow::anyhow!("external invoice not found on server"))?; - let parcel = find_handler_parcel(invoice, &external_ref.handler_id) - .ok_or_else(|| anyhow::anyhow!("external invoice does not contain specified parcel"))?; - - let feature = Some(wagi_feature_of(wagi_features)); - - Ok(Parcel { - label: Label { - name: parcel.label.name.clone(), - sha256: parcel.label.sha256.clone(), - media_type: parcel.label.media_type.clone(), - size: parcel.label.size, - annotations: annotation_do_not_stage_file(), - feature, - origin: None, - }, - conditions: Some(Condition { - member_of: vector_of(member_of), - requires: vector_of(requires), - }), - }) - })(); - parcel.map_err(|e: anyhow::Error| { - anyhow::anyhow!( - "Could not assemble parcel for external ref {}:{}: {}", - external_ref.bindle_id, - external_ref.handler_id, - e - ) - }) -} - -fn find_handler_parcel<'a>(invoice: &'a Invoice, handler_id: &'a str) -> Option<&'a Parcel> { - match invoice.parcel.as_ref() { - None => None, - Some(parcels) => parcels.iter().find(|p| has_handler_id(p, handler_id)), - } -} - -fn has_handler_id(parcel: &Parcel, handler_id: &str) -> bool { - match parcel.label.annotations.as_ref() { - None => false, - Some(map) => map.get("wagi_handler_id") == Some(&handler_id.to_owned()), - } -} - -fn merge_memberships(parcels: Vec) -> Vec { - parcels - .into_iter() - .into_grouping_map_by(file_id) - .fold_first(|acc, _key, val| merge_parcel_into(acc, val)) - .values() - .cloned() // into_values is not yet stable - .collect() -} - -fn merge_parcel_into(first: Parcel, second: Parcel) -> Parcel { - Parcel { - label: first.label, - conditions: merge_parcel_conditions(first.conditions, second.conditions), - } -} - -fn merge_parcel_conditions( - first: Option, - second: Option, -) -> Option { - match first { - None => second, // shouldn't happen - Some(first_condition) => match second { - None => Some(first_condition), - Some(second_condition) => { - Some(merge_condition_lists(first_condition, second_condition)) - } - }, - } -} - -fn merge_condition_lists(first: Condition, second: Condition) -> Condition { - Condition { - member_of: merge_lists(first.member_of, second.member_of), - requires: first.requires, - } -} - -fn merge_lists(first: Option>, second: Option>) -> Option> { - match (first, second) { - (None, None) => None, - (some, None) => some, - (None, some) => some, - (Some(list1), Some(list2)) => Some(vec![list1, list2].concat()), - } -} - -fn flatten_or_fail(source: I) -> anyhow::Result> -where - I: IntoIterator>>, -{ - let mut result = vec![]; - - for v in source { - match v { - Err(e) => return Err(e), - Ok(mut vals) => result.append(&mut vals), - } - } - - Ok(result) -} - -fn check_for_name_clashes( - external_dependent_parcels: &[Parcel], - file_parcels: &[Parcel], -) -> anyhow::Result<()> { - let file_parcel_names: HashSet<_> = file_parcels - .iter() - .map(|p| p.label.name.to_owned()) - .collect(); - for parcel in external_dependent_parcels { - if file_parcel_names.contains(&parcel.label.name) { - return Err(anyhow::anyhow!( - "{} occurs both as a local file and as a dependency of an external reference", - parcel.label.name - )); - } - } - Ok(()) -} - -fn current_user() -> Option { - std::env::var("USER") - .or_else(|_| std::env::var("USERNAME")) - .ok() -} - -fn file_id(parcel: &Parcel) -> String { - // Two parcels with different names could refer to the same content. We - // don't want to treat them as the same parcel when deduplicating. - format!("{}@{}", parcel.label.sha256, parcel.label.name) -} - -fn vector_of(option: Option<&str>) -> Option> { - option.map(|val| vec![val.to_owned()]) -} - -fn wagi_feature_of(values: Vec<(&str, &str)>) -> BTreeMap> { - BTreeMap::from_iter(vec![("wagi".to_owned(), map_of(values))]) -} - -fn map_of(values: Vec<(&str, &str)>) -> BTreeMap { - values - .into_iter() - .map(|(k, v)| (k.to_owned(), v.to_owned())) - .collect() -} - -fn annotation_do_not_stage_file() -> Option { - let mut annotations = AnnotationMap::new(); - annotations.insert("hippos_do_not_stage".to_owned(), "true".to_owned()); - Some(annotations) -} - -trait WagiFeatureProvider { - fn wagi_features(&self) -> Vec<(&str, &str)>; -} - -impl WagiFeatureProvider for LocalHandler { - fn wagi_features(&self) -> Vec<(&str, &str)> { - let mut features = vec![("route", &self.route[..]), ("file", "false")]; - if let Some(entrypoint) = &self.entrypoint { - features.push(("entrypoint", &entrypoint[..])); - } - features - } -} - -impl WagiFeatureProvider for ExternalHandler { - fn wagi_features(&self) -> Vec<(&str, &str)> { - vec![("route", &self.route[..]), ("file", "false")] - } -} - -impl WagiFeatureProvider for Export { - fn wagi_features(&self) -> Vec<(&str, &str)> { - let mut features = vec![("file", "false")]; - if let Some(entrypoint) = &self.entrypoint { - features.push(("entrypoint", &entrypoint[..])); - } - features - } -} - -#[cfg(test)] -mod test { - use std::str::FromStr; - - use super::*; - - fn test_dir(name: &str) -> PathBuf { - let test_data_base = PathBuf::from_str(env!("CARGO_MANIFEST_DIR")) - .unwrap() - .join("testdata"); - test_data_base.join(name) - } - - fn read_hippofacts(path: impl AsRef) -> anyhow::Result { - HippoFacts::read_from(path) - } - - fn parcel_named<'a>(invoice: &'a Invoice, parcel_name: &str) -> &'a Parcel { - invoice - .parcel - .as_ref() - .unwrap() - .iter() - .find(|p| p.label.name == parcel_name) - .expect(&format!("No parcel named {}", parcel_name)) - } - - fn parcel_feature_value<'a>( - invoice: &'a Invoice, - parcel_name: &str, - feature_name: &str, - item_name: &str, - ) -> &'a str { - parcel_named(invoice, parcel_name) - .label - .feature - .as_ref() - .unwrap() - .get(feature_name) - .as_ref() - .unwrap() - .get(item_name) - .as_ref() - .unwrap() - } - - fn parcel_conditions<'a>(invoice: &'a Invoice, parcel_name: &str) -> &'a Condition { - parcel_named(invoice, parcel_name) - .conditions - .as_ref() - .unwrap() - } - - fn parcel_memberships<'a>(invoice: &'a Invoice, parcel_name: &str) -> &'a Vec { - parcel_conditions(invoice, parcel_name) - .member_of - .as_ref() - .unwrap() - } - - fn parcel_requirements<'a>(invoice: &'a Invoice, parcel_name: &str) -> &'a Vec { - parcel_conditions(invoice, parcel_name) - .requires - .as_ref() - .unwrap() - } - - fn expand_test_invoice(name: &str) -> anyhow::Result { - expand_test_invoice_per_versioning(name, InvoiceVersioning::Production) - } - - fn expand_test_invoice_per_versioning( - name: &str, - invoice_versioning: InvoiceVersioning, - ) -> anyhow::Result { - let dir = test_dir(name); - let hippofacts = read_hippofacts(dir.join("HIPPOFACTS")).unwrap(); - let expansion_context = ExpansionContext { - relative_to: dir, - invoice_versioning: invoice_versioning, - external_invoices: external_test_invoices(), - }; - - let (invoice, _) = expand(&hippofacts, &expansion_context)?.into(); - Ok(invoice) - } - - fn external_test_invoices() -> HashMap { - let mut invoices = HashMap::new(); - - let fs_id = bindle::Id::from_str("deislabs/fileserver/1.0.3").unwrap(); - let fs_parcels = vec![ - Parcel { - label: Label { - name: "experimental_file_server.gr.wasm".to_owned(), - sha256: "987654".to_owned(), - media_type: "application/wasm".to_owned(), - size: 123, - origin: None, - annotations: None, - feature: None, - }, - conditions: None, - }, - Parcel { - label: Label { - name: "file_server.gr.wasm".to_owned(), - sha256: "123456789".to_owned(), - media_type: "application/wasm".to_owned(), - size: 100, - origin: None, - annotations: Some( - vec![("wagi_handler_id".to_owned(), "static".to_owned())] - .into_iter() - .collect(), - ), - feature: None, - }, - conditions: None, - }, - Parcel { - label: Label { - name: "imagegallery.wasm".to_owned(), - sha256: "13463".to_owned(), - media_type: "application/wasm".to_owned(), - size: 234, - origin: None, - annotations: Some( - vec![("wagi_handler_id".to_owned(), "image_gallery".to_owned())] - .into_iter() - .collect(), - ), - feature: None, - }, - conditions: Some(Condition { - member_of: None, - requires: Some(vec!["igfiles".to_owned()]), - }), - }, - Parcel { - label: Label { - name: "images.db".to_owned(), - sha256: "134632".to_owned(), - media_type: "application/octet-stream".to_owned(), - size: 345, - origin: None, - annotations: None, - feature: None, - }, - conditions: Some(Condition { - member_of: Some(vec!["igfiles".to_owned()]), - requires: None, - }), - }, - Parcel { - label: Label { - name: "thumbnails.db".to_owned(), - sha256: "444444".to_owned(), - media_type: "application/octet-stream".to_owned(), - size: 456, - origin: None, - annotations: None, - feature: None, - }, - conditions: Some(Condition { - member_of: Some(vec!["igfiles".to_owned()]), - requires: Some(vec!["thumbfiles".to_owned()]), - }), - }, - Parcel { - label: Label { - name: "thumblywumbly.txt".to_owned(), // give me a break I am running out of ideas - sha256: "555555".to_owned(), - media_type: "text/plain".to_owned(), - size: 456, - origin: None, - annotations: None, - feature: None, - }, - conditions: Some(Condition { - member_of: Some(vec!["thumbfiles".to_owned()]), - requires: None, - }), - }, - Parcel { - label: Label { - name: "unused.txt".to_owned(), - sha256: "3948759834765".to_owned(), - media_type: "text/plain".to_owned(), - size: 456, - origin: None, - annotations: None, - feature: None, - }, - conditions: Some(Condition { - member_of: Some(vec!["group_that_does_not_exist".to_owned()]), - requires: None, - }), - }, - ]; - let fs_invoice = Invoice { - bindle_version: "1.0.0".to_owned(), - yanked: None, - yanked_signature: None, - bindle: bindle::BindleSpec { - id: fs_id.clone(), - description: None, - authors: None, - }, - annotations: None, - parcel: Some(fs_parcels), - group: None, - signature: None, - }; - invoices.insert(fs_id.clone(), fs_invoice); - - invoices - } - - #[test] - fn test_name_is_kept() { - let invoice = expand_test_invoice("app1").unwrap(); - assert_eq!("weather", invoice.bindle.id.name()); - } - - #[test] - fn test_version_is_valid() { - use regex::Regex; - use semver::Version; - use std::env; - - env::set_var("USER", "foo"); - - let invoice = expand_test_invoice_per_versioning("app1", InvoiceVersioning::Dev).unwrap(); - let version = &invoice.bindle.id.version().to_string(); - // The dev version is expected to follow the format of - // --<17-digit timestamp> - // For the HIPPOFACTS bindle version, we have it hardcoded to the value - // used in the 'app1' test app. - // For the username, we have it hardcoded to the environment variable's - // value set above. - let dev_version_re = Regex::new(r"^(1.2.3-foo-)[0-9]{17}$").unwrap(); - assert!( - dev_version_re.is_match(version), - "version should match the expected regex when InvoiceVersioning is Dev" - ); - assert!( - Version::parse(version).is_ok(), - "version should be valid semver" - ); - - let invoice = - expand_test_invoice_per_versioning("app1", InvoiceVersioning::Production).unwrap(); - let version = &invoice.bindle.id.version().to_string(); - assert_eq!( - "1.2.3", - version, - "version should exactly match the value in HIPPOFACTS when InvoiceVersioning is Production" - ); - assert!( - Version::parse(version).is_ok(), - "version should be valid semver" - ); - } - - #[test] - fn test_version_is_invalid() { - let invoice = expand_test_invoice("bad_version"); - assert!(invoice.is_err()); - if let Err(e) = invoice { - let message = format!("{}", e); - assert_eq!( - "Version 1.2.3.4 is not a valid semantic version (e.g. 1.2.3)", - message, - ); - } - } - - #[test] - fn test_route_is_mapped() { - let invoice = expand_test_invoice("app1").unwrap(); - assert_eq!( - "/fake", - parcel_feature_value(&invoice, "out/fake.wasm", "wagi", "route") - ); - } - - #[test] - fn test_entrypoint_is_mapped() { - let invoice = expand_test_invoice("app1").unwrap(); - assert_eq!( - "even_faker", - parcel_feature_value(&invoice, "out/fakeissimo.wasm", "wagi", "entrypoint") - ); - } - - #[test] - fn test_handler_parcel_is_not_asset() { - let invoice = expand_test_invoice("app1").unwrap(); - assert_eq!( - "false", - parcel_feature_value(&invoice, "out/fake.wasm", "wagi", "file") - ); - } - - #[test] - fn test_group_is_created_per_handler() { - let invoice = expand_test_invoice("app1").unwrap(); - let groups = invoice.group.as_ref().unwrap(); - assert_eq!(3, groups.len()); - assert_eq!("out/fake.wasm-files", groups[0].name); - assert_eq!("out/lies.wasm-files", groups[1].name); - assert_eq!("out/fakeissimo.wasm-files", groups[2].name); - } - - #[test] - fn test_files_are_members_of_correct_groups() { - let invoice = expand_test_invoice("app1").unwrap(); - assert_eq!( - 1, - parcel_conditions(&invoice, "scripts/ignore.json") - .member_of - .as_ref() - .unwrap() - .len() - ); - assert_eq!( - 2, - parcel_conditions(&invoice, "scripts/real.js") - .member_of - .as_ref() - .unwrap() - .len() - ); - } - - #[test] - fn test_assets_parcels_are_marked_as_assets() { - let invoice = expand_test_invoice("app1").unwrap(); - assert_eq!( - "true", - parcel_feature_value(&invoice, "scripts/real.js", "wagi", "file") - ); - } - - #[test] - fn test_handler_parcels_are_not_members_of_groups() { - let invoice = expand_test_invoice("app1").unwrap(); - assert_eq!(None, parcel_conditions(&invoice, "out/lies.wasm").member_of); - } - - #[test] - fn test_handlers_require_correct_groups() { - let invoice = expand_test_invoice("app1").unwrap(); - assert_eq!( - 1, - parcel_conditions(&invoice, "out/lies.wasm") - .requires - .as_ref() - .unwrap() - .len() - ); - assert_eq!( - "out/lies.wasm-files", - parcel_conditions(&invoice, "out/lies.wasm") - .requires - .as_ref() - .unwrap()[0] - ); - } - - #[test] - fn test_if_no_files_key_then_no_asset_parcels() { - let invoice = expand_test_invoice("app2").unwrap(); - let count = invoice - .parcel - .unwrap() - .iter() - .filter(|parcel| parcel.member_of("wasm/no-assets.wasm-files")) - .count(); - assert_eq!(0, count); - } - - #[test] - fn test_if_empty_files_key_then_no_asset_parcels() { - let invoice = expand_test_invoice("app2").unwrap(); - let count = invoice - .parcel - .unwrap() - .iter() - .filter(|parcel| parcel.member_of("wasm/empty-assets.wasm-files")) - .count(); - assert_eq!(0, count); - } - - #[test] - fn test_if_no_files_match_then_no_asset_parcels() { - let invoice = expand_test_invoice("app2").unwrap(); - let count = invoice - .parcel - .unwrap() - .iter() - .filter(|parcel| parcel.member_of("wasm/no-match.wasm-files")) - .count(); - assert_eq!(0, count); - } - - #[test] - fn test_if_nonexistent_directory_then_no_asset_parcels() { - let invoice = expand_test_invoice("app2").unwrap(); - let count = invoice - .parcel - .unwrap() - .iter() - .filter(|parcel| parcel.member_of("wasm/no-directory.wasm-files")) - .count(); - assert_eq!(0, count); - } - - #[test] - fn test_finds_assets_in_nested_subdirectories() { - let invoice = expand_test_invoice("nesttest").unwrap(); - let assets = invoice - .parcel - .unwrap() - .iter() - .filter(|parcel| parcel.member_of("out/fake.wasm-files")) - .map(|parcel| parcel.label.name.clone()) - .collect_vec(); - assert_eq!(4, assets.len()); - assert!(assets.contains(&"assets/scripts/justsome.json".to_owned())); - assert!(assets.contains(&"assets/scripts/real.js".to_owned())); - assert!(assets.contains(&"assets/styles/css/suspicious.css".to_owned())); - assert!(assets.contains(&"assets/styles/sass/iffy.sass".to_owned())); - } - - #[test] - fn test_if_file_does_not_exist_then_no_asset_parcels() { - // TODO: I feel like this should be an error - let invoice = expand_test_invoice("app2").unwrap(); - let count = invoice - .parcel - .unwrap() - .iter() - .filter(|parcel| parcel.member_of("wasm/specific-file-missing.wasm-files")) - .count(); - assert_eq!(0, count); // TODO: ? - } - - #[test] - fn test_if_handler_appears_as_an_asset_then_there_are_two_parcels_with_appropriate_membership_and_requirements_clauses( - ) { - let invoice = expand_test_invoice("app2").unwrap(); - let parcels = invoice.parcel.as_ref().unwrap(); - let count = parcels - .iter() - .filter(|parcel| parcel.member_of("wasm/other-wasms.wasm-files")) - .count(); - assert_eq!(3, count); - let file_occurrences = parcels - .iter() - .filter(|parcel| parcel.label.name == "wasm/no-assets.wasm") - .collect::>(); - assert_eq!(2, file_occurrences.len()); - let handler_parcel = file_occurrences - .iter() - .filter(|parcel| parcel.conditions.as_ref().unwrap().requires.is_some()); - assert_eq!(1, handler_parcel.count()); - let asset_parcel = file_occurrences - .iter() - .filter(|parcel| parcel.conditions.as_ref().unwrap().member_of.is_some()); - assert_eq!(1, asset_parcel.count()); - } - - #[test] - fn test_externals_are_surfaced_as_parcels() { - let invoice = expand_test_invoice("external1").unwrap(); - let parcels = invoice.parcel.as_ref().unwrap(); - let ext_parcel = parcel_named(&invoice, "file_server.gr.wasm"); - assert_eq!("123456789", ext_parcel.label.sha256); - assert_eq!("application/wasm", ext_parcel.label.media_type); - assert_eq!(100, ext_parcel.label.size); - assert_eq!(5, parcels.len()); // 1 local handler, 1 ext handler, 3 asset files - } - - #[test] - fn test_externals_bring_along_their_dependencies() { - let invoice = expand_test_invoice("external2").unwrap(); - let parcels = invoice.parcel.as_ref().unwrap(); - assert_eq!(8, parcels.len()); // 1 local handler, 1 ext handler, 3 asset files, 2 immediate ext deps, 1 indirect ext dep - } - - #[test] - fn test_externals_cannot_clash_with_local_files() { - let invoice = expand_test_invoice("external3"); - assert!(invoice.is_err()); - if let Err(e) = invoice { - let message = format!("{}", e); - assert!(message.contains("thumbnails.db")); - assert!(message.contains( - "occurs both as a local file and as a dependency of an external reference" - )); - } - } - - #[test] - fn test_exports_keep_their_entry_points() { - let invoice = expand_test_invoice("lib1").unwrap(); - let parcels = invoice.parcel.as_ref().unwrap(); - assert_eq!(4, parcels.len()); - - let exported_parcel = parcel_named(&invoice, "wasm/gallery.wasm"); - - match exported_parcel.label.feature.as_ref() { - None => assert!(false, "No features on the exported parcel"), - Some(map) => assert_eq!( - "serve_pix", - map.get("wagi").unwrap().get("entrypoint").unwrap() - ), - }; - } - - #[test] - fn test_exports_have_the_wagi_handler_annotation() { - let invoice = expand_test_invoice("lib1").unwrap(); - let parcels = invoice.parcel.as_ref().unwrap(); - assert_eq!(4, parcels.len()); - - let exported_parcel = parcel_named(&invoice, "wasm/server.wasm"); - - match exported_parcel.label.annotations.as_ref() { - None => assert!(false, "No annotations on the exported parcel"), - Some(map) => assert_eq!("serve_all_the_things", map.get("wagi_handler_id").unwrap()), - }; - } - - #[test] - fn test_exports_bring_along_their_dependencies() { - let invoice = expand_test_invoice("lib1").unwrap(); - let parcels = invoice.parcel.as_ref().unwrap(); - assert_eq!(4, parcels.len()); - - assert_eq!( - "wasm/gallery.wasm-image_gallery-files", - parcel_requirements(&invoice, "wasm/gallery.wasm")[0] - ); - - assert_eq!( - "wasm/gallery.wasm-image_gallery-files", - parcel_memberships(&invoice, "gallery/images.db")[0] - ); - assert_eq!( - "wasm/gallery.wasm-image_gallery-files", - parcel_memberships(&invoice, "gallery/thumbnails.db")[0] - ); - } -} diff --git a/src/hippo/client.rs b/src/hippo/client.rs index 6886681..5c24d4d 100644 --- a/src/hippo/client.rs +++ b/src/hippo/client.rs @@ -19,7 +19,6 @@ use hippo_openapi::models::{ use reqwest::header; use serde::Deserialize; - const JSON_MIME_TYPE: &str = "application/json"; pub struct ConnectionInfo { @@ -73,7 +72,8 @@ impl Client { password_confirm: password, }), ) - .await.map_err(format_response_error) + .await + .map_err(format_response_error) } pub async fn login(&self, username: String, password: String) -> anyhow::Result { @@ -84,7 +84,8 @@ impl Client { password: password, }), ) - .await.map_err(format_response_error) + .await + .map_err(format_response_error) } pub async fn add_app(&self, name: String, storage_id: String) -> anyhow::Result { @@ -95,11 +96,14 @@ impl Client { storage_id: storage_id, }), ) - .await.map_err(format_response_error) + .await + .map_err(format_response_error) } pub async fn remove_app(&self, id: String) -> anyhow::Result<()> { - api_app_id_delete(&self.configuration, &id).await.map_err(format_response_error) + api_app_id_delete(&self.configuration, &id) + .await + .map_err(format_response_error) } pub async fn add_certificate( @@ -116,11 +120,14 @@ impl Client { private_key: private_key, }), ) - .await.map_err(format_response_error) + .await + .map_err(format_response_error) } pub async fn remove_certificate(&self, id: String) -> anyhow::Result<()> { - api_certificate_id_delete(&self.configuration, &id).await.map_err(format_response_error) + api_certificate_id_delete(&self.configuration, &id) + .await + .map_err(format_response_error) } pub async fn add_channel( @@ -133,23 +140,24 @@ impl Client { active_revision_id: Option, certificate_id: Option, ) -> anyhow::Result { - api_channel_post( - &self.configuration, - Some(CreateChannelCommand { - app_id: app_id, - name: name, - domain, - revision_selection_strategy, - range_rule, - active_revision_id, - certificate_id, - }), - ) - .await.map_err(format_response_error) + let command = CreateChannelCommand { + app_id: app_id, + name: name, + domain, + revision_selection_strategy, + range_rule, + active_revision_id, + certificate_id, + }; + api_channel_post(&self.configuration, Some(command)) + .await + .map_err(format_response_error) } pub async fn remove_channel(&self, id: String) -> anyhow::Result<()> { - api_channel_id_delete(&self.configuration, &id).await.map_err(format_response_error) + api_channel_id_delete(&self.configuration, &id) + .await + .map_err(format_response_error) } pub async fn add_environment_variable( @@ -166,11 +174,14 @@ impl Client { channel_id: channel_id, }), ) - .await.map_err(format_response_error) + .await + .map_err(format_response_error) } pub async fn remove_environment_variable(&self, id: String) -> anyhow::Result<()> { - api_environmentvariable_id_delete(&self.configuration, &id).await.map_err(format_response_error) + api_environmentvariable_id_delete(&self.configuration, &id) + .await + .map_err(format_response_error) } pub async fn add_revision( @@ -185,14 +196,15 @@ impl Client { revision_number: revision_number, }), ) - .await.map_err(format_response_error) + .await + .map_err(format_response_error) } } #[derive(Deserialize, Debug)] struct ValidationExceptionMessage { title: String, - errors: HashMap> + errors: HashMap>, } fn format_response_error(e: Error) -> anyhow::Error { @@ -200,9 +212,9 @@ fn format_response_error(e: Error) -> anyhow::Error { Error::ResponseError(r) => { match serde_json::from_str::(&r.content) { Ok(m) => anyhow::anyhow!("{} {:?}", m.title, m.errors), - _ => anyhow::anyhow!(r.content) + _ => anyhow::anyhow!(r.content), } - }, - _ => anyhow::anyhow!(e.to_string()) + } + _ => anyhow::anyhow!(e.to_string()), } } diff --git a/src/hippofacts.rs b/src/hippofacts.rs deleted file mode 100644 index fe5b8da..0000000 --- a/src/hippofacts.rs +++ /dev/null @@ -1,365 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::{collections::BTreeMap, convert::TryFrom}; - -// type FeatureMap = BTreeMap>; - -type AnnotationMap = BTreeMap; - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(deny_unknown_fields, rename_all = "camelCase")] -pub(crate) struct RawHippoFacts { - pub bindle: BindleSpec, - pub annotations: Option, - pub handler: Option>, - pub export: Option>, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(deny_unknown_fields, rename_all = "camelCase")] -pub struct BindleSpec { - pub name: String, - pub version: String, // not semver::Version because this could be a template - pub description: Option, - pub authors: Option>, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(deny_unknown_fields, rename_all = "camelCase")] -pub(crate) struct RawHandler { - pub name: Option, - pub entrypoint: Option, - pub external: Option, - pub route: String, - pub files: Option>, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(deny_unknown_fields, rename_all = "camelCase")] -pub(crate) struct RawExport { - pub name: String, - pub entrypoint: Option, - pub id: String, - pub files: Option>, -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -#[serde(deny_unknown_fields, rename_all = "camelCase")] -pub(crate) struct RawExternalRef { - pub bindle_id: String, - pub handler_id: String, -} - -pub struct HippoFacts { - pub bindle: BindleSpec, - pub annotations: Option, - pub entries: Vec, -} - -pub struct LocalHandler { - pub name: String, - pub entrypoint: Option, - pub route: String, - pub files: Option>, -} - -pub struct ExternalHandler { - pub external: ExternalRef, - pub route: String, - pub files: Option>, -} - -enum HandlerModule { - File(String), - External(ExternalRef), -} - -#[derive(Clone)] -pub struct ExternalRef { - pub bindle_id: bindle::Id, - pub handler_id: String, -} - -pub struct Export { - pub name: String, - pub entrypoint: Option, - pub id: String, - pub files: Vec, -} - -pub enum HippoFactsEntry { - LocalHandler(LocalHandler), - ExternalHandler(ExternalHandler), - Export(Export), -} - -impl HippoFacts { - pub fn read_from(source: impl AsRef) -> anyhow::Result { - // Immediate-call closure lets us use the try operator - let read_result = (|| { - let content = std::fs::read_to_string(&source)?; - let spec = toml::from_str::(&content)?; - Self::try_from(&spec) - })(); - read_result.map_err(|e: anyhow::Error| { - anyhow::anyhow!( - "Error parsing {} as a Hippo artifacts file: {}", - source.as_ref().to_string_lossy(), - e - ) - }) - } -} - -impl TryFrom<&RawHippoFacts> for HippoFacts { - type Error = anyhow::Error; - - fn try_from(raw: &RawHippoFacts) -> anyhow::Result { - let handler_vec = raw.handler.clone().unwrap_or_default(); - let export_vec = raw.export.clone().unwrap_or_default(); - let entries = handler_vec - .iter() - .map(HippoFactsEntry::try_from) - .chain(export_vec.iter().map(HippoFactsEntry::try_from)) - .collect::>>()?; - if entries.is_empty() { - return Err(no_handlers()); - } - Ok(Self { - bindle: raw.bindle.clone(), - annotations: raw.annotations.clone(), - entries, - }) - } -} - -impl TryFrom<&RawHandler> for HippoFactsEntry { - type Error = anyhow::Error; - - fn try_from(raw: &RawHandler) -> anyhow::Result { - let handler_module = match (&raw.name, &raw.external) { - (Some(name), None) => Ok(HandlerModule::File(name.clone())), - (None, Some(external_ref)) => Ok(HandlerModule::External(ExternalRef::try_from( - external_ref, - )?)), - _ => Err(anyhow::anyhow!( - "Route '{}' must specify exactly one of 'name' and 'external'", - raw.route - )), - }?; - if let Some(_) = &raw.entrypoint { - if let HandlerModule::External(_) = &handler_module { - anyhow::bail!( - "Route '{}' may not specify an entrypoint on an external reference", - raw.route - ); - } - } - let entry = match handler_module { - HandlerModule::File(name) => Self::LocalHandler(LocalHandler { - name, - entrypoint: raw.entrypoint.clone(), - route: raw.route.clone(), - files: raw.files.clone(), - }), - HandlerModule::External(external) => Self::ExternalHandler(ExternalHandler { - external, - route: raw.route.clone(), - files: raw.files.clone(), - }), - }; - Ok(entry) - } -} - -impl TryFrom<&RawExternalRef> for ExternalRef { - type Error = anyhow::Error; - - fn try_from(raw: &RawExternalRef) -> anyhow::Result { - let bindle_id = bindle::Id::try_from(&raw.bindle_id)?; - Ok(Self { - bindle_id, - handler_id: raw.handler_id.clone(), - }) - } -} - -impl TryFrom<&RawExport> for HippoFactsEntry { - type Error = anyhow::Error; - - fn try_from(raw: &RawExport) -> anyhow::Result { - Ok(Self::Export(Export { - id: raw.id.clone(), - entrypoint: raw.entrypoint.clone(), - name: raw.name.clone(), - files: raw.files.clone().unwrap_or_default(), - })) - } -} - -impl HippoFactsEntry { - pub fn files(&self) -> Vec { - match self { - Self::LocalHandler(h) => h.files.clone().unwrap_or_default(), - Self::ExternalHandler(h) => h.files.clone().unwrap_or_default(), - Self::Export(e) => e.files.clone(), - } - } - - pub fn external_ref(&self) -> Option { - match self { - Self::LocalHandler(_) => None, - Self::ExternalHandler(h) => Some(h.external.clone()), - Self::Export(_) => None, - } - } -} - -fn no_handlers() -> anyhow::Error { - anyhow::anyhow!("No handlers defined in artifact spec") -} - -#[cfg(test)] -mod test { - use super::*; - - impl HippoFactsEntry { - pub fn name(&self) -> Option { - match self { - Self::LocalHandler(h) => Some(h.name.clone()), - Self::ExternalHandler(_) => None, - Self::Export(e) => Some(e.name.clone()), - } - } - - pub fn entrypoint(&self) -> Option { - match self { - Self::LocalHandler(h) => h.entrypoint.clone(), - Self::ExternalHandler(_) => None, - Self::Export(e) => e.entrypoint.clone(), - } - } - - pub fn route(&self) -> Option { - match self { - Self::LocalHandler(h) => Some(h.route.clone()), - Self::ExternalHandler(h) => Some(h.route.clone()), - Self::Export(_) => None, - } - } - - pub fn export_id(&self) -> Option { - match self { - Self::LocalHandler(_) => None, - Self::ExternalHandler(_) => None, - Self::Export(e) => Some(e.id.clone()), - } - } - } - - #[test] - fn test_can_read_hippo_facts() { - let raw: RawHippoFacts = toml::from_str( - r#" - # HIPPO FACT: the North American house hippo is found across Canada and the Eastern US - [bindle] - name = "birds" - version = "1.2.4" - - [[handler]] - name = "penguin.wasm" - route = "/birds/flightless" - files = ["adelie.png", "rockhopper.png", "*.jpg"] - - [[handler]] - name = "cassowary.wasm" - entrypoint = "rawr" - route = "/birds/savage/rending" - "#, - ) - .expect("error parsing test TOML"); - let facts = HippoFacts::try_from(&raw).expect("error parsing raw to HF"); - - assert_eq!("birds", &facts.bindle.name); - assert_eq!(&None, &facts.annotations); - - let handlers = &facts.entries; - - assert_eq!(2, handlers.len()); - - assert_eq!("penguin.wasm", handlers[0].name().unwrap()); - assert_eq!(None, handlers[0].entrypoint()); - assert_eq!("/birds/flightless", &handlers[0].route().unwrap()); - assert_eq!(3, handlers[0].files().len()); - - assert_eq!("cassowary.wasm", handlers[1].name().unwrap()); - assert_eq!("rawr", handlers[1].entrypoint().unwrap()); - assert_eq!("/birds/savage/rending", &handlers[1].route().unwrap()); - assert_eq!(0, handlers[1].files().len()); - } - - #[test] - fn test_parse_externals() { - let facts = HippoFacts::read_from("./testdata/external1/HIPPOFACTS") - .expect("error reading facts file"); - - assert_eq!("toastbattle", &facts.bindle.name); - - let handlers = &facts.entries; - - assert_eq!(2, handlers.len()); - - let ext = handlers[1].external_ref().unwrap(); - assert_eq!("deislabs/fileserver", ext.bindle_id.name()); - assert_eq!("1.0.3", ext.bindle_id.version_string()); - assert_eq!("static", ext.handler_id); - } - - #[test] - fn test_external_refs_cannot_have_own_entrypoints() { - let facts = HippoFacts::read_from("./testdata/external_bad/HIPPOFACTS"); - assert!(facts.is_err()); - } - - #[test] - fn test_parse_exports() { - let facts = - HippoFacts::read_from("./testdata/lib1/HIPPOFACTS").expect("error reading facts file"); - - assert_eq!("server", &facts.bindle.name); - - assert_eq!(2, facts.entries.len()); - - let server_export = &facts.entries[0]; - assert_eq!("wasm/server.wasm", server_export.name().unwrap()); - assert_eq!("serve_all_the_things", server_export.export_id().unwrap()); - assert_eq!(0, server_export.files().len()); - - let gallery_export = &facts.entries[1]; - assert_eq!("wasm/gallery.wasm", gallery_export.name().unwrap()); - assert_eq!("serve_pix", gallery_export.entrypoint().unwrap()); - assert_eq!(2, gallery_export.files().len()); - } - - #[test] - fn test_no_handlers_no_exports_no_service() { - let raw: RawHippoFacts = toml::from_str( - r#" - # HIPPO FACT: Hippos are the second heaviest land animal after the elephant - [bindle] - name = "nope" - version = "1.2.4" - "#, - ) - .expect("error parsing test TOML"); - let facts = HippoFacts::try_from(&raw); - - assert!(facts.is_err()); - if let Err(e) = facts { - assert!( - e.to_string().contains("No handlers"), - "check error message is helpful: '{}'", - e - ); - } - } -} diff --git a/src/main.rs b/src/main.rs index 87df7a3..ceb29f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,5 @@ -mod bindle; mod cli; -mod expander; mod hippo; -mod hippofacts; -mod warnings; use cli::Cli; diff --git a/src/warnings.rs b/src/warnings.rs deleted file mode 100644 index c4bc552..0000000 --- a/src/warnings.rs +++ /dev/null @@ -1,71 +0,0 @@ -pub struct Warned { - pub value: T, - pub warnings: Vec, -} - -impl From for Warned { - fn from(value: T) -> Self { - Warned { - value, - warnings: vec![], - } - } -} - -impl> From<(T, I)> for Warned { - fn from((value, warn): (T, I)) -> Self { - Warned { - value, - warnings: vec![warn.into()], - } - } -} - -impl From> for (T, Vec) { - fn from(w: Warned) -> Self { - (w.value, w.warnings) - } -} - -pub struct WarnContext { - warnings: Vec, -} - -impl WarnContext { - pub fn run(action: impl Fn(&mut Self) -> Result) -> Result, E> { - let mut wc = Self { warnings: vec![] }; - let t = action(&mut wc)?; - Ok(Warned { - value: t, - warnings: wc.warnings, - }) - } -} - -pub trait Unwarn { - type Value; - fn unwarn(self, wc: &mut WarnContext) -> Self::Value; -} - -impl Unwarn for Warned { - type Value = T; - fn unwarn(self, wc: &mut WarnContext) -> Self::Value { - let mut warnings = self.warnings.clone(); - wc.warnings.append(&mut warnings); - self.value - } -} - -impl Unwarn for Result, E> { - type Value = Result; - fn unwarn(self, wc: &mut WarnContext) -> Self::Value { - match self { - Err(e) => Err(e), - Ok(t) => { - let mut warnings = t.warnings.clone(); - wc.warnings.append(&mut warnings); - Ok(t.value) - } - } - } -} diff --git a/testdata/app1/HIPPOFACTS b/testdata/app1/HIPPOFACTS deleted file mode 100644 index 317eb6b..0000000 --- a/testdata/app1/HIPPOFACTS +++ /dev/null @@ -1,18 +0,0 @@ -[bindle] -name = "weather" -version = "1.2.3" - -[[handler]] -name = "out/fake.wasm" -route = "/fake" -files = ["scripts/*.js"] - -[[handler]] -name = "out/lies.wasm" -route = "/lies" -files = ["scripts/*.js", "scripts/*.json"] - -[[handler]] -name = "out/fakeissimo.wasm" -entrypoint = "even_faker" -route = "/fake/fake/fake" diff --git a/testdata/app1/out/fake.js b/testdata/app1/out/fake.js deleted file mode 100644 index 0d37fc0..0000000 --- a/testdata/app1/out/fake.js +++ /dev/null @@ -1 +0,0 @@ -"This shouldn't be included in the invoice" diff --git a/testdata/app1/out/fake.wasm b/testdata/app1/out/fake.wasm deleted file mode 100644 index eb6fa76..0000000 --- a/testdata/app1/out/fake.wasm +++ /dev/null @@ -1 +0,0 @@ -Supposedly Wasm but not really \ No newline at end of file diff --git a/testdata/app1/out/fakeissimo.wasm b/testdata/app1/out/fakeissimo.wasm deleted file mode 100644 index eb6fa76..0000000 --- a/testdata/app1/out/fakeissimo.wasm +++ /dev/null @@ -1 +0,0 @@ -Supposedly Wasm but not really \ No newline at end of file diff --git a/testdata/app1/out/lies.wasm b/testdata/app1/out/lies.wasm deleted file mode 100644 index 4a5c203..0000000 --- a/testdata/app1/out/lies.wasm +++ /dev/null @@ -1 +0,0 @@ -This isn't Wasm either \ No newline at end of file diff --git a/testdata/app1/scripts/ignore.json b/testdata/app1/scripts/ignore.json deleted file mode 100644 index 29d0ff3..0000000 --- a/testdata/app1/scripts/ignore.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "fact": "this shouldn't be included in the bindle" -} \ No newline at end of file diff --git a/testdata/app1/scripts/real.js b/testdata/app1/scripts/real.js deleted file mode 100644 index 25db33c..0000000 --- a/testdata/app1/scripts/real.js +++ /dev/null @@ -1,3 +0,0 @@ -function foo() { - console.log("This should be included in the bindle") -} diff --git a/testdata/app2/HIPPOFACTS b/testdata/app2/HIPPOFACTS deleted file mode 100644 index cb28c85..0000000 --- a/testdata/app2/HIPPOFACTS +++ /dev/null @@ -1,32 +0,0 @@ -[bindle] -name = "birdbattle" -version = "1.0.0" - -[[handler]] -name = "wasm/no-assets.wasm" -route = "/penguin" - -[[handler]] -name = "wasm/empty-assets.wasm" -route = "/moa" -files = [] - -[[handler]] -name = "wasm/no-match.wasm" -route = "/weka" -files = ["scripts/*.biscuits"] - -[[handler]] -name = "wasm/no-directory.wasm" -route = "/kokako" -files = ["biscuits/*.txt"] - -[[handler]] -name = "wasm/specific-file-missing.wasm" -route = "/piwakawaka" -files = ["scripts/important-but-does-not-exist.txt"] - -[[handler]] -name = "wasm/other-wasms.wasm" -route = "/kea" -files = ["wasm/no*.wasm"] diff --git a/testdata/app2/more-scripts/one.js b/testdata/app2/more-scripts/one.js deleted file mode 100644 index e2312a2..0000000 --- a/testdata/app2/more-scripts/one.js +++ /dev/null @@ -1 +0,0 @@ -function foo() { } diff --git a/testdata/app2/scripts/one.js b/testdata/app2/scripts/one.js deleted file mode 100644 index e2312a2..0000000 --- a/testdata/app2/scripts/one.js +++ /dev/null @@ -1 +0,0 @@ -function foo() { } diff --git a/testdata/app2/scripts/two.js b/testdata/app2/scripts/two.js deleted file mode 100644 index 45d4ebd..0000000 --- a/testdata/app2/scripts/two.js +++ /dev/null @@ -1,3 +0,0 @@ -function bar() { - console.log("bar bar bar"); -} \ No newline at end of file diff --git a/testdata/app2/styles/whizz.css b/testdata/app2/styles/whizz.css deleted file mode 100644 index 1a0f4ba..0000000 --- a/testdata/app2/styles/whizz.css +++ /dev/null @@ -1,3 +0,0 @@ -.fie { - font-size: xx-large; -} \ No newline at end of file diff --git a/testdata/app2/wasm/empty-assets.wasm b/testdata/app2/wasm/empty-assets.wasm deleted file mode 100644 index 3531bdb..0000000 --- a/testdata/app2/wasm/empty-assets.wasm +++ /dev/null @@ -1 +0,0 @@ -Tests handler with empty files array \ No newline at end of file diff --git a/testdata/app2/wasm/no-assets.wasm b/testdata/app2/wasm/no-assets.wasm deleted file mode 100644 index 97f639b..0000000 --- a/testdata/app2/wasm/no-assets.wasm +++ /dev/null @@ -1 +0,0 @@ -Tests handler with no files key \ No newline at end of file diff --git a/testdata/app2/wasm/no-directory.wasm b/testdata/app2/wasm/no-directory.wasm deleted file mode 100644 index fc6c1b5..0000000 --- a/testdata/app2/wasm/no-directory.wasm +++ /dev/null @@ -1 +0,0 @@ -Tests handler with a files directory that doesn't exist \ No newline at end of file diff --git a/testdata/app2/wasm/no-match.wasm b/testdata/app2/wasm/no-match.wasm deleted file mode 100644 index 7b6c137..0000000 --- a/testdata/app2/wasm/no-match.wasm +++ /dev/null @@ -1 +0,0 @@ -Tests handler where no files match spec \ No newline at end of file diff --git a/testdata/app2/wasm/other-wasms.wasm b/testdata/app2/wasm/other-wasms.wasm deleted file mode 100644 index ed3ca0d..0000000 --- a/testdata/app2/wasm/other-wasms.wasm +++ /dev/null @@ -1 +0,0 @@ -Tests requires-memberOf behaviour when an asset is also a handler \ No newline at end of file diff --git a/testdata/app2/wasm/specific-file-missing.wasm b/testdata/app2/wasm/specific-file-missing.wasm deleted file mode 100644 index 4dcfb83..0000000 --- a/testdata/app2/wasm/specific-file-missing.wasm +++ /dev/null @@ -1 +0,0 @@ -Tests handler that lists a specific file, which doesn't exist \ No newline at end of file diff --git a/testdata/bad_version/HIPPOFACTS b/testdata/bad_version/HIPPOFACTS deleted file mode 100644 index 94709c6..0000000 --- a/testdata/bad_version/HIPPOFACTS +++ /dev/null @@ -1,7 +0,0 @@ -[bindle] -name = "bad_version" -version = "1.2.3.4" - -[[handler]] -name = "out/fake.wasm" -route = "/fake" diff --git a/testdata/bad_version/out/fake.wasm b/testdata/bad_version/out/fake.wasm deleted file mode 100644 index eb6fa76..0000000 --- a/testdata/bad_version/out/fake.wasm +++ /dev/null @@ -1 +0,0 @@ -Supposedly Wasm but not really \ No newline at end of file diff --git a/testdata/docs-example/HIPPOFACTS b/testdata/docs-example/HIPPOFACTS deleted file mode 100644 index 623a408..0000000 --- a/testdata/docs-example/HIPPOFACTS +++ /dev/null @@ -1,20 +0,0 @@ -[bindle] -name = "birdsondemand" -version = "1.2.3" -description = "provides birds as a service" # optional -authors = ["Joan Q Programmer"] # optional - -[[handler]] -route = "/birds/flightless" -name = "bin/penguin.wasm" -files = ["photo/adelie.png", "photo/rockhopper.png", "stock/*.jpg"] - -[[handler]] -route = "/birds/irritable/fighty" -name = "bin/cassowary.wasm" -# files key is optional - -[[handler]] -route = "/birds/naughty" -name = "bin/kea.wasm" -files = ["stock/kea.jpg", "stock/wipers.jpg"] diff --git a/testdata/docs-example/bin/cassowary.wasm b/testdata/docs-example/bin/cassowary.wasm deleted file mode 100644 index 5192ae5..0000000 --- a/testdata/docs-example/bin/cassowary.wasm +++ /dev/null @@ -1 +0,0 @@ -cassowary \ No newline at end of file diff --git a/testdata/docs-example/bin/kea.wasm b/testdata/docs-example/bin/kea.wasm deleted file mode 100644 index bf454a0..0000000 --- a/testdata/docs-example/bin/kea.wasm +++ /dev/null @@ -1 +0,0 @@ -kea \ No newline at end of file diff --git a/testdata/docs-example/bin/penguin.wasm b/testdata/docs-example/bin/penguin.wasm deleted file mode 100644 index 6f72287..0000000 --- a/testdata/docs-example/bin/penguin.wasm +++ /dev/null @@ -1 +0,0 @@ -penguin \ No newline at end of file diff --git a/testdata/docs-example/photo/adelie.png b/testdata/docs-example/photo/adelie.png deleted file mode 100644 index 2b20f5d..0000000 Binary files a/testdata/docs-example/photo/adelie.png and /dev/null differ diff --git a/testdata/docs-example/photo/emperor.png b/testdata/docs-example/photo/emperor.png deleted file mode 100644 index 32c663a..0000000 Binary files a/testdata/docs-example/photo/emperor.png and /dev/null differ diff --git a/testdata/docs-example/photo/rockhopper.png b/testdata/docs-example/photo/rockhopper.png deleted file mode 100644 index 606c60e..0000000 Binary files a/testdata/docs-example/photo/rockhopper.png and /dev/null differ diff --git a/testdata/docs-example/stock/kea.jpg b/testdata/docs-example/stock/kea.jpg deleted file mode 100644 index d513aec..0000000 Binary files a/testdata/docs-example/stock/kea.jpg and /dev/null differ diff --git a/testdata/docs-example/stock/little-blue.jpg b/testdata/docs-example/stock/little-blue.jpg deleted file mode 100644 index 3608b68..0000000 Binary files a/testdata/docs-example/stock/little-blue.jpg and /dev/null differ diff --git a/testdata/docs-example/stock/little-blue.png b/testdata/docs-example/stock/little-blue.png deleted file mode 100644 index c373325..0000000 Binary files a/testdata/docs-example/stock/little-blue.png and /dev/null differ diff --git a/testdata/docs-example/stock/wipers.jpg b/testdata/docs-example/stock/wipers.jpg deleted file mode 100644 index c2c6648..0000000 Binary files a/testdata/docs-example/stock/wipers.jpg and /dev/null differ diff --git a/testdata/external1/HIPPOFACTS b/testdata/external1/HIPPOFACTS deleted file mode 100644 index 18d69fe..0000000 --- a/testdata/external1/HIPPOFACTS +++ /dev/null @@ -1,13 +0,0 @@ -[bindle] -name = "toastbattle" -version = "1.2.3" - -[[handler]] -route = "/battle" -name = "out/fake.wasm" - -[[handler]] -external.bindleId = "deislabs/fileserver/1.0.3" -external.handlerId = "static" -route = "/images" -files = ["toast/*.jpg"] diff --git a/testdata/external1/out/fake.js b/testdata/external1/out/fake.js deleted file mode 100644 index 0d37fc0..0000000 --- a/testdata/external1/out/fake.js +++ /dev/null @@ -1 +0,0 @@ -"This shouldn't be included in the invoice" diff --git a/testdata/external1/out/fake.wasm b/testdata/external1/out/fake.wasm deleted file mode 100644 index eb6fa76..0000000 --- a/testdata/external1/out/fake.wasm +++ /dev/null @@ -1 +0,0 @@ -Supposedly Wasm but not really \ No newline at end of file diff --git a/testdata/external1/out/lies.wasm b/testdata/external1/out/lies.wasm deleted file mode 100644 index 4a5c203..0000000 --- a/testdata/external1/out/lies.wasm +++ /dev/null @@ -1 +0,0 @@ -This isn't Wasm either \ No newline at end of file diff --git a/testdata/external1/toast/burnt.jpg b/testdata/external1/toast/burnt.jpg deleted file mode 100644 index d513aec..0000000 Binary files a/testdata/external1/toast/burnt.jpg and /dev/null differ diff --git a/testdata/external1/toast/light-brown.jpg b/testdata/external1/toast/light-brown.jpg deleted file mode 100644 index 3608b68..0000000 Binary files a/testdata/external1/toast/light-brown.jpg and /dev/null differ diff --git a/testdata/external1/toast/white.jpg b/testdata/external1/toast/white.jpg deleted file mode 100644 index c2c6648..0000000 Binary files a/testdata/external1/toast/white.jpg and /dev/null differ diff --git a/testdata/external2/HIPPOFACTS b/testdata/external2/HIPPOFACTS deleted file mode 100644 index 7308be8..0000000 --- a/testdata/external2/HIPPOFACTS +++ /dev/null @@ -1,13 +0,0 @@ -[bindle] -name = "toastbattle" -version = "1.2.3" - -[[handler]] -route = "/battle" -name = "out/fake.wasm" - -[[handler]] -external.bindleId = "deislabs/fileserver/1.0.3" -external.handlerId = "image_gallery" -route = "/images" -files = ["toast/*.jpg"] diff --git a/testdata/external2/out/fake.js b/testdata/external2/out/fake.js deleted file mode 100644 index 0d37fc0..0000000 --- a/testdata/external2/out/fake.js +++ /dev/null @@ -1 +0,0 @@ -"This shouldn't be included in the invoice" diff --git a/testdata/external2/out/fake.wasm b/testdata/external2/out/fake.wasm deleted file mode 100644 index eb6fa76..0000000 --- a/testdata/external2/out/fake.wasm +++ /dev/null @@ -1 +0,0 @@ -Supposedly Wasm but not really \ No newline at end of file diff --git a/testdata/external2/out/lies.wasm b/testdata/external2/out/lies.wasm deleted file mode 100644 index 4a5c203..0000000 --- a/testdata/external2/out/lies.wasm +++ /dev/null @@ -1 +0,0 @@ -This isn't Wasm either \ No newline at end of file diff --git a/testdata/external2/toast/burnt.jpg b/testdata/external2/toast/burnt.jpg deleted file mode 100644 index d513aec..0000000 Binary files a/testdata/external2/toast/burnt.jpg and /dev/null differ diff --git a/testdata/external2/toast/light-brown.jpg b/testdata/external2/toast/light-brown.jpg deleted file mode 100644 index 3608b68..0000000 Binary files a/testdata/external2/toast/light-brown.jpg and /dev/null differ diff --git a/testdata/external2/toast/white.jpg b/testdata/external2/toast/white.jpg deleted file mode 100644 index c2c6648..0000000 Binary files a/testdata/external2/toast/white.jpg and /dev/null differ diff --git a/testdata/external3/HIPPOFACTS b/testdata/external3/HIPPOFACTS deleted file mode 100644 index 3f4db5b..0000000 --- a/testdata/external3/HIPPOFACTS +++ /dev/null @@ -1,13 +0,0 @@ -[bindle] -name = "toastbattle" -version = "1.2.3" - -[[handler]] -route = "/battle" -name = "out/fake.wasm" - -[[handler]] -external.bindleId = "deislabs/fileserver/1.0.3" -external.handlerId = "image_gallery" -route = "/images" -files = ["toast/*.jpg", "*.db"] diff --git a/testdata/external3/out/fake.js b/testdata/external3/out/fake.js deleted file mode 100644 index 0d37fc0..0000000 --- a/testdata/external3/out/fake.js +++ /dev/null @@ -1 +0,0 @@ -"This shouldn't be included in the invoice" diff --git a/testdata/external3/out/fake.wasm b/testdata/external3/out/fake.wasm deleted file mode 100644 index eb6fa76..0000000 --- a/testdata/external3/out/fake.wasm +++ /dev/null @@ -1 +0,0 @@ -Supposedly Wasm but not really \ No newline at end of file diff --git a/testdata/external3/out/lies.wasm b/testdata/external3/out/lies.wasm deleted file mode 100644 index 4a5c203..0000000 --- a/testdata/external3/out/lies.wasm +++ /dev/null @@ -1 +0,0 @@ -This isn't Wasm either \ No newline at end of file diff --git a/testdata/external3/thumbnails.db b/testdata/external3/thumbnails.db deleted file mode 100644 index 0da9d99..0000000 --- a/testdata/external3/thumbnails.db +++ /dev/null @@ -1 +0,0 @@ -a clashy file \ No newline at end of file diff --git a/testdata/external3/toast/burnt.jpg b/testdata/external3/toast/burnt.jpg deleted file mode 100644 index d513aec..0000000 Binary files a/testdata/external3/toast/burnt.jpg and /dev/null differ diff --git a/testdata/external3/toast/light-brown.jpg b/testdata/external3/toast/light-brown.jpg deleted file mode 100644 index 3608b68..0000000 Binary files a/testdata/external3/toast/light-brown.jpg and /dev/null differ diff --git a/testdata/external3/toast/white.jpg b/testdata/external3/toast/white.jpg deleted file mode 100644 index c2c6648..0000000 Binary files a/testdata/external3/toast/white.jpg and /dev/null differ diff --git a/testdata/external_bad/HIPPOFACTS b/testdata/external_bad/HIPPOFACTS deleted file mode 100644 index 31ba29e..0000000 --- a/testdata/external_bad/HIPPOFACTS +++ /dev/null @@ -1,14 +0,0 @@ -[bindle] -name = "toastbattlebad" -version = "1.2.3" - -[[handler]] -route = "/battle" -name = "out/fake.wasm" - -[[handler]] -external.bindleId = "deislabs/fileserver/1.0.3" -external.handlerId = "static" -entrypoint = "no_no_no" -route = "/images" -files = ["toast/*.jpg"] diff --git a/testdata/external_bad/out/fake.js b/testdata/external_bad/out/fake.js deleted file mode 100644 index 0d37fc0..0000000 --- a/testdata/external_bad/out/fake.js +++ /dev/null @@ -1 +0,0 @@ -"This shouldn't be included in the invoice" diff --git a/testdata/external_bad/out/fake.wasm b/testdata/external_bad/out/fake.wasm deleted file mode 100644 index eb6fa76..0000000 --- a/testdata/external_bad/out/fake.wasm +++ /dev/null @@ -1 +0,0 @@ -Supposedly Wasm but not really \ No newline at end of file diff --git a/testdata/external_bad/out/lies.wasm b/testdata/external_bad/out/lies.wasm deleted file mode 100644 index 4a5c203..0000000 --- a/testdata/external_bad/out/lies.wasm +++ /dev/null @@ -1 +0,0 @@ -This isn't Wasm either \ No newline at end of file diff --git a/testdata/external_bad/toast/burnt.jpg b/testdata/external_bad/toast/burnt.jpg deleted file mode 100644 index d513aec..0000000 Binary files a/testdata/external_bad/toast/burnt.jpg and /dev/null differ diff --git a/testdata/external_bad/toast/light-brown.jpg b/testdata/external_bad/toast/light-brown.jpg deleted file mode 100644 index 3608b68..0000000 Binary files a/testdata/external_bad/toast/light-brown.jpg and /dev/null differ diff --git a/testdata/external_bad/toast/white.jpg b/testdata/external_bad/toast/white.jpg deleted file mode 100644 index c2c6648..0000000 Binary files a/testdata/external_bad/toast/white.jpg and /dev/null differ diff --git a/testdata/lib1/HIPPOFACTS b/testdata/lib1/HIPPOFACTS deleted file mode 100644 index 670a1f9..0000000 --- a/testdata/lib1/HIPPOFACTS +++ /dev/null @@ -1,13 +0,0 @@ -[bindle] -name = "server" -version = "1.0.0" - -[[export]] -name = "wasm/server.wasm" -id = "serve_all_the_things" - -[[export]] -name = "wasm/gallery.wasm" -entrypoint = "serve_pix" -id = "image_gallery" -files = ["gallery/images.db", "gallery/thumbnails.db"] diff --git a/testdata/lib1/gallery/images.db b/testdata/lib1/gallery/images.db deleted file mode 100644 index 10fabcd..0000000 --- a/testdata/lib1/gallery/images.db +++ /dev/null @@ -1 +0,0 @@ -I'm not actually a database you know \ No newline at end of file diff --git a/testdata/lib1/gallery/thumbnails.db b/testdata/lib1/gallery/thumbnails.db deleted file mode 100644 index 723f65f..0000000 --- a/testdata/lib1/gallery/thumbnails.db +++ /dev/null @@ -1 +0,0 @@ -I don't actually have any thumbs \ No newline at end of file diff --git a/testdata/lib1/wasm/gallery.wasm b/testdata/lib1/wasm/gallery.wasm deleted file mode 100644 index 389551f..0000000 --- a/testdata/lib1/wasm/gallery.wasm +++ /dev/null @@ -1 +0,0 @@ -Pretends to gallerise things but it's just 'avin' a giraffe \ No newline at end of file diff --git a/testdata/lib1/wasm/server.wasm b/testdata/lib1/wasm/server.wasm deleted file mode 100644 index d6288fe..0000000 --- a/testdata/lib1/wasm/server.wasm +++ /dev/null @@ -1 +0,0 @@ -Pretends to serve things but it's all a lie \ No newline at end of file diff --git a/testdata/nesttest/HIPPOFACTS b/testdata/nesttest/HIPPOFACTS deleted file mode 100644 index b95e213..0000000 --- a/testdata/nesttest/HIPPOFACTS +++ /dev/null @@ -1,8 +0,0 @@ -[bindle] -name = "weather" -version = "1.2.3" - -[[handler]] -name = "out/fake.wasm" -route = "/" -files = ["assets/**/*"] diff --git a/testdata/nesttest/assets/scripts/justsome.json b/testdata/nesttest/assets/scripts/justsome.json deleted file mode 100644 index 29d0ff3..0000000 --- a/testdata/nesttest/assets/scripts/justsome.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "fact": "this shouldn't be included in the bindle" -} \ No newline at end of file diff --git a/testdata/nesttest/assets/scripts/real.js b/testdata/nesttest/assets/scripts/real.js deleted file mode 100644 index 25db33c..0000000 --- a/testdata/nesttest/assets/scripts/real.js +++ /dev/null @@ -1,3 +0,0 @@ -function foo() { - console.log("This should be included in the bindle") -} diff --git a/testdata/nesttest/assets/styles/css/suspicious.css b/testdata/nesttest/assets/styles/css/suspicious.css deleted file mode 100644 index 3e01e9a..0000000 --- a/testdata/nesttest/assets/styles/css/suspicious.css +++ /dev/null @@ -1 +0,0 @@ -/* not a css file at all */ \ No newline at end of file diff --git a/testdata/nesttest/assets/styles/sass/iffy.sass b/testdata/nesttest/assets/styles/sass/iffy.sass deleted file mode 100644 index 7751cd5..0000000 --- a/testdata/nesttest/assets/styles/sass/iffy.sass +++ /dev/null @@ -1 +0,0 @@ -/* not an actual sass file */ diff --git a/testdata/nesttest/out/fake.wasm b/testdata/nesttest/out/fake.wasm deleted file mode 100644 index eb6fa76..0000000 --- a/testdata/nesttest/out/fake.wasm +++ /dev/null @@ -1 +0,0 @@ -Supposedly Wasm but not really \ No newline at end of file