diff --git a/CHANGELOG.md b/CHANGELOG.md index d5385636..4b45557b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## 2024-10-29 - CLI Version 0.13.4 + +- `modus build` should install SDK if not already installed [#524](https://github.com/hypermodeinc/modus/pull/524) + ## 2024-10-29 - CLI Version 0.13.3 - Fix Go not found on first install [#522](https://github.com/hypermodeinc/modus/pull/522) diff --git a/cli/src/commands/build/index.ts b/cli/src/commands/build/index.ts index 06850c37..75c4d344 100644 --- a/cli/src/commands/build/index.ts +++ b/cli/src/commands/build/index.ts @@ -18,6 +18,7 @@ import { getHeader } from "../../custom/header.js"; import { getAppInfo } from "../../util/appinfo.js"; import { withSpinner } from "../../util/index.js"; import { execFileWithExitCode } from "../../util/cp.js"; +import SDKInstallCommand from "../sdk/install/index.js"; export default class BuildCommand extends Command { static args = { @@ -63,6 +64,10 @@ export default class BuildCommand extends Command { // pass chalk level to child processes so they can colorize output process.env.FORCE_COLOR = chalk.level.toString(); + if (!(await vi.sdkVersionIsInstalled(app.sdk, app.sdkVersion))) { + await SDKInstallCommand.run([app.sdk, app.sdkVersion, "--no-logo"]); + } + const results = await withSpinner("Building " + app.name, async () => { const execOpts = { cwd: appPath, diff --git a/cli/src/commands/new/index.ts b/cli/src/commands/new/index.ts index d9aeff5a..af254321 100644 --- a/cli/src/commands/new/index.ts +++ b/cli/src/commands/new/index.ts @@ -17,7 +17,7 @@ import * as fs from "../../util/fs.js"; import * as vi from "../../util/versioninfo.js"; import { execFile } from "../../util/cp.js"; import { isOnline } from "../../util/index.js"; -import { GitHubOwner, GitHubRepo, MinGoVersion, MinNodeVersion, MinTinyGoVersion, ModusHomeDir, SDK, parseSDK } from "../../custom/globals.js"; +import { MinGoVersion, MinNodeVersion, MinTinyGoVersion, SDK, parseSDK } from "../../custom/globals.js"; import { withSpinner } from "../../util/index.js"; import { extract } from "../../util/tar.js"; import SDKInstallCommand from "../sdk/install/index.js"; @@ -250,37 +250,12 @@ export default class NewCommand extends Command { const sdkVersion = installedSdkVersion; const sdkPath = vi.getSdkPath(sdk, sdkVersion); - const templatesArchive = path.join(sdkPath, "templates.tar.gz"); if (!(await fs.exists(templatesArchive))) { this.logError(`Could not find any templates for ${sdkText} ${sdkVersion}`); this.exit(1); } - // Install build tools if needed - if (sdk == SDK.Go) { - const ext = os.platform() === "win32" ? ".exe" : ""; - const buildTool = path.join(sdkPath, "modus-go-build" + ext); - if (!(await fs.exists(buildTool))) { - if (await isOnline()) { - const module = `github.com/${GitHubOwner}/${GitHubRepo}/sdk/go/tools/modus-go-build@${sdkVersion}`; - await withSpinner("Downloading the Modus Go build tool.", async () => { - await execFile("go", ["install", module], { - cwd: ModusHomeDir, - shell: true, - env: { - ...process.env, - GOBIN: sdkPath, - }, - }); - }); - } else { - this.logError("Could not find the Modus Go build tool. Please try again when you are online."); - this.exit(1); - } - } - } - // Create the app this.log(chalk.dim(`Using ${sdkText} ${sdkVersion}`)); await withSpinner(`Creating a new Modus ${sdk} app.`, async () => { diff --git a/cli/src/commands/sdk/install/index.ts b/cli/src/commands/sdk/install/index.ts index 9069f04f..5ad00d2b 100644 --- a/cli/src/commands/sdk/install/index.ts +++ b/cli/src/commands/sdk/install/index.ts @@ -151,6 +151,9 @@ export default class SDKInstallCommand extends Command { spinner.fail(chalk.red(`Failed to download ${sdkText}`)); throw e; } + + await installer.installBuildTools(sdk, sdkVersion); + spinner.succeed(chalk.dim(`Installed ${sdkText}`)); }); } diff --git a/cli/src/util/index.ts b/cli/src/util/index.ts index 1725c060..54835806 100644 --- a/cli/src/util/index.ts +++ b/cli/src/util/index.ts @@ -8,7 +8,7 @@ */ import chalk from "chalk"; -import { oraPromise, Ora } from "ora"; +import ora, { Ora } from "ora"; import path from "node:path"; import { Readable } from "node:stream"; @@ -17,10 +17,18 @@ import { createWriteStream } from "node:fs"; import * as fs from "./fs.js"; export async function withSpinner(text: string, fn: (spinner: Ora) => Promise): Promise { - return await oraPromise(fn, { + // NOTE: Ora comes with "oraPromise", but it doesn't clear the original text on completion. + // Thus, we use this custom async function to ensure the spinner is applied correctly. + const spinner = ora({ color: "white", text: text, - }); + }).start(); + + try { + return await fn(spinner); + } finally { + spinner.stop(); + } } export async function downloadFile(url: string, dest: string): Promise { diff --git a/cli/src/util/installer.ts b/cli/src/util/installer.ts index a33e2504..67f5b4f1 100644 --- a/cli/src/util/installer.ts +++ b/cli/src/util/installer.ts @@ -12,6 +12,7 @@ import path from "node:path"; import * as fs from "./fs.js"; import * as vi from "./versioninfo.js"; import { extract } from "./tar.js"; +import { execFile } from "./cp.js"; import { downloadFile, isOnline } from "./index.js"; import { GitHubOwner, GitHubRepo, SDK } from "../custom/globals.js"; @@ -60,3 +61,34 @@ export async function installRuntime(version: string) { await extract(archivePath, installDir); await fs.rm(archivePath); } + +export async function installBuildTools(sdk: SDK, sdkVersion: string) { + switch (sdk) { + case SDK.Go: + await installGoBuildTools(sdkVersion); + break; + } +} + +async function installGoBuildTools(sdkVersion: string) { + const sdkPath = vi.getSdkPath(SDK.Go, sdkVersion); + + const ext = os.platform() === "win32" ? ".exe" : ""; + const buildTool = path.join(sdkPath, "modus-go-build" + ext); + if (await fs.exists(buildTool)) { + return; + } + + if (!(await isOnline())) { + throw new Error("Could not find the Modus Go build tool. Please try again when you are online."); + } + + const module = `github.com/${GitHubOwner}/${GitHubRepo}/sdk/go/tools/modus-go-build@${sdkVersion}`; + await execFile("go", ["install", module], { + shell: true, + env: { + ...process.env, + GOBIN: sdkPath, + }, + }); +}