Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions ci/build-channel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
);
}
}
108 changes: 102 additions & 6 deletions component/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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") => {
Comment thread
cursor[bot] marked this conversation as resolved.
format!("{}-{}", self.name, version)
}
_ => format!("v{}", version),
Expand Down Expand Up @@ -153,13 +156,35 @@ 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
}

/// Deprecated: Use `parent_component_for_executable` instead for better error messages.
pub fn is_default_forc_plugin(name: &str) -> bool {
Self::parent_component_for_executable(name).is_some()
Comment thread
cursor[bot] marked this conversation as resolved.
Outdated
}

/// Tests if the supplied `Component`s come from same distribution
Expand Down Expand Up @@ -328,7 +353,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 {
Expand Down Expand Up @@ -634,6 +659,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();
Expand Down
10 changes: 7 additions & 3 deletions components.toml
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Comment thread
cursor[bot] marked this conversation as resolved.

[component.forc-migrate]
name = "forc-migrate"
Expand Down
8 changes: 5 additions & 3 deletions src/ops/fuelup_component/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ You may create a custom toolchain using 'fuelup toolchain new <toolchain>'.",
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
);
}

Expand Down
8 changes: 7 additions & 1 deletion src/proxy_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
};
Expand Down
9 changes: 9 additions & 0 deletions src/target_triple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading