From 9b7070e8723ccf2a6423ff5037ee26b7604c867f Mon Sep 17 00:00:00 2001 From: Daniel Tao Date: Wed, 27 May 2026 00:27:43 +0000 Subject: [PATCH] Revert "feat: [PR-1797] add `sf migrate` command and Rust CLI migration banner (#266)" This reverts commit 06230a2a735c91728b4889e59779e82915017f6a. The Rust CLI install script at cli.sfcompute.com does not actually create the promised `sf-old` fallback, so users who follow the migration banner / `sf migrate` lose access to the legacy CLI. Reverting the banner + `sf migrate` command until that install script is fixed. Generated with [Indent](https://indent.com) Co-Authored-By: Indent --- install.sh | 22 ++------ src/checkVersion.ts | 23 +++----- src/index.ts | 30 +---------- src/lib/migrate.ts | 124 -------------------------------------------- src/lib/upgrade.ts | 12 +---- 5 files changed, 12 insertions(+), 199 deletions(-) delete mode 100644 src/lib/migrate.ts diff --git a/install.sh b/install.sh index d0292c5b..d2af927a 100755 --- a/install.sh +++ b/install.sh @@ -4,23 +4,14 @@ set -e # Exit on any error # Define the GitHub repository and the name of the binary. GITHUB_REPO="sfcompute/cli" -# Allow the caller to override the binary name / install dir so an in-place -# upgrade lands wherever the existing binary actually lives (e.g. `sf-old`, -# or an `sf` that's not under ~/.local/bin). The TS CLI sets these from -# process.execPath when it shells out to this script. -BINARY_NAME="${SF_CLI_BINARY_NAME:-sf}" +BINARY_NAME="sf" # Check the operating system OS="$(uname -s)" ARCH="$(uname -m)" -if [ -n "${SF_CLI_TARGET_DIR}" ]; then - TARGET_DIR="${SF_CLI_TARGET_DIR}" - TARGET_DIR_UNEXPANDED="${SF_CLI_TARGET_DIR}" -else - TARGET_DIR_UNEXPANDED="\${HOME}/.local/bin" - TARGET_DIR="${HOME}/.local/bin" -fi +TARGET_DIR_UNEXPANDED="\${HOME}/.local/bin" +TARGET_DIR="${HOME}/.local/bin" # Function to check if a command exists command_exists() { @@ -139,13 +130,6 @@ if [ -f "${TARGET_FILE}" ]; then echo "Successfully installed '${BINARY_NAME}' CLI." echo "The binary is located at '${TARGET_FILE}'." - # In-place upgrades (TARGET_DIR overridden by the caller) skip the PATH - # onboarding nudge — the user is already running the binary, so they - # obviously have it on PATH. - if [ -n "${SF_CLI_TARGET_DIR}" ]; then - exit 0 - fi - # Provide instructions for adding the target directory to the PATH. printf "\033[0;32m\\n" printf "To use the '%s' command, add '%s' to your PATH.\\n" "${BINARY_NAME}" "${TARGET_DIR_UNEXPANDED}" diff --git a/src/checkVersion.ts b/src/checkVersion.ts index 173169ea..64b68ecc 100644 --- a/src/checkVersion.ts +++ b/src/checkVersion.ts @@ -93,35 +93,30 @@ async function checkProductionCLIVersion() { } } -/** - * Returns true if an upgrade banner was shown (or an auto-upgrade was - * performed), false otherwise. Callers can use this to decide whether to - * show a different banner instead. - */ -export async function checkVersion(): Promise { +export async function checkVersion() { // Disable auto-upgrade if env var is set if (process.env.SF_CLI_DISABLE_AUTO_UPGRADE) { - return false; + return; } // Skip version check if running upgrade command const args = process.argv.slice(2); - if (args[0] === "upgrade") return false; + if (args[0] === "upgrade") return; const version = pkg.version; const latestVersion = await checkProductionCLIVersion(); - if (!latestVersion) return false; + if (!latestVersion) return; - if (version === latestVersion) return false; + if (version === latestVersion) return; // Don't upgrade from stable to prerelease const currentIsStable = !semver.prerelease(version); const latestIsPrerelease = semver.prerelease(latestVersion); - if (currentIsStable && latestIsPrerelease) return false; + if (currentIsStable && latestIsPrerelease) return; const isOutdated = semver.lt(version, latestVersion); - if (!isOutdated) return false; + if (!isOutdated) return; // Only auto-upgrade for patch changes and when not going to a prerelease const isPatchUpdate = semver.diff(version, latestVersion) === "patch"; @@ -154,7 +149,6 @@ export async function checkVersion(): Promise { } catch { // Silent error, just run the command the user wanted to run } - return true; } else if (!latestIsPrerelease) { // Only show update message for non-prerelease versions const message = ` @@ -172,8 +166,5 @@ Run 'sf upgrade' to update to the latest version borderStyle: "round", }), ); - return true; } - - return false; } diff --git a/src/index.ts b/src/index.ts index 8612401e..9c73532a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,7 +22,6 @@ import { registerDev } from "./lib/dev.ts"; import { registerImages } from "./lib/images/index.ts"; import { registerLogin } from "./lib/login.ts"; import { registerMe } from "./lib/me.ts"; -import { registerMigrate, showMigrateBanner } from "./lib/migrate.ts"; import { registerNodes } from "./lib/nodes/index.ts"; import { analytics, IS_TRACKING_DISABLED } from "./lib/posthog.ts"; import { registerScale } from "./lib/scale/index.tsx"; @@ -34,34 +33,8 @@ import { registerZones } from "./lib/zones.tsx"; async function main() { const program = new Command(); - // `sf migrate` replaces this binary outright, so auto-upgrading the legacy - // CLI first would be wasted work — and worse, the install scripts target - // the same `~/.local/bin/sf` path, so racing them risks clobbering the new - // Rust binary the user is about to install. - if (process.argv[2] === "migrate") { - process.env.SF_CLI_DISABLE_AUTO_UPGRADE = "1"; - } - if (!process.argv.includes("--json")) { - const [shownUpgradeBanner] = await Promise.all([ - checkVersion(), - getAppBanner(), - ]); - // If the user is already on the latest version of the legacy CLI, nudge - // them toward the new Rust CLI instead of showing nothing. We avoid - // double-stacking with the upgrade banner since users on outdated builds - // need to upgrade before migrating, and skip the banner for the - // `upgrade` / `migrate` commands themselves (where it'd just be noise) - // and for users who've opted out via SF_CLI_DISABLE_MIGRATE_BANNER. - const subcommand = process.argv[2]; - if ( - !shownUpgradeBanner && - subcommand !== "migrate" && - subcommand !== "upgrade" && - !process.env.SF_CLI_DISABLE_MIGRATE_BANNER - ) { - showMigrateBanner(); - } + await Promise.all([checkVersion(), getAppBanner()]); } program @@ -90,7 +63,6 @@ async function main() { registerBalance(program); registerTokens(program); registerUpgrade(program); - registerMigrate(program); await registerScale(program); registerMe(program); await registerVM(program); diff --git a/src/lib/migrate.ts b/src/lib/migrate.ts deleted file mode 100644 index e2bce95b..00000000 --- a/src/lib/migrate.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { spawn } from "node:child_process"; -import * as console from "node:console"; -import process from "node:process"; -import type { Command } from "@commander-js/extra-typings"; -import boxen from "boxen"; -import chalk from "chalk"; -import ora from "ora"; - -const NEW_CLI_INSTALL_URL = "https://cli.sfcompute.com"; -const MIGRATION_GUIDE_URL = "https://sfcompute.com/migrate"; - -export function showMigrateBanner() { - const message = `We've rewritten the sf CLI in Rust. - -List idle capacity on the orderbook to -recoup up to 20% of your spend. - -Run 'sf migrate' to switch. Your current -CLI stays as 'sf-old'. - -Docs: ${MIGRATION_GUIDE_URL} -Hide: SF_CLI_DISABLE_MIGRATE_BANNER=1`; - - console.log( - boxen(chalk.yellow(message), { - padding: 1, - borderColor: "yellow", - borderStyle: "round", - }), - ); -} - -export function registerMigrate(program: Command) { - return program - .command("migrate") - .description("Install the new Rust-based sf CLI") - .action(async () => { - const spinner = ora("Downloading install script").start(); - let script: string; - try { - const response = await fetch(NEW_CLI_INSTALL_URL); - if (!response.ok) { - spinner.fail("Failed to download install script."); - process.exit(1); - } - script = await response.text(); - spinner.succeed(); - } catch (err) { - spinner.fail("Failed to download install script."); - console.error(err); - process.exit(1); - } - - console.log(chalk.cyan("\nInstalling the new Rust sf CLI...\n")); - - if (process.env.IS_DEVELOPMENT_CLI_ENV) { - console.log( - chalk.yellow( - "[dev] Skipping install script execution (IS_DEVELOPMENT_CLI_ENV).\n", - ), - ); - } else { - const bashProcess = spawn("bash", [], { - stdio: ["pipe", "inherit", "inherit"], - env: process.env, - }); - - // Without an error listener, spawn failures (ENOENT/EACCES on bash) emit - // an unhandled 'error' event and crash the CLI instead of exiting cleanly. - const spawnError = new Promise((resolve) => { - bashProcess.once("error", resolve); - }); - - try { - bashProcess.stdin.write(script); - bashProcess.stdin.end(); - } catch { - // If stdin is already torn down (e.g. spawn failed synchronously), the - // 'error' event handler below will surface the real reason. - } - - const result = await Promise.race([ - new Promise<{ kind: "close"; code: number | null }>((resolve) => { - bashProcess.once("close", (code) => - resolve({ kind: "close", code }), - ); - }), - spawnError.then((err) => ({ kind: "error" as const, err })), - ]); - - if (result.kind === "error") { - console.error(chalk.red(`Failed to run bash: ${result.err.message}`)); - process.exit(1); - } - - if (result.code !== 0) { - console.error(chalk.red("\nMigration failed.")); - process.exit(1); - } - } - - console.log( - boxen( - chalk.cyan( - `You're on the new sf. - -Your previous CLI is still available as 'sf-old'. - -Next steps: - sf login - sf availability - -Docs: ${MIGRATION_GUIDE_URL}`, - ), - { - padding: 1, - borderColor: "cyan", - borderStyle: "round", - }, - ), - ); - process.exit(0); - }); -} diff --git a/src/lib/upgrade.ts b/src/lib/upgrade.ts index 5edebd15..ac3a5540 100644 --- a/src/lib/upgrade.ts +++ b/src/lib/upgrade.ts @@ -1,6 +1,5 @@ import { spawn } from "node:child_process"; import * as console from "node:console"; -import { basename, dirname } from "node:path"; import process from "node:process"; import type { Command } from "@commander-js/extra-typings"; import ora from "ora"; @@ -71,18 +70,9 @@ export async function handleUpgrade( // Execute the script with bash spinner.start("Installing upgrade"); - // Tell the install script to write back to this exact binary's path. Without - // this, the installer hardcodes ~/.local/bin/sf — which would clobber the - // Rust `sf` if we're running as `sf-old`, and would silently drop a - // duplicate copy when `sf` is installed somewhere else (e.g. /usr/local/bin). const bashProcess = spawn("bash", [], { stdio: ["pipe", "pipe", "pipe"], - env: { - ...process.env, - ...(version ? { SF_CLI_VERSION: version } : {}), - SF_CLI_TARGET_DIR: dirname(process.execPath), - SF_CLI_BINARY_NAME: basename(process.execPath), - }, + env: version ? { ...process.env, SF_CLI_VERSION: version } : process.env, }); let stdout = "";