Skip to content

Commit 82884e5

Browse files
committed
fix(stat): include content type in metadata output
1 parent f5df9f4 commit 82884e5

1 file changed

Lines changed: 70 additions & 17 deletions

File tree

crates/cli/src/commands/stat.rs

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use clap::Args;
66
use rc_core::{AliasManager, ObjectStore as _, RemotePath};
77
use rc_s3::S3Client;
88
use serde::Serialize;
9-
use std::collections::BTreeMap;
9+
use std::collections::{BTreeMap, HashMap};
1010

1111
use crate::exit_code::ExitCode;
1212
use crate::output::{Formatter, OutputConfig};
@@ -55,6 +55,31 @@ fn metadata_is_none_or_empty(metadata: &Option<BTreeMap<String, String>>) -> boo
5555
}
5656
}
5757

58+
fn normalize_metadata(
59+
content_type: Option<&str>,
60+
metadata: Option<&HashMap<String, String>>,
61+
) -> Option<BTreeMap<String, String>> {
62+
let mut out = BTreeMap::new();
63+
64+
if let Some(ct) = content_type
65+
&& !ct.is_empty()
66+
{
67+
out.insert("Content-Type".to_string(), ct.to_string());
68+
}
69+
70+
if let Some(meta) = metadata {
71+
let mut sorted: BTreeMap<_, _> = meta.iter().collect();
72+
for (key, value) in &mut sorted {
73+
out.insert(
74+
format!("X-Amz-Meta-{}", capitalize_meta_key(key)),
75+
(*value).clone(),
76+
);
77+
}
78+
}
79+
80+
if out.is_empty() { None } else { Some(out) }
81+
}
82+
5883
/// Execute the stat command
5984
pub async fn execute(args: StatArgs, output_config: OutputConfig) -> ExitCode {
6085
let formatter = Formatter::new(output_config);
@@ -109,15 +134,10 @@ pub async fn execute(args: StatArgs, output_config: OutputConfig) -> ExitCode {
109134
content_type: info.content_type.clone(),
110135
storage_class: info.storage_class.clone(),
111136
version_id: args.version_id,
112-
metadata: info
113-
.metadata
114-
.as_ref()
115-
.map(|m| {
116-
m.iter()
117-
.map(|(k, v)| (k.clone(), v.clone()))
118-
.collect::<BTreeMap<_, _>>()
119-
})
120-
.filter(|m| !m.is_empty()),
137+
metadata: normalize_metadata(
138+
info.content_type.as_deref(),
139+
info.metadata.as_ref(),
140+
),
121141
};
122142
formatter.json(&output);
123143
} else {
@@ -153,13 +173,12 @@ pub async fn execute(args: StatArgs, output_config: OutputConfig) -> ExitCode {
153173
if let Some(sc) = &info.storage_class {
154174
formatter.println(&format_kv("Class", sc));
155175
}
156-
if let Some(metadata) = &info.metadata {
157-
let sorted: BTreeMap<_, _> = metadata.iter().collect();
158-
for (key, value) in &sorted {
159-
formatter.println(&format_kv(
160-
&format!("X-Amz-Meta-{}", capitalize_meta_key(key)),
161-
value,
162-
));
176+
if let Some(metadata) =
177+
normalize_metadata(info.content_type.as_deref(), info.metadata.as_ref())
178+
{
179+
formatter.println(&format_kv("Metadata", ""));
180+
for (key, value) in &metadata {
181+
formatter.println(&format_kv(key, value));
163182
}
164183
}
165184
}
@@ -327,4 +346,38 @@ mod tests {
327346
// Empty BTreeMap is treated as None via skip_serializing_if helper
328347
assert!(!json.contains("metadata"));
329348
}
349+
350+
#[test]
351+
fn test_normalize_metadata_includes_content_type() {
352+
let metadata = normalize_metadata(Some("text/plain"), None).expect("metadata present");
353+
assert_eq!(
354+
metadata.get("Content-Type").map(String::as_str),
355+
Some("text/plain")
356+
);
357+
}
358+
359+
#[test]
360+
fn test_normalize_metadata_includes_custom_metadata() {
361+
let mut custom = HashMap::new();
362+
custom.insert("content-disposition".to_string(), "attachment".to_string());
363+
custom.insert("x-custom-key".to_string(), "value".to_string());
364+
365+
let metadata =
366+
normalize_metadata(Some("text/plain"), Some(&custom)).expect("metadata present");
367+
368+
assert_eq!(
369+
metadata.get("Content-Type").map(String::as_str),
370+
Some("text/plain")
371+
);
372+
assert_eq!(
373+
metadata
374+
.get("X-Amz-Meta-Content-Disposition")
375+
.map(String::as_str),
376+
Some("attachment")
377+
);
378+
assert_eq!(
379+
metadata.get("X-Amz-Meta-X-Custom-Key").map(String::as_str),
380+
Some("value")
381+
);
382+
}
330383
}

0 commit comments

Comments
 (0)