Skip to content
This repository has been archived by the owner on Aug 3, 2023. It is now read-only.

Commit

Permalink
Add bucket::upload, bucket::delete
Browse files Browse the repository at this point in the history
  • Loading branch information
ashleymichal committed Sep 3, 2019
1 parent 810f5ab commit 0ed02e8
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 3 deletions.
103 changes: 103 additions & 0 deletions src/commands/kv/bucket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
extern crate base64;

use crate::commands::kv::delete_bulk::delete_bulk;
use crate::commands::kv::write_bulk::write_bulk;

use cloudflare::endpoints::workerskv::write_bulk::KeyValuePair;

use walkdir::WalkDir;

use std::ffi::OsString;
use std::fs::metadata;
use std::path::Path;

use failure::bail;

use crate::terminal::message;

pub fn upload(namespace_id: &str, filename: &Path) -> Result<(), failure::Error> {
let pairs: Result<Vec<KeyValuePair>, failure::Error> = match metadata(filename) {
Ok(ref file_type) if file_type.is_dir() => parse_directory(filename),
Ok(_file_type) => {
// any other file types (namely, symlinks)
bail!("wrangler kv:bucket upload takes a directory",)
}
Err(e) => bail!(e),
};

write_bulk(namespace_id, pairs?)
}

pub fn delete(namespace_id: &str, filename: &Path) -> Result<(), failure::Error> {
let keys: Result<Vec<String>, failure::Error> = match metadata(filename) {
Ok(ref file_type) if file_type.is_dir() => {
let key_value_pairs = parse_directory(filename)?;
Ok(key_value_pairs
.iter()
.map(|kv| kv.key.clone())
.collect::<Vec<_>>())
}
Ok(_file_type) => {
// any other file types (namely, symlinks)
bail!(
"{} should be a file or directory, but is a symlink",
filename.display()
)
}
Err(e) => bail!(e),
};

delete_bulk(namespace_id, keys?)
}

fn parse_directory(directory: &Path) -> Result<Vec<KeyValuePair>, failure::Error> {
let mut upload_vec: Vec<KeyValuePair> = 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!("Parsing {}...", 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 :) Used for bulk operations (write, delete)
fn generate_key(path: &Path, directory: &Path) -> Result<String, failure::Error> {
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())
}
2 changes: 1 addition & 1 deletion src/commands/kv/delete_bulk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub fn delete_json(namespace_id: &str, filename: &Path) -> Result<(), failure::E
delete_bulk(namespace_id, keys?)
}

fn delete_bulk(namespace_id: &str, keys: Vec<String>) -> Result<(), failure::Error> {
pub fn delete_bulk(namespace_id: &str, keys: Vec<String>) -> Result<(), failure::Error> {
let client = super::api_client()?;
let account_id = super::account_id()?;

Expand Down
1 change: 1 addition & 0 deletions src/commands/kv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use http::status::StatusCode;
use crate::settings;
use crate::terminal::message;

pub mod bucket;
mod create_namespace;
mod delete_bulk;
mod delete_key;
Expand Down
2 changes: 1 addition & 1 deletion src/commands/kv/write_bulk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn write_json(namespace_id: &str, filename: &Path) -> Result<(), failure::Er
write_bulk(namespace_id, pairs?)
}

fn write_bulk(namespace_id: &str, pairs: Vec<KeyValuePair>) -> Result<(), failure::Error> {
pub fn write_bulk(namespace_id: &str, pairs: Vec<KeyValuePair>) -> Result<(), failure::Error> {
let client = super::api_client()?;
let account_id = super::account_id()?;

Expand Down
2 changes: 1 addition & 1 deletion src/commands/publish/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ fn upload_bucket(project: &Project) -> Result<(), failure::Error> {
Ok(ref file_type) if file_type.is_dir() => {
println!("Publishing contents of directory {:?}", path.as_os_str());

kv::write_bulk(&namespace.id, Path::new(&path))?;
kv::bucket::upload(&namespace.id, Path::new(&path))?;
}
Ok(file_type) => {
// any other file types (namely, symlinks)
Expand Down
60 changes: 60 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,51 @@ fn run() -> Result<(), failure::Error> {
)
)
)
.subcommand(
SubCommand::with_name("kv:bucket")
.about(&*format!(
"{} Use KV as bucket-style storage",
emoji::KV
))
.subcommand(
SubCommand::with_name("upload")
.about("Upload the contents of a directory keyed on path")
.arg(
Arg::with_name("namespace-id")
.help("The ID of the namespace this action applies to")
.required(true)
// .short("n")
// .long("namespace-id")
// .value_name("<ID>")
// .takes_value(true)
)
.arg(
Arg::with_name("path")
.help("the directory to be uploaded to KV")
.required(true)
.index(2),
)
)
.subcommand(
SubCommand::with_name("delete")
.about("Delete the contents of a directory keyed on path")
.arg(
Arg::with_name("namespace-id")
.help("The ID of the namespace this action applies to")
.required(true)
// .short("n")
// .long("namespace-id")
// .value_name("<ID>")
// .takes_value(true)
)
.arg(
Arg::with_name("path")
.help("the directory to be deleted from KV")
.required(true)
.index(2),
)
)
)
.subcommand(
SubCommand::with_name("generate")
.about(&*format!(
Expand Down Expand Up @@ -518,6 +563,21 @@ fn run() -> Result<(), failure::Error> {
("", None) => message::warn("kv:bulk expects a subcommand"),
_ => unreachable!(),
}
} else if let Some(kv_matches) = matches.subcommand_matches("kv:bucket") {
match kv_matches.subcommand() {
("upload", Some(write_bulk_matches)) => {
let id = write_bulk_matches.value_of("namespace-id").unwrap();
let path = write_bulk_matches.value_of("path").unwrap();
commands::kv::bucket::upload(id, Path::new(path))?;
}
("delete", Some(delete_matches)) => {
let id = delete_matches.value_of("namespace-id").unwrap();
let path = delete_matches.value_of("path").unwrap();
commands::kv::bucket::delete(id, Path::new(path))?;
}
("", None) => message::warn("kv:bucket expects a subcommand"),
_ => unreachable!(),
}
}
Ok(())
}

0 comments on commit 0ed02e8

Please sign in to comment.