@@ -34,11 +34,15 @@ pub enum VersionFilter {
3434 /// Accept the newest release that actually ships the expected asset.
3535 ///
3636 /// Used for universal-wasm tools whose later releases may stop shipping the
37- /// consumable artifact (e.g. loom: v0.3.0 ships `loom.wasm` but v1.x ship
38- /// only compliance reports). Without this the updater would pick the latest
39- /// tag and fail to download. The asset name comes from the tool's
37+ /// consumable `.wasm` artifact, so plain "latest" would pick a tag with no
38+ /// downloadable asset. The asset name comes from the tool's
4039 /// `UrlPattern::UniversalWasm`. Resolved in the update engine (it needs each
4140 /// release's asset list), not via `accepts()`.
41+ ///
42+ /// (loom used this while it shipped `loom.wasm` through v0.3.0; from v1.x it
43+ /// ships per-platform native binaries and moved to
44+ /// `PerPlatformVersionedAsset` + `Any`. file-ops-component is the current
45+ /// user.)
4246 AssetExists ,
4347}
4448
@@ -79,6 +83,22 @@ pub enum UrlPattern {
7983 pattern : String ,
8084 platform_mapping : HashMap < String , String > ,
8185 } ,
86+ /// Per-platform asset whose stored `url_suffix` is the COMPLETE filename
87+ /// *including the version*, e.g. loom's `loom-v1.1.14-aarch64-apple-darwin.tar.gz`.
88+ /// Required when the toolchain reads `url_suffix` as the whole filename
89+ /// (`filename: "{suffix}"` in tool_registry.bzl, as loom/wkg/wrpc do) rather
90+ /// than appending a fragment to a version-templated pattern. `PerPlatformAsset`
91+ /// can't express this because its stored suffix is static (no `{version}`),
92+ /// so the next release would write a stale, wrong filename.
93+ ///
94+ /// `filename_pattern` is the asset filename with `{version}` and `{platform}`
95+ /// placeholders; `platform_mapping` maps each platform to its `{platform}`
96+ /// value (including the file extension). The full resolved filename is both
97+ /// the download asset and the verbatim registry `url_suffix`.
98+ PerPlatformVersionedAsset {
99+ filename_pattern : String ,
100+ platform_mapping : HashMap < String , String > ,
101+ } ,
82102}
83103
84104impl Default for ToolConfig {
@@ -349,21 +369,36 @@ impl ToolConfig {
349369 } ,
350370 ) ;
351371
352- // PulseEngine universal-wasm components. These publish a single
353- // platform-independent .wasm asset per release. The AssetExists filter
354- // picks the newest release that actually ships the asset — important for
355- // loom, whose v1.x releases ship only compliance reports (no loom.wasm),
356- // so the updater correctly stays at v0.3.0 instead of failing on v1.x.
372+ // loom, the optimizer. v0.3.0 was the last release shipping the
373+ // universal `loom.wasm`; from v1.x loom ships per-platform native
374+ // tarballs (`loom-v{version}-{triple}.tar.gz`, `.zip` on Windows) and the
375+ // toolchain (tool_registry.bzl loom: `filename: "{suffix}"`) reads the
376+ // full versioned filename as the registry `url_suffix`. That needs
377+ // PerPlatformVersionedAsset — UniversalWasm/AssetExists kept the updater
378+ // stuck at v0.3.0 (#514 migrated the registry + toolchain to native).
357379 tools. insert (
358380 "loom" . to_string ( ) ,
359381 ToolConfigEntry {
360382 github_repo : "pulseengine/loom" . to_string ( ) ,
361- platforms : vec ! [ "wasm" . to_string( ) ] ,
362- url_pattern : UrlPattern :: UniversalWasm {
363- asset_name : "loom.wasm" . to_string ( ) ,
383+ platforms : vec ! [
384+ "darwin_amd64" . to_string( ) ,
385+ "darwin_arm64" . to_string( ) ,
386+ "linux_amd64" . to_string( ) ,
387+ "windows_amd64" . to_string( ) ,
388+ ] ,
389+ url_pattern : UrlPattern :: PerPlatformVersionedAsset {
390+ filename_pattern : "loom-v{version}-{platform}" . to_string ( ) ,
391+ platform_mapping : {
392+ let mut map = HashMap :: new ( ) ;
393+ map. insert ( "darwin_amd64" . to_string ( ) , "x86_64-apple-darwin.tar.gz" . to_string ( ) ) ;
394+ map. insert ( "darwin_arm64" . to_string ( ) , "aarch64-apple-darwin.tar.gz" . to_string ( ) ) ;
395+ map. insert ( "linux_amd64" . to_string ( ) , "x86_64-unknown-linux-gnu.tar.gz" . to_string ( ) ) ;
396+ map. insert ( "windows_amd64" . to_string ( ) , "x86_64-pc-windows-msvc.zip" . to_string ( ) ) ;
397+ map
398+ } ,
364399 } ,
365400 tag_prefix : Some ( "v" . to_string ( ) ) ,
366- version_filter : VersionFilter :: AssetExists ,
401+ version_filter : VersionFilter :: Any ,
367402 } ,
368403 ) ;
369404
@@ -543,6 +578,35 @@ impl ToolConfigEntry {
543578 . replace ( "{version}" , version)
544579 . replace ( "{asset}" , asset) )
545580 }
581+ UrlPattern :: PerPlatformVersionedAsset { .. } => {
582+ let filename = self . versioned_filename ( version, platform) ?;
583+ Ok ( format ! (
584+ "https://github.com/{}/releases/download/v{}/{}" ,
585+ self . github_repo, version, filename
586+ ) )
587+ }
588+ }
589+ }
590+
591+ /// Resolve the full per-platform filename for a `PerPlatformVersionedAsset`
592+ /// tool. This is both the download asset name and the verbatim registry
593+ /// `url_suffix`, so the two can never drift.
594+ fn versioned_filename ( & self , version : & str , platform : & str ) -> Result < String > {
595+ match & self . url_pattern {
596+ UrlPattern :: PerPlatformVersionedAsset {
597+ filename_pattern,
598+ platform_mapping,
599+ } => {
600+ let platform_value = platform_mapping
601+ . get ( platform)
602+ . with_context ( || format ! ( "Unsupported platform: {}" , platform) ) ?;
603+ Ok ( filename_pattern
604+ . replace ( "{version}" , version)
605+ . replace ( "{platform}" , platform_value) )
606+ }
607+ _ => Err ( anyhow:: anyhow!(
608+ "versioned_filename called on non-versioned pattern"
609+ ) ) ,
546610 }
547611 }
548612
@@ -570,8 +634,9 @@ impl ToolConfigEntry {
570634 }
571635 }
572636
573- /// Get URL suffix for JSON storage
574- pub fn get_url_suffix ( & self , platform : & str ) -> Result < String > {
637+ /// Get URL suffix for JSON storage. `version` is only consulted by patterns
638+ /// whose stored suffix embeds the version (PerPlatformVersionedAsset).
639+ pub fn get_url_suffix ( & self , version : & str , platform : & str ) -> Result < String > {
575640 match & self . url_pattern {
576641 UrlPattern :: StandardTarball { platform_mapping } => {
577642 let platform_name = platform_mapping
@@ -602,6 +667,9 @@ impl ToolConfigEntry {
602667 . get ( platform)
603668 . cloned ( )
604669 . with_context ( || format ! ( "Platform {} not found" , platform) ) ,
670+ UrlPattern :: PerPlatformVersionedAsset { .. } => {
671+ self . versioned_filename ( version, platform)
672+ }
605673 _ => Err ( anyhow:: anyhow!( "Tool does not use URL suffixes" ) ) ,
606674 }
607675 }
@@ -665,7 +733,9 @@ mod tests {
665733 let config = ToolConfig :: new ( ) ;
666734 let wasm_tools_config = config. get_tool_config ( "wasm-tools" ) ;
667735
668- let suffix = wasm_tools_config. get_url_suffix ( "linux_amd64" ) . unwrap ( ) ;
736+ let suffix = wasm_tools_config
737+ . get_url_suffix ( "1.240.0" , "linux_amd64" )
738+ . unwrap ( ) ;
669739 assert_eq ! ( suffix, "x86_64-linux.tar.gz" ) ;
670740 }
671741
@@ -688,7 +758,7 @@ mod tests {
688758 "https://github.com/bytecodealliance/wit-bindgen/releases/download/v0.58.0/wit-bindgen-0.58.0-x86_64-windows.zip"
689759 ) ;
690760 assert_eq ! (
691- wb. get_url_suffix( "windows_amd64" ) . unwrap( ) ,
761+ wb. get_url_suffix( "0.58.0" , " windows_amd64") . unwrap( ) ,
692762 "x86_64-windows.zip"
693763 ) ;
694764 // Unix stays .tar.gz.
@@ -697,7 +767,7 @@ mod tests {
697767 "https://github.com/bytecodealliance/wit-bindgen/releases/download/v0.58.0/wit-bindgen-0.58.0-x86_64-linux.tar.gz"
698768 ) ;
699769 assert_eq ! (
700- wb. get_url_suffix( "linux_amd64" ) . unwrap( ) ,
770+ wb. get_url_suffix( "0.58.0" , " linux_amd64") . unwrap( ) ,
701771 "x86_64-linux.tar.gz"
702772 ) ;
703773 assert ! ( !wb. has_platform_names( ) ) ;
@@ -713,36 +783,48 @@ mod tests {
713783 "https://github.com/bytecodealliance/wasmtime/releases/download/v45.0.1/wasmtime-v45.0.1-x86_64-linux.tar.xz"
714784 ) ;
715785 assert_eq ! (
716- wt. get_url_suffix( "linux_amd64" ) . unwrap( ) ,
786+ wt. get_url_suffix( "45.0.1" , " linux_amd64") . unwrap( ) ,
717787 "x86_64-linux.tar.xz"
718788 ) ;
719789 assert_eq ! (
720790 wt. generate_download_url( "45.0.1" , "windows_amd64" ) . unwrap( ) ,
721791 "https://github.com/bytecodealliance/wasmtime/releases/download/v45.0.1/wasmtime-v45.0.1-x86_64-windows.zip"
722792 ) ;
723793 assert_eq ! (
724- wt. get_url_suffix( "windows_amd64" ) . unwrap( ) ,
794+ wt. get_url_suffix( "45.0.1" , " windows_amd64") . unwrap( ) ,
725795 "x86_64-windows.zip"
726796 ) ;
727797 }
728798
729799 #[ test]
730- fn test_universal_wasm_loom ( ) {
800+ fn test_per_platform_versioned_asset_loom_native ( ) {
731801 let config = ToolConfig :: new ( ) ;
732802 let loom = config. get_tool_config ( "loom" ) ;
733803
734804 assert_eq ! ( loom. github_repo, "pulseengine/loom" ) ;
735- assert_eq ! ( loom. platforms, vec![ "wasm" . to_string( ) ] ) ;
736- assert ! ( matches!( loom. version_filter, VersionFilter :: AssetExists ) ) ;
737- assert_eq ! ( loom. universal_asset_name( ) , Some ( "loom.wasm" ) ) ;
805+ assert ! ( matches!( loom. version_filter, VersionFilter :: Any ) ) ;
806+ assert ! ( !loom. has_platform_names( ) ) ;
738807
739- let url = loom. generate_download_url ( "0.3.0" , "wasm" ) . unwrap ( ) ;
808+ // The stored url_suffix must be the FULL versioned filename the toolchain
809+ // reads verbatim, and must match the hand-authored #513 registry block
810+ // exactly — else the loom toolchain download breaks on the next release.
740811 assert_eq ! (
741- url,
742- "https://github.com/pulseengine/loom/releases/download/v0.3.0/loom.wasm"
812+ loom. generate_download_url( "1.1.14" , "darwin_arm64" ) . unwrap( ) ,
813+ "https://github.com/pulseengine/loom/releases/download/v1.1.14/loom-v1.1.14-aarch64-apple-darwin.tar.gz"
814+ ) ;
815+ assert_eq ! (
816+ loom. get_url_suffix( "1.1.14" , "darwin_arm64" ) . unwrap( ) ,
817+ "loom-v1.1.14-aarch64-apple-darwin.tar.gz"
818+ ) ;
819+ assert_eq ! (
820+ loom. get_url_suffix( "1.1.14" , "linux_amd64" ) . unwrap( ) ,
821+ "loom-v1.1.14-x86_64-unknown-linux-gnu.tar.gz"
822+ ) ;
823+ // Windows is .zip (mixed extension).
824+ assert_eq ! (
825+ loom. get_url_suffix( "1.1.14" , "windows_amd64" ) . unwrap( ) ,
826+ "loom-v1.1.14-x86_64-pc-windows-msvc.zip"
743827 ) ;
744- assert_eq ! ( loom. get_url_suffix( "wasm" ) . unwrap( ) , "loom.wasm" ) ;
745- assert ! ( !loom. has_platform_names( ) ) ;
746828 }
747829
748830 #[ test]
0 commit comments