From df8219ae78e447c30b90ef827f4f2fbf8e02af08 Mon Sep 17 00:00:00 2001 From: Gabbi Fisher Date: Tue, 20 Aug 2019 23:36:40 -0700 Subject: [PATCH] Add bulk upload to Workers KV (#445) Add bulk write functionality. Supports reading json files and directories --- Cargo.lock | 68 +++++++++++++++------- Cargo.toml | 1 + src/commands/kv/mod.rs | 4 +- src/commands/kv/write_bulk.rs | 106 ++++++++++++++++++++++++++++++++++ src/main.rs | 24 +++++++- 5 files changed, 177 insertions(+), 26 deletions(-) create mode 100644 src/commands/kv/write_bulk.rs diff --git a/Cargo.lock b/Cargo.lock index d3f69af76..29161d12b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,7 +61,7 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -116,12 +116,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2b_simd" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -259,16 +259,18 @@ dependencies = [ [[package]] name = "cloudflare" version = "0.1.0" -source = "git+https://github.com/cloudflare/cloudflare-rs.git#54b21d4f6fd2d48305f112a8e5e544918a28f87b" +source = "git+https://github.com/cloudflare/cloudflare-rs.git#12c17c27152ffabf20472a83be014e3919f63c5a" dependencies = [ "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_qs 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_with 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "slog-term 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -310,7 +312,7 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -701,7 +703,7 @@ dependencies = [ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "http 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", - "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "string 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -810,7 +812,7 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1114,7 +1116,7 @@ name = "num-integer" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1131,7 +1133,7 @@ name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1183,7 +1185,7 @@ name = "openssl-sys" version = "0.9.49" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-src 111.5.0+1.1.1c (registry+https://github.com/rust-lang/crates.io-index)", @@ -1359,7 +1361,7 @@ name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1389,7 +1391,7 @@ name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1475,7 +1477,7 @@ name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1545,7 +1547,7 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.9.19" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1587,7 +1589,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1748,6 +1750,25 @@ dependencies = [ "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_with" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_with_macros 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_with_macros" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "serde_yaml" version = "0.8.9" @@ -2383,13 +2404,14 @@ dependencies = [ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)", + "reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "text_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "which 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2457,13 +2479,13 @@ dependencies = [ "checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" "checksum assert_cmd 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2dc477793bd82ec39799b6f6b3df64938532fdf2ab0d49ef817eac65856a5a1e" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" +"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" "checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55" "checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum binary-install 0.0.3-alpha (registry+https://github.com/rust-lang/crates.io-index)" = "a81dda17f2dbba8271cf61f2ea3e48e3da8aef31665731bce48818cc07863f06" "checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" -"checksum blake2b_simd 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "461f4b879a8eb70c1debf7d0788a9a5ff15f1ea9d25925fea264ef4258bed6b2" +"checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499" "checksum block-buffer 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" "checksum block-padding 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6d4dc3af3ee2e12f3e5d224e5e1e3d73668abbeb69e566d361f7d5563a4fdf09" "checksum bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94cdf78eb7e94c566c1f5dbe2abf8fc70a548fc902942a48c4b3a98b48ca9ade" @@ -2482,7 +2504,7 @@ dependencies = [ "checksum cloudflare 0.1.0 (git+https://github.com/cloudflare/cloudflare-rs.git)" = "" "checksum config 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9107d78ed62b3fa5a86e7d18e647abed48cfd8f8fab6c72f4cdb982d196f7e6" "checksum console 0.7.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8ca57c2c14b8a2bf3105bc9d15574aad80babf6a9c44b1058034cdf8bd169628" -"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" +"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum cookie 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" "checksum cookie_store 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46750b3f362965f197996c4448e4a0935e791bf7d6631bfce9ee0af3d24c919c" "checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" @@ -2538,7 +2560,7 @@ dependencies = [ "checksum hyper-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3a800d6aa50af4b5850b2b0f659625ce9504df908e9733b635720483be26174f" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" +"checksum indexmap 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4d6d89e0948bf10c08b9ecc8ac5b83f07f857ebe2c0cbe38de15b4e4f510356" "checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718" "checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" @@ -2624,7 +2646,7 @@ dependencies = [ "checksum regex-automata 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "92b73c2a1770c255c240eaa4ee600df1704a38dc3feaa6e949e7fcd4f8dc09f9" "checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum reqwest 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0777154c2c3eb54f5c480db01de845652d941e47191277cc673634c3853939" +"checksum reqwest 0.9.20 (registry+https://github.com/rust-lang/crates.io-index)" = "0f6d896143a583047512e59ac54a215cb203c29cc941917343edea3be8df9c78" "checksum rle-decode-fast 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" "checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" "checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" @@ -2647,6 +2669,8 @@ dependencies = [ "checksum serde_qs 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "35965fa1d2413717053d67c2df1f5c3e1763fbf77200ea7e767523707bd5a0af" "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" "checksum serde_urlencoded 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "642dd69105886af2efd227f75a520ec9b44a820d65bc133a9131f7d229fd165a" +"checksum serde_with 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32dc67e726b4b06ccf46860bef46fe713fffde11181d6c3c2f3104a670ceddb1" +"checksum serde_with_macros 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6304d92ad5493e340b95c353b8328c312d020f0eb5cb6df8506f160f5b7300d" "checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" "checksum sha-1 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23962131a91661d643c98940b20fcaffe62d776a823247be80a48fcb8b6fce68" "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" diff --git a/Cargo.toml b/Cargo.toml index 340df202c..9176404e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ prettytable-rs = "0.8.0" notify = "4.0.12" ws = "0.9.0" url = "2.1.0" +walkdir = "2.2.9" percent-encoding = "1.0.1" [dev-dependencies] diff --git a/src/commands/kv/mod.rs b/src/commands/kv/mod.rs index 4413aeb38..9a7bf739c 100644 --- a/src/commands/kv/mod.rs +++ b/src/commands/kv/mod.rs @@ -11,6 +11,7 @@ mod delete_namespace; mod list_namespaces; mod read_key; mod rename_namespace; +mod write_bulk; mod write_key; pub use create_namespace::create_namespace; @@ -18,6 +19,7 @@ pub use delete_namespace::delete_namespace; pub use list_namespaces::list_namespaces; pub use read_key::read_key; pub use rename_namespace::rename_namespace; +pub use write_bulk::write_bulk; pub use write_key::write_key; fn api_client() -> Result { @@ -39,7 +41,7 @@ fn print_error(e: ApiFailure) { match e { ApiFailure::Error(_status, api_errors) => { for error in api_errors.errors { - message::warn(&format!("Error {}: {}", error.code, error.message,)); + message::warn(&format!("Error {}: {}", error.code, error.message)); let suggestion = help(error.code); if !suggestion.is_empty() { diff --git a/src/commands/kv/write_bulk.rs b/src/commands/kv/write_bulk.rs new file mode 100644 index 000000000..e3406c4fb --- /dev/null +++ b/src/commands/kv/write_bulk.rs @@ -0,0 +1,106 @@ +extern crate base64; + +use cloudflare::framework::apiclient::ApiClient; +use walkdir::WalkDir; + +use std::ffi::OsString; +use std::fs; +use std::fs::metadata; +use std::path::Path; + +use cloudflare::endpoints::workerskv::write_bulk::KeyValuePair; +use cloudflare::endpoints::workerskv::write_bulk::WriteBulk; +use failure::bail; + +use crate::terminal::message; + +pub fn write_bulk(namespace_id: &str, filename: &Path) -> Result<(), failure::Error> { + let client = super::api_client()?; + let account_id = super::account_id()?; + + // If the provided argument for write_bulk is a json file, parse it + // and upload its contents. If the argument is a directory, create key-value + // pairs where keys are the relative pathnames of files in the directory, and + // values are the base64-encoded contents of those files. + let mut data; + let pairs: Result, failure::Error> = match metadata(filename) { + Ok(ref file_type) if file_type.is_file() => { + data = fs::read_to_string(filename)?; + Ok(serde_json::from_str(&data)?) + } + Ok(ref file_type) if file_type.is_dir() => parse_directory(filename), + Ok(_file_type) => { + // any other file types (namely, symlinks) + bail!( + "Cannot upload a file that is a symlink: {}", + filename.display() + ) + } + Err(e) => bail!(e), + }; + + let response = client.request(&WriteBulk { + account_identifier: &account_id, + namespace_identifier: namespace_id, + bulk_key_value_pairs: pairs?, + }); + + match response { + Ok(_success) => message::success("Success"), + Err(e) => super::print_error(e), + } + + Ok(()) +} + +fn parse_directory(directory: &Path) -> Result, failure::Error> { + let mut upload_vec: Vec = Vec::new(); + for entry in WalkDir::new(directory) { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_file() { + let key = generate_key(path, directory)?; + + let value = std::fs::read(path)?; + + // Need to base64 encode value + let b64_value = base64::encode(&value); + message::working(&format!("Uploading {}...", key.clone())); + upload_vec.push(KeyValuePair { + key: key, + value: b64_value, + expiration: None, + expiration_ttl: None, + base64: Some(true), + }); + } + } + Ok(upload_vec) +} + +// Courtesy of Steve Kalabnik's PoC :) +fn generate_key(path: &Path, directory: &Path) -> Result { + let path = path.strip_prefix(directory).unwrap(); + + // next, we have to re-build the paths: if we're on Windows, we have paths with + // `\` as separators. But we want to use `/` as separators. Because that's how URLs + // work. + let mut path_with_forward_slash = OsString::new(); + + for (i, component) in path.components().enumerate() { + // we don't want a leading `/`, so skip that + if i > 0 { + path_with_forward_slash.push("/"); + } + + path_with_forward_slash.push(component); + } + + // if we have a non-utf8 path here, it will fail, but that's not realistically going to happen + let path = path_with_forward_slash.to_str().expect(&format!( + "found a non-UTF-8 path, {:?}", + path_with_forward_slash + )); + + Ok(path.to_string()) +} diff --git a/src/main.rs b/src/main.rs index 4d90c6816..821956f7c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate text_io; use std::env; +use std::path::Path; use std::str::FromStr; use clap::{App, AppSettings, Arg, SubCommand}; @@ -121,6 +122,20 @@ fn run() -> Result<(), failure::Error> { .help("the value passed in is a filename; open and upload its contents"), ) ) + .subcommand( + SubCommand::with_name("write-bulk") + .about("upload multiple key-value pairs at once") + .arg( + Arg::with_name("id") + .help("the id of your Workers KV namespace") + .index(1), + ) + .arg( + Arg::with_name("path") + .help("the json file of key-value pairs to upload, in form [{\"key\":..., \"value\":...}\"...] OR the directory of files to upload.") + .index(2), + ) + ) ) .subcommand( SubCommand::with_name("generate") @@ -339,7 +354,7 @@ fn run() -> Result<(), failure::Error> { let title = rename_matches.value_of("title").unwrap(); commands::kv::rename_namespace(id, title)?; } - ("list", Some(_create_matches)) => { + ("list", Some(_list_matches)) => { commands::kv::list_namespaces()?; } ("read-key", Some(read_key_matches)) => { @@ -347,7 +362,6 @@ fn run() -> Result<(), failure::Error> { let user = settings::global_user::GlobalUser::new()?; let id = read_key_matches.value_of("id").unwrap(); let key = read_key_matches.value_of("key").unwrap(); - commands::kv::read_key(&project, &user, id, key)?; } ("write-key", Some(write_key_matches)) => { @@ -362,9 +376,13 @@ fn run() -> Result<(), failure::Error> { }; let expiration = write_key_matches.value_of("expiration"); let ttl = write_key_matches.value_of("expiration-ttl"); - commands::kv::write_key(&project, &user, id, key, value, is_file, expiration, ttl)?; } + ("write-bulk", Some(write_bulk_matches)) => { + let id = write_bulk_matches.value_of("id").unwrap(); + let filename = write_bulk_matches.value_of("path").unwrap(); + commands::kv::write_bulk(id, Path::new(filename))?; + } ("", None) => message::warn("kv expects a subcommand"), _ => unreachable!(), }