diff --git a/ci/build-channel/src/main.rs b/ci/build-channel/src/main.rs index 82e8f59f2..89a2ff0f6 100644 --- a/ci/build-channel/src/main.rs +++ b/ci/build-channel/src/main.rs @@ -476,4 +476,29 @@ mod tests { ("forc", "forc-node-0.71.0", "forc-node") ); } + + #[test] + fn test_forc_client_url_generation() { + let forc_client = Component::from_name("forc-client").unwrap(); + + // Legacy version (< 0.71.0) should use sway repo with forc-binaries tarball + let legacy = Version::new(0, 70, 1); + let repo = forc_client.repository_for_version(&legacy); + let tag = forc_client.tag_for_version(&legacy); + let prefix = forc_client.tarball_prefix_for_version(&legacy); + assert_eq!( + (repo, tag.as_str(), prefix), + ("sway", "v0.70.1", "forc-binaries") + ); + + // Migrated version (>= 0.71.0) should use forc repo with forc-client tarball + let migrated = Version::new(0, 71, 0); + let repo = forc_client.repository_for_version(&migrated); + let tag = forc_client.tag_for_version(&migrated); + let prefix = forc_client.tarball_prefix_for_version(&migrated); + assert_eq!( + (repo, tag.as_str(), prefix), + ("forc", "forc-client-0.71.0", "forc-client") + ); + } } diff --git a/component/src/lib.rs b/component/src/lib.rs index 04fa50d4c..a7cf3e32f 100644 --- a/component/src/lib.rs +++ b/component/src/lib.rs @@ -118,7 +118,10 @@ impl Component { pub fn tag_for_version(&self, version: &Version) -> String { let repo = self.repository_for_version(version); match (self.name.as_str(), repo) { - ("forc-wallet", "forc") | ("forc-crypto", "forc") | ("forc-node", "forc") => { + ("forc-wallet", "forc") + | ("forc-crypto", "forc") + | ("forc-node", "forc") + | ("forc-client", "forc") => { format!("{}-{}", self.name, version) } _ => format!("v{}", version), @@ -153,13 +156,30 @@ impl Component { }) } - pub fn is_default_forc_plugin(name: &str) -> bool { - (Self::from_name(FORC) + /// Returns the parent component name if the given name is an executable bundled + /// with another component (e.g., forc-fmt is bundled with forc, forc-run is + /// bundled with forc-client). + /// + /// Returns `None` if the name is a standalone component or not recognized. + pub fn parent_component_for_executable(name: &str) -> Option<&'static str> { + // Check if it's a forc executable (except forc itself) + if Self::from_name(FORC) .expect("there must always be a `forc` component") .executables .contains(&name.to_string()) - && name != FORC) - || name == FORC_CLIENT + && name != FORC + { + return Some(FORC); + } + + // Check if it's a forc-client executable (except forc-client itself) + if let Ok(forc_client) = Self::from_name(FORC_CLIENT) { + if forc_client.executables.contains(&name.to_string()) && name != FORC_CLIENT { + return Some(FORC_CLIENT); + } + } + + None } /// Tests if the supplied `Component`s come from same distribution @@ -328,7 +348,7 @@ impl Components { /// assert!(Components::is_distributed_by_forc("forc")); /// assert!(!Components::is_distributed_by_forc("fuel-core")); /// assert!(Components::is_distributed_by_forc("forc-fmt")); - /// assert!(Components::is_distributed_by_forc("forc-run")); + /// assert!(!Components::is_distributed_by_forc("forc-run")); // forc-run is now distributed by forc-client /// ``` pub fn is_distributed_by_forc(name: &str) -> bool { match name { @@ -634,6 +654,77 @@ mod tests { ); } + #[test] + fn test_repository_for_version_forc_client_migration() { + let components = Components::collect().unwrap(); + let forc_client = components + .component + .get("forc-client") + .expect("forc-client component must exist"); + + let legacy = Version::new(0, 70, 1); + let migrated = Version::new(0, 71, 0); + + assert_eq!( + forc_client.repository_for_version(&legacy), + "sway", + "pre-0.71.0 forc-client versions should use the sway repository" + ); + assert_eq!( + forc_client.repository_for_version(&migrated), + "forc", + "0.71.0+ forc-client versions should use the forc monorepo" + ); + } + + #[test] + fn test_tarball_prefix_for_version_forc_client_migration() { + let components = Components::collect().unwrap(); + let forc_client = components + .component + .get("forc-client") + .expect("forc-client component must exist"); + + let legacy = Version::new(0, 70, 1); + let migrated = Version::new(0, 71, 0); + + assert_eq!( + forc_client.tarball_prefix_for_version(&legacy), + "forc-binaries", + "pre-0.71.0 forc-client was bundled in forc-binaries" + ); + assert_eq!( + forc_client.tarball_prefix_for_version(&migrated), + "forc-client", + "0.71.0+ forc-client has its own tarball" + ); + } + + #[test] + fn test_tag_for_version_forc_client_migration() { + let components = Components::collect().unwrap(); + let forc_client = components + .component + .get("forc-client") + .expect("forc-client component must exist"); + + // Legacy versions (< 0.71.0) should use standard v-prefixed tags + let legacy = Version::new(0, 70, 1); + assert_eq!( + forc_client.tag_for_version(&legacy), + "v0.70.1", + "Legacy forc-client versions should use v-prefixed tags" + ); + + // New versions (>= 0.71.0) in forc repo should use forc-client-prefixed tags + let migrated = Version::new(0, 71, 0); + assert_eq!( + forc_client.tag_for_version(&migrated), + "forc-client-0.71.0", + "Migrated forc-client versions should use forc-client-prefixed tags" + ); + } + #[test] fn test_tag_for_version_standard_components() { let components = Components::collect().unwrap(); diff --git a/components.toml b/components.toml index e7903509a..3309ddd3e 100644 --- a/components.toml +++ b/components.toml @@ -1,7 +1,7 @@ [component.forc] name = "forc" tarball_prefix = "forc-binaries" -executables = ["forc", "forc-fmt", "forc-lsp", "forc-doc", "forc-call", "forc-deploy", "forc-run"] +executables = ["forc", "forc-fmt", "forc-lsp", "forc-doc"] repository_name = "sway" targets = ["linux_amd64", "linux_arm64", "darwin_amd64", "darwin_arm64"] publish = true @@ -53,11 +53,15 @@ targets = ["linux_amd64", "linux_arm64", "darwin_amd64", "darwin_arm64"] [component.forc-client] name = "forc-client" -tarball_prefix = "forc-binaries" +tarball_prefix = "forc-client" is_plugin = true executables = ["forc-call", "forc-deploy", "forc-run", "forc-submit"] -repository_name = "sway" +repository_name = "forc" +legacy_repository_name = "sway" +legacy_before = "0.71.0" +legacy_tarball_prefix = "forc-binaries" targets = ["linux_amd64", "linux_arm64", "darwin_amd64", "darwin_arm64"] +publish = true [component.forc-migrate] name = "forc-migrate" diff --git a/src/ops/fuelup_component/add.rs b/src/ops/fuelup_component/add.rs index d1feafbbc..5c8534660 100644 --- a/src/ops/fuelup_component/add.rs +++ b/src/ops/fuelup_component/add.rs @@ -40,10 +40,12 @@ You may create a custom toolchain using 'fuelup toolchain new '.", None => (&maybe_versioned_component, None), }; - if Component::is_default_forc_plugin(component) { + if let Some(parent) = Component::parent_component_for_executable(component) { bail!( - "'{}' is a default plugin that comes with core forc; please do 'fuelup component add forc' if you would like to install or update it.", - &maybe_versioned_component + "'{}' is an executable bundled with '{}'; please do 'fuelup component add {}' if you would like to install or update it.", + &maybe_versioned_component, + parent, + parent ); } diff --git a/src/proxy_cli.rs b/src/proxy_cli.rs index b4d764918..f34c2710b 100644 --- a/src/proxy_cli.rs +++ b/src/proxy_cli.rs @@ -5,7 +5,7 @@ use crate::{ toolchain_override::{ComponentSpec, ToolchainOverride}, }; use anyhow::Result; -use component::Components; +use component::{Component, Components, FORC_CLIENT}; use std::{ env, ffi::OsString, @@ -47,8 +47,14 @@ fn direct_proxy(proc_name: &str, args: &[OsString], toolchain: &Toolchain) -> Re // Plugins distributed by forc have to be handled a little differently, // if one of them is called we want to check for 'forc' instead. + // Similarly, forc-client executables should check for 'forc-client'. let component_name = if Components::is_distributed_by_forc(proc_name) { component::FORC + } else if Component::from_name(FORC_CLIENT) + .map(|fc| fc.executables.contains(&proc_name.to_string())) + .unwrap_or(false) + { + FORC_CLIENT } else { proc_name }; diff --git a/src/target_triple.rs b/src/target_triple.rs index f124a666d..1cbc75085 100644 --- a/src/target_triple.rs +++ b/src/target_triple.rs @@ -162,6 +162,15 @@ mod test_from_component { ); } + #[test] + fn forc_client_uses_simplified() { + let target = TargetTriple::from_component("forc-client").unwrap(); + assert!( + target.0.contains('_'), + "forc-client should use simplified target format" + ); + } + #[test] fn fuel_core_uses_rust_triple() { let target = TargetTriple::from_component("fuel-core").unwrap();