Skip to content

Commit 0f51ccc

Browse files
committed
Updates
1 parent ef67db9 commit 0f51ccc

2 files changed

Lines changed: 46 additions & 68 deletions

File tree

src/api/data_types/snapshots.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,15 @@ pub struct SnapshotsManifest {
2222

2323
// Keep in sync with https://github.com/getsentry/sentry/blob/master/src/sentry/preprod/snapshots/manifest.py
2424
/// Metadata for a single image in a snapshot manifest.
25+
///
26+
/// The `image_file_name`, `width`, and `height` fields are set by the CLI.
27+
/// Any additional fields from a companion JSON sidecar file are included
28+
/// via `extra` and flattened into the serialized output.
2529
#[derive(Debug, Serialize)]
2630
pub struct ImageMetadata {
2731
pub image_file_name: String,
2832
pub width: u32,
2933
pub height: u32,
30-
#[serde(skip_serializing_if = "Option::is_none")]
31-
pub display_name: Option<String>,
34+
#[serde(flatten)]
35+
pub extra: HashMap<String, serde_json::Value>,
3236
}

src/commands/build/snapshots.rs

Lines changed: 40 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ use secrecy::ExposeSecret as _;
1212
use sha2::{Digest as _, Sha256};
1313
use walkdir::WalkDir;
1414

15-
use serde::Deserialize;
16-
1715
use crate::api::{Api, CreateSnapshotResponse, ImageMetadata, SnapshotsManifest};
1816
use crate::config::{Auth, Config};
1917
use crate::utils::args::ArgExt as _;
@@ -97,8 +95,8 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
9795
style(images.len()).yellow(),
9896
if images.len() == 1 { "file" } else { "files" }
9997
);
100-
let display_names = collect_display_names(dir_path);
101-
let manifest_entries = upload_images(images, &display_names, &org, &project)?;
98+
99+
let manifest_entries = upload_images(images, &org, &project)?;
102100

103101
// Build manifest from discovered images
104102
let manifest = SnapshotsManifest {
@@ -191,9 +189,42 @@ fn is_image_file(path: &Path) -> bool {
191189
.unwrap_or(false)
192190
}
193191

192+
/// Reads the companion JSON sidecar for an image, if it exists.
193+
///
194+
/// For an image at `path/to/button.png`, looks for `path/to/button.json`.
195+
/// Returns a map of all key-value pairs from the JSON file.
196+
fn read_sidecar_metadata(image_path: &Path) -> HashMap<String, serde_json::Value> {
197+
let sidecar_path = image_path.with_extension("json");
198+
if !sidecar_path.is_file() {
199+
return HashMap::new();
200+
}
201+
202+
debug!("Reading sidecar metadata: {}", sidecar_path.display());
203+
let contents = match fs::read_to_string(&sidecar_path) {
204+
Ok(c) => c,
205+
Err(err) => {
206+
warn!(
207+
"Failed to read sidecar file {}: {err}",
208+
sidecar_path.display()
209+
);
210+
return HashMap::new();
211+
}
212+
};
213+
214+
match serde_json::from_str(&contents) {
215+
Ok(map) => map,
216+
Err(err) => {
217+
warn!(
218+
"Failed to parse sidecar file {}: {err}",
219+
sidecar_path.display()
220+
);
221+
HashMap::new()
222+
}
223+
}
224+
}
225+
194226
fn upload_images(
195227
images: Vec<ImageInfo>,
196-
display_names: &HashMap<String, String>,
197228
org: &str,
198229
project: &str,
199230
) -> Result<HashMap<String, ImageMetadata>> {
@@ -251,14 +282,16 @@ fn upload_images(
251282
.unwrap_or_default()
252283
.to_string_lossy()
253284
.into_owned();
254-
let display_name = display_names.get(&image_file_name).cloned();
285+
286+
let extra = read_sidecar_metadata(&image.path);
287+
255288
manifest_entries.insert(
256289
hash,
257290
ImageMetadata {
291+
extra,
258292
image_file_name,
259293
width: image.width,
260294
height: image.height,
261-
display_name,
262295
},
263296
);
264297
}
@@ -286,62 +319,3 @@ fn upload_images(
286319
}
287320
}
288321
}
289-
290-
/// Input format for user-provided JSON manifest files.
291-
#[derive(Deserialize)]
292-
struct ManifestFile {
293-
images: HashMap<String, ManifestFileEntry>,
294-
}
295-
296-
#[derive(Deserialize)]
297-
struct ManifestFileEntry {
298-
image_file_name: String,
299-
display_name: Option<String>,
300-
}
301-
302-
/// Collects `image_file_name -> display_name` mappings from JSON manifest files in a directory.
303-
fn collect_display_names(dir: &Path) -> HashMap<String, String> {
304-
let mut display_names = HashMap::new();
305-
let entries = WalkDir::new(dir)
306-
.follow_links(true)
307-
.into_iter()
308-
.filter_entry(|e| !is_hidden(dir, e.path()));
309-
310-
for entry in entries.flatten() {
311-
if !entry.file_type().is_file() {
312-
continue;
313-
}
314-
let path = entry.path();
315-
let is_json = path
316-
.extension()
317-
.and_then(|ext| ext.to_str())
318-
.map(|ext| ext.eq_ignore_ascii_case("json"))
319-
.unwrap_or(false);
320-
if !is_json {
321-
continue;
322-
}
323-
324-
debug!("Reading manifest file: {}", path.display());
325-
let contents = match fs::read_to_string(path) {
326-
Ok(c) => c,
327-
Err(err) => {
328-
warn!("Failed to read manifest file {}: {err}", path.display());
329-
continue;
330-
}
331-
};
332-
let manifest: ManifestFile = match serde_json::from_str(&contents) {
333-
Ok(m) => m,
334-
Err(err) => {
335-
warn!("Failed to parse manifest file {}: {err}", path.display());
336-
continue;
337-
}
338-
};
339-
340-
for entry in manifest.images.into_values() {
341-
if let Some(display_name) = entry.display_name {
342-
display_names.insert(entry.image_file_name, display_name);
343-
}
344-
}
345-
}
346-
display_names
347-
}

0 commit comments

Comments
 (0)