From db5a3099235f83eb12eb3c9042799e31b57ef07f Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 4 Mar 2026 15:04:14 +0100 Subject: [PATCH 1/3] build(deps): Bump objectstore-client to 0.1.2 --- Cargo.lock | 8 ++++---- Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 72afa7f2a2..ec1ba5eb31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2322,9 +2322,9 @@ dependencies = [ [[package]] name = "objectstore-client" -version = "0.0.19" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcaf8bc0ea7c50905631df108126c6a075ce5a9c16713ec4b68cc872a408e08" +checksum = "033eedf125e31b30962c0172842e964fc9983bbccd99d9ff033e7e413946861c" dependencies = [ "async-compression", "async-stream", @@ -2346,9 +2346,9 @@ dependencies = [ [[package]] name = "objectstore-types" -version = "0.0.19" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f190038e8988112a4e593f1796612941117d88753574ef6476f99324d4605aae" +checksum = "956cbdef3971ea108a15e5248625d6229870da3a3c637b6e7aada213526f8014" dependencies = [ "http", "humantime", diff --git a/Cargo.toml b/Cargo.toml index 728aea4c73..a54e6d5f3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ java-properties = "2.0.0" lazy_static = "1.4.0" libc = "0.2.139" log = { version = "0.4.17", features = ["std"] } -objectstore-client = { version = "0.0.19" , default-features = false, features = ["native-tls"] } +objectstore-client = { version = "0.1.2" , default-features = false, features = ["native-tls"] } open = "3.2.0" parking_lot = "0.12.1" percent-encoding = "2.2.0" From 8555c09a1a627f6eb643141a8e13cda6a8c4498c Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 4 Mar 2026 17:54:21 +0100 Subject: [PATCH 2/3] ref(snapshots): Use file-based upload for objectstore puts Use `put_file` instead of `put` when uploading images to objectstore, streaming file contents from disk rather than loading entire files into memory. Hash computation also now uses buffered reads. Co-Authored-By: Claude Opus 4.6 --- src/commands/build/snapshots.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/commands/build/snapshots.rs b/src/commands/build/snapshots.rs index 89f2d387c4..a6e4176bae 100644 --- a/src/commands/build/snapshots.rs +++ b/src/commands/build/snapshots.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::fs; use std::path::{Path, PathBuf}; use std::str::FromStr as _; @@ -10,6 +9,7 @@ use log::{debug, info, warn}; use objectstore_client::{ClientBuilder, ExpirationPolicy, Usecase}; use secrecy::ExposeSecret as _; use sha2::{Digest as _, Sha256}; +use tokio::fs::File; use walkdir::WalkDir; use crate::api::{Api, CreateSnapshotResponse, ImageMetadata, SnapshotsManifest}; @@ -174,11 +174,24 @@ fn collect_image_info(dir: &Path, path: &Path) -> Option { }) } -fn compute_sha256_hash(data: &[u8]) -> String { +fn compute_sha256_hash(path: &Path) -> Result { + use std::io::Read as _; + + let mut file = std::fs::File::open(path) + .with_context(|| format!("Failed to open image for hashing: {}", path.display()))?; let mut hasher = Sha256::new(); - hasher.update(data); + let mut buffer = [0u8; 8192]; + loop { + let bytes_read = file + .read(&mut buffer) + .with_context(|| format!("Failed to read image for hashing: {}", path.display()))?; + if bytes_read == 0 { + break; + } + hasher.update(&buffer[..bytes_read]); + } let result = hasher.finalize(); - format!("{result:x}") + Ok(format!("{result:x}")) } fn is_hidden(root: &Path, path: &Path) -> bool { @@ -236,15 +249,16 @@ fn upload_images( for image in images { debug!("Processing image: {}", image.path.display()); - let contents = fs::read(&image.path) - .with_context(|| format!("Failed to read image: {}", image.path.display()))?; - let hash = compute_sha256_hash(&contents); + let hash = compute_sha256_hash(&image.path)?; + let file = runtime.block_on(File::open(&image.path)).with_context(|| { + format!("Failed to open image for upload: {}", image.path.display()) + })?; info!("Queueing {} as {hash}", image.relative_path.display()); many_builder = many_builder.push( session - .put(contents) + .put_file(file) .key(&hash) .expiration_policy(expiration), ); From 953067769627f8d3a20d068f6f18a0a27dd3334c Mon Sep 17 00:00:00 2001 From: lcian <17258265+lcian@users.noreply.github.com> Date: Wed, 4 Mar 2026 19:35:46 +0100 Subject: [PATCH 3/3] fix(snapshots): Resolve duplicate `File` import causing compilation failure Co-Authored-By: Claude Opus 4.6 --- src/commands/build/snapshots.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/commands/build/snapshots.rs b/src/commands/build/snapshots.rs index 3ed37fe6ac..6b66563899 100644 --- a/src/commands/build/snapshots.rs +++ b/src/commands/build/snapshots.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::fs::{self, File}; +use std::fs::File; use std::io::BufReader; use std::path::{Path, PathBuf}; use std::str::FromStr as _; @@ -13,7 +13,6 @@ use objectstore_client::{ClientBuilder, ExpirationPolicy, Usecase}; use secrecy::ExposeSecret as _; use serde_json::Value; use sha2::{Digest as _, Sha256}; -use tokio::fs::File; use walkdir::WalkDir; use crate::api::{Api, CreateSnapshotResponse, ImageMetadata, SnapshotsManifest}; @@ -312,9 +311,11 @@ fn upload_images( debug!("Processing image: {}", image.path.display()); let hash = compute_sha256_hash(&image.path)?; - let file = runtime.block_on(File::open(&image.path)).with_context(|| { - format!("Failed to open image for upload: {}", image.path.display()) - })?; + let file = runtime + .block_on(tokio::fs::File::open(&image.path)) + .with_context(|| { + format!("Failed to open image for upload: {}", image.path.display()) + })?; info!("Queueing {} as {hash}", image.relative_path.display());