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

Asset Manifest #629

Merged
merged 11 commits into from
Sep 19, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ walkdir = "2.2.9"
percent-encoding = "1.0.1"
http = "0.1.1"
regex = "1"
sha2 = "0.8.0"
data-encoding = "2.1.2"

[dev-dependencies]
assert_cmd = "0.11.1"
Expand Down
47 changes: 38 additions & 9 deletions src/commands/kv/bucket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ mod delete;
mod sync;
mod upload;

use data_encoding::HEXLOWER;
use sha2::{Digest, Sha256};

pub use delete::delete;
pub use sync::sync;
pub use upload::upload;

use std::collections::HashMap;
use std::ffi::OsString;
use std::path::Path;

Expand All @@ -17,29 +21,35 @@ use walkdir::WalkDir;

use crate::terminal::message;

fn directory_keys_values(directory: &Path) -> Result<Vec<KeyValuePair>, failure::Error> {
pub fn directory_keys_values(
directory: &Path,
) -> Result<(Vec<KeyValuePair>, HashMap<String, String>), failure::Error> {
let mut upload_vec: Vec<KeyValuePair> = Vec::new();
let mut key_manifest: HashMap<String, String> = HashMap::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);

let (path, key) = generate_key(path, directory, Some(b64_value.clone()))?;

message::working(&format!("Parsing {}...", key.clone()));
upload_vec.push(KeyValuePair {
key,
key: key.clone(),
value: b64_value,
expiration: None,
expiration_ttl: None,
base64: Some(true),
});
key_manifest.insert(path, key);
}
}
Ok(upload_vec)
Ok((upload_vec, key_manifest))
}

fn directory_keys_only(directory: &Path) -> Result<Vec<String>, failure::Error> {
Expand All @@ -48,16 +58,28 @@ fn directory_keys_only(directory: &Path) -> Result<Vec<String>, failure::Error>
let entry = entry.unwrap();
let path = entry.path();
if path.is_file() {
let key = generate_key(path, directory)?;
let (key, _) = generate_key(path, directory, None)?;

upload_vec.push(key);
}
}
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> {
fn get_digest(value: String) -> Result<String, failure::Error> {
let mut hasher = Sha256::new();
hasher.input(value);
let digest = hasher.result();
let hex_digest = HEXLOWER.encode(digest.as_ref());
Ok(hex_digest)
}

// Courtesy of Steve Klabnik's PoC :) Used for bulk operations (write, delete)
fn generate_key(
path: &Path,
directory: &Path,
value: Option<String>,
) -> Result<(String, 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
Expand All @@ -79,5 +101,12 @@ fn generate_key(path: &Path, directory: &Path) -> Result<String, failure::Error>
.to_str()
.unwrap_or_else(|| panic!("found a non-UTF-8 path, {:?}", path_with_forward_slash));

Ok(path.to_string())
let path_with_hash = if let Some(value) = value {
let digest = get_digest(value)?;
format!("{}-{}", path, digest)
} else {
path.to_string()
};

Ok((path.to_string(), path_with_hash))
}
11 changes: 7 additions & 4 deletions src/commands/kv/bucket/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::fs::metadata;
use std::path::Path;

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

use failure::format_err;
use crate::commands::kv::bucket::directory_keys_values;
use crate::commands::kv::bulk::put::put_bulk;
use crate::settings::global_user::GlobalUser;
Expand All @@ -24,12 +24,15 @@ pub fn upload(
path: &Path,
) -> Result<(), failure::Error> {
let mut pairs: Vec<KeyValuePair> = match &metadata(path) {
Ok(file_type) if file_type.is_dir() => directory_keys_values(path),
Ok(file_type) if file_type.is_dir() => {
let (p, _) = directory_keys_values(path)?;
Ok(p)
}
Ok(_file_type) => {
// any other file types (files, symlinks)
failure::bail!("wrangler kv:bucket upload takes a directory")
Err(format_err!("wrangler kv:bucket upload takes a directory"))
}
Err(e) => failure::bail!("{}", e),
Err(e) => Err(format_err!("{}", e)),
}?;

validate_file_uploads(pairs.clone())?;
Expand Down
37 changes: 32 additions & 5 deletions src/commands/publish/upload_form/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
mod project_assets;
mod text_blob;
mod wasm_module;

use reqwest::multipart::{Form, Part};
use std::fs;
use std::path::Path;

use crate::commands::build::wranglerjs;
use crate::commands::kv::bucket::directory_keys_values;
use crate::settings::binding;

use crate::settings::metadata::Metadata;
use crate::settings::target::kv_namespace;
use crate::settings::target::{Target, TargetType};

use project_assets::ProjectAssets;
use text_blob::TextBlob;
use wasm_module::WasmModule;

use super::{krate, Package};
Expand All @@ -34,7 +36,8 @@ pub fn build_script_upload_form(target: &Target) -> Result<Form, failure::Error>

let script_path = "./worker/generated/script.js".to_string();

let assets = ProjectAssets::new(script_path, vec![wasm_module], kv_namespaces)?;
let assets =
ProjectAssets::new(script_path, vec![wasm_module], kv_namespaces, Vec::new())?;

build_form(&assets)
}
Expand All @@ -45,7 +48,7 @@ pub fn build_script_upload_form(target: &Target) -> Result<Form, failure::Error>

let script_path = package.main()?;

let assets = ProjectAssets::new(script_path, Vec::new(), kv_namespaces)?;
let assets = ProjectAssets::new(script_path, Vec::new(), kv_namespaces, Vec::new())?;
EverlastingBugstopper marked this conversation as resolved.
Show resolved Hide resolved

build_form(&assets)
}
Expand All @@ -63,16 +66,32 @@ pub fn build_script_upload_form(target: &Target) -> Result<Form, failure::Error>
let path = bundle.wasm_path();
let binding = bundle.get_wasm_binding();
let wasm_module = WasmModule::new(path, binding)?;
wasm_modules.push(wasm_module)
wasm_modules.push(wasm_module);
}

let assets = ProjectAssets::new(script_path, wasm_modules, kv_namespaces)?;
let mut text_blobs = Vec::new();

if let Some(site) = &target.site {
let binding = "__STATIC_CONTENT_MANFIEST".to_string();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer making this a const, if possible :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calls in constants are limited to constant functions, tuple structs and tuple variants

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made with <3 from the compiler

let asset_manifest = get_asset_manifest(&site.bucket)?;
let text_blob = TextBlob::new(asset_manifest, binding)?;
text_blobs.push(text_blob);
}

let assets = ProjectAssets::new(script_path, wasm_modules, kv_namespaces, text_blobs)?;

build_form(&assets)
}
}
}

fn get_asset_manifest(directory: &String) -> Result<String, failure::Error> {
let directory = Path::new(&directory);
let (_, manifest) = directory_keys_values(directory)?;
let manifest = serde_json::to_string(&manifest)?;
Ok(manifest)
}

fn build_form(assets: &ProjectAssets) -> Result<Form, failure::Error> {
let mut form = Form::new();

Expand All @@ -93,6 +112,14 @@ fn add_files(mut form: Form, assets: &ProjectAssets) -> Result<Form, failure::Er
form = form.file(wasm_module.filename(), wasm_module.path())?;
}

for text_blob in &assets.text_blobs {
let part = Part::text(text_blob.data.clone())
.file_name(text_blob.binding.clone())
.mime_str("text/plain")?;

form = form.part(text_blob.binding.clone(), part);
}

Ok(form)
}

Expand Down
8 changes: 8 additions & 0 deletions src/commands/publish/upload_form/project_assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use failure::format_err;
use super::binding::Binding;
use super::filename_from_path;
use super::kv_namespace::KvNamespace;
use super::text_blob::TextBlob;
use super::wasm_module::WasmModule;

#[derive(Debug)]
Expand All @@ -11,13 +12,15 @@ pub struct ProjectAssets {
script_path: String,
pub wasm_modules: Vec<WasmModule>,
pub kv_namespaces: Vec<KvNamespace>,
pub text_blobs: Vec<TextBlob>,
}

impl ProjectAssets {
pub fn new(
script_path: String,
wasm_modules: Vec<WasmModule>,
kv_namespaces: Vec<KvNamespace>,
text_blobs: Vec<TextBlob>,
) -> Result<Self, failure::Error> {
let script_name = filename_from_path(&script_path)
.ok_or_else(|| format_err!("filename should not be empty: {}", script_path))?;
Expand All @@ -27,6 +30,7 @@ impl ProjectAssets {
script_path,
wasm_modules,
kv_namespaces,
text_blobs,
})
}

Expand All @@ -41,6 +45,10 @@ impl ProjectAssets {
let binding = kv.binding();
bindings.push(binding);
}
for blob in &self.text_blobs {
let binding = blob.binding();
bindings.push(binding);
}

bindings
}
Expand Down
18 changes: 18 additions & 0 deletions src/commands/publish/upload_form/text_blob.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use super::binding::Binding;
use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
pub struct TextBlob {
pub data: String,
pub binding: String,
}

impl TextBlob {
pub fn new(data: String, binding: String) -> Result<Self, failure::Error> {
Ok(Self { data, binding })
}

pub fn binding(&self) -> Binding {
Binding::new_text_blob(self.binding.clone(), self.binding.clone())
}
}
6 changes: 6 additions & 0 deletions src/settings/binding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub enum Binding {
WasmModule { name: String, part: String },
#[serde(rename = "kv_namespace")]
KvNamespace { name: String, namespace_id: String },
#[serde(rename = "text_blob")]
TextBlob { name: String, part: String },
}

impl Binding {
Expand All @@ -20,4 +22,8 @@ impl Binding {
pub fn new_kv_namespace(name: String, namespace_id: String) -> Binding {
Binding::KvNamespace { name, namespace_id }
}

pub fn new_text_blob(name: String, part: String) -> Binding {
Binding::TextBlob { name, part }
}
}