Shared helper: construct an `ObjectStore` from endpoint / S3 credentials or fall back to `LocalFileSystem` when the endpoint is empty.
(
endpoint: &str,
bucket: &str,
region: &str,
access_key: &str,
secret_key: &str,
local_dir: &std::path::Path,
label: &str,
)
| 90 | /// Shared helper: construct an `ObjectStore` from endpoint / S3 credentials or |
| 91 | /// fall back to `LocalFileSystem` when the endpoint is empty. |
| 92 | fn build_object_store( |
| 93 | endpoint: &str, |
| 94 | bucket: &str, |
| 95 | region: &str, |
| 96 | access_key: &str, |
| 97 | secret_key: &str, |
| 98 | local_dir: &std::path::Path, |
| 99 | label: &str, |
| 100 | ) -> crate::Result<Arc<dyn ObjectStore>> { |
| 101 | if endpoint.is_empty() { |
| 102 | // no-objectstore: bootstrap for the LocalFileSystem ObjectStore backend; the store cannot create its own root. |
| 103 | std::fs::create_dir_all(local_dir).map_err(crate::Error::Io)?; |
| 104 | let store = |
| 105 | LocalFileSystem::new_with_prefix(local_dir).map_err(|e| crate::Error::Storage { |
| 106 | engine: label.into(), |
| 107 | detail: format!("local {label} storage init: {e}"), |
| 108 | })?; |
| 109 | Ok(Arc::new(store)) |
| 110 | } else { |
| 111 | let mut builder = AmazonS3Builder::new() |
| 112 | .with_endpoint(endpoint) |
| 113 | .with_bucket_name(bucket) |
| 114 | .with_region(region) |
| 115 | .with_allow_http(endpoint.starts_with("http://")); |
| 116 | if !access_key.is_empty() { |
| 117 | builder = builder |
| 118 | .with_access_key_id(access_key) |
| 119 | .with_secret_access_key(secret_key); |
| 120 | } |
| 121 | let s3 = builder.build().map_err(|e| crate::Error::Storage { |
| 122 | engine: label.into(), |
| 123 | detail: format!("S3 {label} client init: {e}"), |
| 124 | })?; |
| 125 | Ok(Arc::new(s3)) |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | /// Snapshot manifest: stored as `manifest.msgpack` inside the snapshot prefix. |
| 130 | #[derive( |
no test coverage detected