Skip to content

Commit

Permalink
CLI Polish Round 2 (#506)
Browse files Browse the repository at this point in the history
  • Loading branch information
octref authored Oct 24, 2024
1 parent c498696 commit 9d868a9
Show file tree
Hide file tree
Showing 13 changed files with 339 additions and 88 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ In previous releases, the name "Hypermode" was used for all three._
- Move hyp settings for local model invocation to env variables [#495](https://github.com/hypermodeinc/modus/pull/495) [#504](https://github.com/hypermodeinc/modus/pull/504)
- Change GraphQL SDK examples to use a generic public GraphQL API [#501](https://github.com/hypermodeinc/modus/pull/501)
- Improve file watching and fix Windows issues [#505](https://github.com/hypermodeinc/modus/pull/505)
- Improve help messages, add `modus info` and show SDK version in `modus new` [#506](https://github.com/hypermodeinc/modus/pull/506)

## 2024-10-02 - Version 0.12.7

Expand Down
8 changes: 7 additions & 1 deletion cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@
"runtime": {
"description": "Modus Runtime Management"
}
}
},
"additionalHelpFlags": [
"-h"
],
"additionalVersionFlags": [
"-v"
]
}
}
5 changes: 5 additions & 0 deletions cli/src/commands/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export default class BuildCommand extends Command {
};

static flags = {
help: Flags.help({
char: "h",
helpLabel: "-h, --help",
description: "Show help message",
}),
nologo: Flags.boolean({
aliases: ["no-logo"],
hidden: true,
Expand Down
5 changes: 5 additions & 0 deletions cli/src/commands/dev/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ export default class DevCommand extends Command {
};

static flags = {
help: Flags.help({
char: "h",
helpLabel: "-h, --help",
description: "Show help message",
}),
nologo: Flags.boolean({
aliases: ["no-logo"],
hidden: true,
Expand Down
125 changes: 125 additions & 0 deletions cli/src/commands/info/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { Command, Flags } from "@oclif/core";
import chalk from "chalk";
import os from "node:os";
import * as vi from "../../util/versioninfo.js";
import { SDK } from "../../custom/globals.js";
import { getHeader } from "../../custom/header.js";
import { execFileWithExitCode } from "../../util/cp.js";

export default class InfoCommand extends Command {
static args = {};

static flags = {
help: Flags.help({
char: "h",
helpLabel: "-h, --help",
description: "Show help message",
}),
nologo: Flags.boolean({
aliases: ["no-logo"],
hidden: true,
}),
};

static description = "Show Modus info";

static examples = ["modus info"];

async run(): Promise<void> {
const { flags } = await this.parse(InfoCommand);

if (!flags.nologo) {
this.log(getHeader(this.config.version));
}

const info = await this.logInfo();
this.displayInfo(info);
}

async logInfo(): Promise<Record<string, string | string[]>> {
await this.logRuntimeVersions();
await this.logSDKVersions();

return {
"Modus Installation Path": this.config.root,
"Operating System": `${os.type()} ${os.release()}`,
"Platform Architecture": process.arch,
"Node.js Version": process.version,
"NPM Version": await this.getNPMVersion(),
"Go Version": await this.getGoVersion(),
"TinyGo Version": await this.getTinyGoVersion(),
};
}

displayInfo(info: Record<string, string | string[]>): void {
for (const [key, value] of Object.entries(info)) {
if (Array.isArray(value)) {
this.log(`${chalk.bold(key)}:`);
value.forEach((v) => this.log(` ${v}`));
} else if (value) {
this.log(`${chalk.bold(key)}: ${value}`);
}
}
}

async logRuntimeVersions() {
const versions = await vi.getInstalledRuntimeVersions();
if (versions.length > 0) {
this.log(chalk.bold.cyan("Installed Runtimes:"));
for (const version of versions) {
this.log(`• Modus Runtime ${version}`);
}
} else {
this.log(chalk.yellow("No Modus runtimes installed"));
}

this.log();
}

async logSDKVersions() {
let found = false;
for (const sdk of Object.values(SDK)) {
const versions = await vi.getInstalledSdkVersions(sdk);
if (versions.length === 0) {
continue;
}
if (!found) {
this.log(chalk.bold.cyan("Installed SDKs:"));
found = true;
}

for (const version of versions) {
this.log(`• Modus ${sdk} SDK ${version}`);
}
}

if (!found) {
this.log(chalk.yellow("No Modus SDKs installed"));
}

this.log();
}

async getNPMVersion(): Promise<string> {
const { stdout } = await execFileWithExitCode("npm", ["--version"], { shell: true });
return stdout.trim();
}

async getGoVersion(): Promise<string> {
try {
const { stdout } = await execFileWithExitCode("go", ["version"], { shell: true });
return stdout.trim().split(" ")[2];
} catch (error) {
return "Not installed";
}
}

async getTinyGoVersion(): Promise<string> {
try {
const { stdout } = await execFileWithExitCode("tinygo", ["version"], { shell: true });
return stdout.trim().split(" ")[2];
} catch (error) {
return "Not installed";
}
}
}
111 changes: 62 additions & 49 deletions cli/src/commands/new/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ export default class NewCommand extends Command {
static examples = ["modus new", "modus new --name my-app", "modus new --name my-app --sdk go --dir ./my-app --force"];

static flags = {
help: Flags.help({
char: "h",
helpLabel: "-h, --help",
description: "Show help message",
}),
nologo: Flags.boolean({
aliases: ["no-logo"],
hidden: true,
Expand Down Expand Up @@ -67,65 +72,69 @@ export default class NewCommand extends Command {
};

async run(): Promise<void> {
const { flags } = await this.parse(NewCommand);
try {
const { flags } = await this.parse(NewCommand);

if (!flags.nologo) {
this.log(getHeader(this.config.version));
}
if (!flags.nologo) {
this.log(getHeader(this.config.version));
}

this.log(chalk.hex("#A585FF")(NewCommand.description) + "\n");

let sdk: SDK;
if (flags.sdk) {
sdk = parseSDK(flags.sdk);
} else {
const sdkInput = await inquirer.select({
message: "Select a SDK",
default: SDK.Go,
choices: [
{
value: SDK.Go,
},
{
value: SDK.AssemblyScript,
},
],
});
this.log(chalk.hex("#A585FF")(NewCommand.description) + "\n");

let sdk: SDK;
if (flags.sdk) {
sdk = parseSDK(flags.sdk);
} else {
const sdkInput = await inquirer.select({
message: "Select a SDK",
default: SDK.Go,
choices: [
{
value: SDK.Go,
},
{
value: SDK.AssemblyScript,
},
],
});

sdk = parseSDK(sdkInput);
}
sdk = parseSDK(sdkInput);
}

const defaultAppName = getDefaultAppNameBySdk(sdk);
const name =
flags.name ||
(await inquirer.input({
message: "Pick a name for your app:",
default: defaultAppName,
}));
const defaultAppName = getDefaultAppNameBySdk(sdk);
const name =
flags.name ||
(await inquirer.input({
message: "Pick a name for your app:",
default: defaultAppName,
}));

const dir = flags.dir || "." + path.sep + name;
const dir = flags.dir || "." + path.sep + name;

if (!flags.force) {
const confirmed = await inquirer.confirm({ message: "Continue?", default: true });
if (!confirmed) {
this.log(chalk.dim("Aborted"));
this.exit(1);
if (!flags.force && (await fs.exists(dir))) {
const confirmed = await inquirer.confirm({ message: `Directory ${dir} already exists. Do you want to overwrite it?`, default: false });
if (!confirmed) {
this.abort();
}
}
}

this.log();
await this.createApp(name, dir, sdk, MODUS_DEFAULT_TEMPLATE_NAME, flags.force, flags.prerelease);
}
if (!flags.force) {
const confirmed = await inquirer.confirm({ message: "Continue?", default: true });
if (!confirmed) {
this.abort();
}
}

private async createApp(name: string, dir: string, sdk: SDK, template: string, force: boolean, prerelease: boolean) {
if (!force && (await fs.exists(dir))) {
const confirmed = await inquirer.confirm({ message: "Attempting to overwrite a folder that already exists.\nAre you sure you want to continue?", default: false });
if (!confirmed) {
this.log(chalk.dim("Aborted"));
this.exit(1);
this.log();
await this.createApp(name, dir, sdk, MODUS_DEFAULT_TEMPLATE_NAME, flags.force, flags.prerelease);
} catch (err: any) {
if (err.name === "ExitPromptError") {
this.abort();
}
}
}

private async createApp(name: string, dir: string, sdk: SDK, template: string, force: boolean, prerelease: boolean) {
// Validate SDK-specific prerequisites
const sdkText = `Modus ${sdk} SDK`;
switch (sdk) {
Expand Down Expand Up @@ -210,8 +219,7 @@ export default class NewCommand extends Command {
default: true,
});
if (!confirmed) {
this.log(chalk.dim("Aborted"));
this.exit(1);
this.abort();
} else {
updateSDK = true;
}
Expand Down Expand Up @@ -302,6 +310,11 @@ export default class NewCommand extends Command {
private logError(message: string) {
this.log(chalk.red(" ERROR ") + chalk.dim(": " + message));
}

private abort() {
this.log(chalk.dim("Aborted"));
this.exit(1);
}
}

async function getGoVersion(): Promise<string | undefined> {
Expand Down
5 changes: 5 additions & 0 deletions cli/src/commands/runtime/install/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ export default class RuntimeInstallCommand extends Command {
static examples = ["modus runtime install", "modus runtime install v1.2.3", "modus runtime install --prerelease"];

static flags = {
help: Flags.help({
char: "h",
helpLabel: '-h, --help',
description: "Show help message"
}),
nologo: Flags.boolean({
aliases: ["no-logo"],
hidden: true,
Expand Down
5 changes: 5 additions & 0 deletions cli/src/commands/runtime/list/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ export default class RuntimeListCommand extends Command {
static description = "List installed Modus runtimes";
static examples = ["modus runtime list"];
static flags = {
help: Flags.help({
char: "h",
helpLabel: "-h, --help",
description: "Show help message",
}),
nologo: Flags.boolean({
aliases: ["no-logo"],
hidden: true,
Expand Down
Loading

0 comments on commit 9d868a9

Please sign in to comment.