diff --git a/crates/icp-cli/src/operations/bundle.rs b/crates/icp-cli/src/operations/bundle.rs index 23e411fe..e1d0d623 100644 --- a/crates/icp-cli/src/operations/bundle.rs +++ b/crates/icp-cli/src/operations/bundle.rs @@ -154,23 +154,23 @@ pub enum BundleError { source: serde_yaml::Error, }, - #[snafu(display("`screenshots` in app manifest '{path}' must be a list of file paths"))] - ScreenshotsNotSequence { path: PathBuf }, + #[snafu(display("`images` in app manifest '{path}' must be a list of file paths"))] + ImagesNotSequence { path: PathBuf }, - #[snafu(display("screenshot entries in app manifest '{path}' must be file path strings"))] - ScreenshotNotString { path: PathBuf }, + #[snafu(display("image entries in app manifest '{path}' must be file path strings"))] + ImageNotString { path: PathBuf }, #[snafu(display( - "screenshot path '{path}' resolves outside the project directory '{root}'; \ + "image path '{path}' resolves outside the project directory '{root}'; \ bundles cannot reference files outside the project" ))] - ScreenshotEscapesProject { path: PathBuf, root: PathBuf }, + ImageEscapesProject { path: PathBuf, root: PathBuf }, #[snafu(display( - "screenshots {paths:?} both map to the same bundle path 'screenshots/{sanitized}'; \ + "images {paths:?} both map to the same bundle path 'images/{sanitized}'; \ rename one so they use distinct file names" ))] - ScreenshotNameCollision { + ImageNameCollision { sanitized: String, paths: Vec, }, @@ -178,8 +178,8 @@ pub enum BundleError { #[snafu(display("failed to serialize app manifest"))] SerializeAppManifest { source: serde_yaml::Error }, - #[snafu(display("failed to read screenshot '{path}'"))] - ReadScreenshot { path: PathBuf, source: fs::IoError }, + #[snafu(display("failed to read image '{path}'"))] + ReadImage { path: PathBuf, source: fs::IoError }, } /// In-memory bytes destined for a single tar entry. @@ -209,16 +209,16 @@ struct InitArgsFile { } /// The optional `icp_appmanifest.yaml` app-metadata file. We only understand its top-level -/// `screenshots` list; all other keys are preserved semantically. +/// `images` list; all other keys are preserved semantically. struct AppManifest { /// YAML to write at `APP_MANIFEST` in the archive. The original source text is used when - /// no screenshot relocation is needed; otherwise the YAML is re-serialized (formatting/comments may change). + /// no image relocation is needed; otherwise the YAML is re-serialized (formatting/comments may change). yaml: String, - screenshots: Vec, + images: Vec, } -/// A screenshot referenced from `icp_appmanifest.yaml`, relocated under `screenshots/` in the bundle. -struct ScreenshotFile { +/// A image referenced from `icp_appmanifest.yaml`, relocated under `images/` in the bundle. +struct ImageFile { src_path: PathBuf, archive_path: String, } @@ -567,8 +567,8 @@ async fn inline_environments( Ok((out, init_args_files)) } -/// Load `icp_appmanifest.yaml` if present, rewriting its top-level `screenshots` paths to point at -/// copies relocated under `screenshots/` in the bundle. Returns `None` when the file is absent. +/// Load `icp_appmanifest.yaml` if present, rewriting its top-level `images` paths to point at +/// copies relocated under `images/` in the bundle. Returns `None` when the file is absent. fn prepare_app_manifest( project_dir: &Path, canonical_project_dir: &Path, @@ -585,20 +585,20 @@ fn prepare_app_manifest( path: &manifest_path, })?; - let Some(screenshots_val) = doc.get_mut("screenshots") else { - // No screenshots to relocate; embed the file unchanged. + let Some(images_val) = doc.get_mut("images") else { + // No images to relocate; embed the file unchanged. return Ok(Some(AppManifest { yaml: raw, - screenshots: Vec::new(), + images: Vec::new(), })); }; - let seq = screenshots_val + let seq = images_val .as_sequence_mut() - .context(ScreenshotsNotSequenceSnafu { + .context(ImagesNotSequenceSnafu { path: &manifest_path, })?; - let mut screenshots = Vec::with_capacity(seq.len()); + let mut images = Vec::with_capacity(seq.len()); // Maps a relocated archive name back to the canonical source and original path it came from, // so identical entries are deduplicated and distinct sources that flatten to the same name // are reported as a collision. @@ -606,36 +606,36 @@ fn prepare_app_manifest( for entry in seq.iter_mut() { let orig = entry .as_str() - .context(ScreenshotNotStringSnafu { + .context(ImageNotStringSnafu { path: &manifest_path, })? .to_owned(); let src = project_dir.join(&orig); let canon = canonicalize(&src)?; if !canon.starts_with(canonical_project_dir) { - return ScreenshotEscapesProjectSnafu { + return ImageEscapesProjectSnafu { path: src, root: canonical_project_dir.to_path_buf(), } .fail(); } - // Flatten into the top-level `screenshots/` folder by basename, sanitized the same way + // Flatten into the top-level `images/` folder by basename, sanitized the same way // canister name segments are. let base = canon.file_name().unwrap_or(orig.as_str()); let sanitized = path_segment(base); - let archive_path = format!("screenshots/{sanitized}"); + let archive_path = format!("images/{sanitized}"); match seen.get(&sanitized) { Some((prev_canon, _)) if *prev_canon == canon => {} Some((_, prev_orig)) => { let mut paths = vec![prev_orig.clone(), orig.clone()]; paths.sort(); - return ScreenshotNameCollisionSnafu { sanitized, paths }.fail(); + return ImageNameCollisionSnafu { sanitized, paths }.fail(); } None => { seen.insert(sanitized.clone(), (canon.clone(), orig.clone())); - screenshots.push(ScreenshotFile { + images.push(ImageFile { src_path: canon, archive_path: archive_path.clone(), }); @@ -646,7 +646,7 @@ fn prepare_app_manifest( } let yaml = serde_yaml::to_string(&doc).context(SerializeAppManifestSnafu)?; - Ok(Some(AppManifest { yaml, screenshots })) + Ok(Some(AppManifest { yaml, images })) } fn write_archive( @@ -676,8 +676,8 @@ fn write_archive( if let Some(app) = app_manifest { append_bytes(&mut archive, APP_MANIFEST, app.yaml.as_bytes())?; - for shot in &app.screenshots { - let data = fs::read(&shot.src_path).context(ReadScreenshotSnafu { + for shot in &app.images { + let data = fs::read(&shot.src_path).context(ReadImageSnafu { path: shot.src_path.clone(), })?; append_bytes(&mut archive, &shot.archive_path, &data)?; diff --git a/crates/icp-cli/tests/bundle_tests.rs b/crates/icp-cli/tests/bundle_tests.rs index d563d6dd..c2f0655f 100644 --- a/crates/icp-cli/tests/bundle_tests.rs +++ b/crates/icp-cli/tests/bundle_tests.rs @@ -744,10 +744,10 @@ fn bundle_packages_plugin_sync_steps() { } /// An `icp_appmanifest.yaml` next to the project manifest must be included in the bundle, with its -/// top-level `screenshots` paths relocated under a top-level `screenshots/` folder and the +/// top-level `images` paths relocated under a top-level `images/` folder and the /// referenced image files copied alongside. Unrelated metadata is preserved. #[test] -fn bundle_includes_app_manifest_screenshots() { +fn bundle_includes_app_manifest_images() { let ctx = TestContext::new(); let project_dir = ctx.create_project_dir("icp"); let wasm_src = ctx.make_asset("example_icp_mo.wasm"); @@ -770,7 +770,7 @@ fn bundle_includes_app_manifest_screenshots() { let app_manifest = formatdoc! {r#" name: My App description: an app we do not parse - screenshots: + images: - media/home.png - media/detail.png "#}; @@ -806,14 +806,14 @@ fn bundle_includes_app_manifest_screenshots() { .read_to_string(&mut app_manifest_yaml) .expect("failed to read icp_appmanifest.yaml"); } - "screenshots/home.png" => { + "images/home.png" => { let mut buf = Vec::new(); entry .read_to_end(&mut buf) .expect("failed to read home.png"); home_bytes = Some(buf); } - "screenshots/detail.png" => { + "images/detail.png" => { let mut buf = Vec::new(); entry .read_to_end(&mut buf) @@ -827,24 +827,18 @@ fn bundle_includes_app_manifest_screenshots() { assert_eq!( home_bytes.as_deref(), Some(b"home-bytes".as_slice()), - "screenshots/home.png missing or wrong content" + "images/home.png missing or wrong content" ); assert_eq!( detail_bytes.as_deref(), Some(b"detail-bytes".as_slice()), - "screenshots/detail.png missing or wrong content" + "images/detail.png missing or wrong content" ); let parsed: serde_yaml::Value = serde_yaml::from_str(&app_manifest_yaml).expect("app manifest yaml is invalid"); - assert_eq!( - parsed["screenshots"][0].as_str(), - Some("screenshots/home.png") - ); - assert_eq!( - parsed["screenshots"][1].as_str(), - Some("screenshots/detail.png") - ); + assert_eq!(parsed["images"][0].as_str(), Some("images/home.png")); + assert_eq!(parsed["images"][1].as_str(), Some("images/detail.png")); // Unrelated metadata must survive the rewrite. assert_eq!(parsed["name"].as_str(), Some("My App")); assert_eq!( @@ -853,9 +847,9 @@ fn bundle_includes_app_manifest_screenshots() { ); } -/// Two screenshots whose basenames collide under the flat `screenshots/` folder must be rejected. +/// Two images whose basenames collide under the flat `images/` folder must be rejected. #[test] -fn bundle_rejects_screenshot_name_collision() { +fn bundle_rejects_image_name_collision() { let ctx = TestContext::new(); let project_dir = ctx.create_project_dir("icp"); let wasm_src = ctx.make_asset("example_icp_mo.wasm"); @@ -876,7 +870,7 @@ fn bundle_rejects_screenshot_name_collision() { write_string(&project_dir.join("icp.yaml"), &pm).expect("failed to write project manifest"); let app_manifest = formatdoc! {r#" - screenshots: + images: - a/shot.png - b/shot.png "#}; @@ -891,10 +885,10 @@ fn bundle_rejects_screenshot_name_collision() { .stderr(contains("same bundle path").and(contains("shot.png"))); } -/// A screenshot path resolving outside the project directory must be rejected, like other bundle +/// A image path resolving outside the project directory must be rejected, like other bundle /// sources. #[test] -fn bundle_rejects_screenshot_outside_project() { +fn bundle_rejects_image_outside_project() { let ctx = TestContext::new(); let project_dir = ctx.create_project_dir("icp"); let wasm_src = ctx.make_asset("example_icp_mo.wasm"); @@ -903,7 +897,7 @@ fn bundle_rejects_screenshot_outside_project() { .parent() .expect("project dir has no parent") .join("outside.png"); - write(&outside, b"secret").expect("failed to write outside screenshot"); + write(&outside, b"secret").expect("failed to write outside image"); let pm = formatdoc! {r#" canisters: @@ -916,7 +910,7 @@ fn bundle_rejects_screenshot_outside_project() { write_string(&project_dir.join("icp.yaml"), &pm).expect("failed to write project manifest"); let app_manifest = formatdoc! {r#" - screenshots: + images: - ../outside.png "#}; write_string(&project_dir.join("icp_appmanifest.yaml"), &app_manifest)