Skip to content

Commit 6a6e480

Browse files
Merge pull request #96 from maejima-fumika/feature/bscript-update
Add an update command to CLI and refactor tests for CLI
2 parents f0a7a43 + ba6b132 commit 6a6e480

30 files changed

+1298
-518
lines changed

cli/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ node_modules/
44
.idea/
55
a.out.dSYM/
66
tsconfig.tsbuildinfo
7+
temp-files/

cli/src/commands/board/flash-runtime.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,17 @@ import { Command } from "commander";
22
import inquirer from 'inquirer';
33
import * as path from 'path';
44
import { SerialPort } from 'serialport'
5-
import { GlobalConfigHandler } from "../../config/global-config";
65
import { BoardName } from "../../config/board-utils";
76
import { logger, LogStep, showErrorMessages } from "../../core/logger";
87
import { exec } from '../../core/shell';
98
import chalk from "chalk";
9+
import { CommandHandler } from "../command";
1010

1111

1212
const RUNTIME_ESP_PORT_DIR = (runtimeDir: string) => path.join(runtimeDir, 'ports/esp32');
1313

14-
abstract class FlashRuntimeHandler {
15-
globalConfigHandler: GlobalConfigHandler;
16-
17-
constructor() {
18-
this.globalConfigHandler = GlobalConfigHandler.load();
19-
}
20-
14+
abstract class FlashRuntimeHandler extends CommandHandler {
2115
abstract isSetup(): boolean;
22-
2316
abstract flashRuntime(port: string, monitor: boolean): Promise<void>;
2417
}
2518

cli/src/commands/board/full-clean.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,26 @@ import { Command } from "commander";
22
import inquirer from 'inquirer';
33
import { logger, showErrorMessages } from "../../core/logger";
44
import * as fs from '../../core/fs';
5-
import { GLOBAL_BLUESCRIPT_PATH } from "../../config/global-config";
5+
import { CommandHandler } from "../command";
6+
import { GLOBAL_SETTINGS } from "../../config/constants";
67

7-
export async function handleFullcleanCommand(options: { force: boolean }) {
8+
9+
class FullcleanHandler extends CommandHandler {
10+
constructor() {
11+
super(false);
12+
}
13+
14+
fullclean() {
15+
if (fs.exists(GLOBAL_SETTINGS.BLUESCRIPT_DIR)) {
16+
fs.removeDir(GLOBAL_SETTINGS.BLUESCRIPT_DIR);
17+
}
18+
}
19+
}
20+
21+
export async function handleFullcleanCommand(options: { force?: boolean }) {
822
try {
23+
const fullcleanHandler = new FullcleanHandler();
24+
925
let confirmed = options.force;
1026
if (!confirmed) {
1127
const { proceed } = await inquirer.prompt([
@@ -24,9 +40,7 @@ export async function handleFullcleanCommand(options: { force: boolean }) {
2440
}
2541

2642
// Fullclean
27-
if (fs.exists(GLOBAL_BLUESCRIPT_PATH)) {
28-
fs.removeDir(GLOBAL_BLUESCRIPT_PATH);
29-
}
43+
fullcleanHandler.fullclean();
3044

3145
logger.br();
3246
logger.success(`Success to delete entire settings.`);

cli/src/commands/board/list.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,25 @@
11
import { Command } from "commander";
22
import chalk from 'chalk';
3-
import { GlobalConfigHandler } from "../../config/global-config";
43
import { BOARD_NAMES } from "../../config/board-utils";
54
import { logger, showErrorMessages } from "../../core/logger";
5+
import { CommandHandler } from "../command";
66

7-
export async function handleListCommand() {
8-
try {
9-
const supportedBoards = BOARD_NAMES;
10-
const globalConfigHandler = GlobalConfigHandler.load();
117

8+
class ListHandler extends CommandHandler {
9+
list() {
10+
const supportedBoards = BOARD_NAMES;
1211
logger.log('Available boards:');
1312
supportedBoards.forEach(board => {
14-
const isSetup = globalConfigHandler.isBoardSetup(board);
13+
const isSetup = this.globalConfigHandler.isBoardSetup(board);
1514
logger.log(' --', board, isSetup ? ` - ${chalk.green('set up')}` : ` - ${chalk.gray('not set up')}`);
1615
});
16+
}
17+
}
18+
19+
export async function handleListCommand() {
20+
try {
21+
const listHandler = new ListHandler();
22+
listHandler.list();
1723

1824
logger.br();
1925
logger.info(`To set up a new board, run ${chalk.yellow('bscript board setup <board-name>')}`);

cli/src/commands/board/remove.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,17 @@
11
import { Command } from "commander";
22
import inquirer from 'inquirer';
3-
import { GlobalConfigHandler } from "../../config/global-config";
43
import { BoardName } from "../../config/board-utils";
54
import { logger, LogStep, showErrorMessages } from "../../core/logger";
65
import * as fs from '../../core/fs';
6+
import { CommandHandler } from "../command";
77

88

9-
abstract class RemoveHandler {
10-
globalConfigHandler: GlobalConfigHandler;
11-
12-
constructor() {
13-
this.globalConfigHandler = GlobalConfigHandler.load();
14-
}
15-
9+
abstract class RemoveHandler extends CommandHandler {
1610
async remove() {
1711
await this.removeBoard();
1812
this.globalConfigHandler.save();
1913
}
20-
2114
abstract isSetup(): boolean;
22-
2315
abstract removeBoard(): Promise<void>;
2416
}
2517

@@ -52,7 +44,7 @@ function getRemoveHandler(board: string) {
5244
}
5345
}
5446

55-
export async function handleRemoveCommand(board: string, options: { force: boolean }) {
47+
export async function handleRemoveCommand(board: string, options: { force?: boolean }) {
5648
try {
5749
const removeHandler = getRemoveHandler(board);
5850

cli/src/commands/board/setup.ts

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,19 @@ import * as path from 'path';
33
import * as os from 'os';
44
import inquirer from 'inquirer';
55
import { logger, LogStep, showErrorMessages, SkipStep } from "../../core/logger";
6-
import { VM_VERSION, GLOBAL_BLUESCRIPT_PATH, GlobalConfigHandler } from "../../config/global-config";
76
import { BoardName } from "../../config/board-utils";
87
import { exec } from '../../core/shell';
98
import * as fs from '../../core/fs';
109
import chalk from "chalk";
10+
import { CommandHandler } from "../command";
11+
import { GLOBAL_SETTINGS } from "../../config/constants";
1112

1213

13-
const RUNTIME_ZIP_URL = `https://github.com/csg-tokyo/bluescript/releases/download/v${VM_VERSION}/release-microcontroller-v${VM_VERSION}.zip`;
14-
const RUNTIME_DIR = path.join(GLOBAL_BLUESCRIPT_PATH, 'microcontroller');
15-
16-
const ESP_IDF_VERSION = 'v5.4';
17-
const ESP_IDF_GIT_REPO = 'https://github.com/espressif/esp-idf.git';
18-
const ESP_ROOT_DIR = path.join(GLOBAL_BLUESCRIPT_PATH, 'esp');
19-
const ESP_IDF_EXPORT_FILE = path.join(ESP_ROOT_DIR, 'esp-idf/export.sh');
20-
const ESP_IDF_INSTALL_FILE = path.join(ESP_ROOT_DIR, 'esp-idf/install.sh');
21-
22-
23-
abstract class SetupHandler {
24-
protected globalConfigHandler: GlobalConfigHandler;
25-
26-
constructor() {
27-
this.globalConfigHandler = GlobalConfigHandler.load();
28-
}
14+
abstract class SetupHandler extends CommandHandler {
2915

3016
getSetupPlan(): string[] {
3117
const plan: string[] = [];
32-
plan.push(`Download BlueScript runtime from ${RUNTIME_ZIP_URL}`);
18+
plan.push(`Download BlueScript runtime from ${GLOBAL_SETTINGS.RUNTIME_ZIP_URL}`);
3319
plan.push(...this.getBoardSetupPlan());
3420
return plan;
3521
}
@@ -42,8 +28,8 @@ abstract class SetupHandler {
4228
}
4329

4430
private ensureBlueScriptDir() {
45-
if (!fs.exists(GLOBAL_BLUESCRIPT_PATH)) {
46-
fs.makeDir(GLOBAL_BLUESCRIPT_PATH);
31+
if (!fs.exists(GLOBAL_SETTINGS.BLUESCRIPT_DIR)) {
32+
fs.makeDir(GLOBAL_SETTINGS.BLUESCRIPT_DIR);
4733
}
4834
}
4935

@@ -56,18 +42,16 @@ abstract class SetupHandler {
5642
if (!this.needToDownloadBlueScriptRuntime()) {
5743
throw new SkipStep('already downloaded.', undefined);
5844
}
59-
if (fs.exists(RUNTIME_DIR)) {
60-
fs.removeDir(RUNTIME_DIR);
45+
if (fs.exists(GLOBAL_SETTINGS.RUNTIME_DIR)) {
46+
fs.removeDir(GLOBAL_SETTINGS.RUNTIME_DIR);
6147
}
6248

63-
await fs.downloadAndUnzip(RUNTIME_ZIP_URL, GLOBAL_BLUESCRIPT_PATH);
64-
this.globalConfigHandler.setRuntimeDir(RUNTIME_DIR);
49+
await fs.downloadAndUnzip(GLOBAL_SETTINGS.RUNTIME_ZIP_URL, GLOBAL_SETTINGS.BLUESCRIPT_DIR);
50+
this.globalConfigHandler.setRuntimeDir(GLOBAL_SETTINGS.RUNTIME_DIR);
6551
}
6652

6753
abstract needSetup(): boolean;
68-
6954
abstract getBoardSetupPlan(): string[];
70-
7155
abstract setupBoard(): Promise<void>;
7256
}
7357

@@ -103,7 +87,7 @@ export class ESP32SetupHandler extends SetupHandler {
10387
} else {
10488
throw new Error('Unknown OS.');
10589
}
106-
plan.push(`Clone ESP-IDF ${ESP_IDF_VERSION} from ${ESP_IDF_GIT_REPO}.`);
90+
plan.push(`Clone ESP-IDF ${GLOBAL_SETTINGS.ESP_IDF_VERSION} from ${GLOBAL_SETTINGS.ESP_IDF_GIT_REPO}.`);
10791
plan.push('Run ESP-IDF install script.');
10892
return plan;
10993
}
@@ -115,9 +99,9 @@ export class ESP32SetupHandler extends SetupHandler {
11599
await this.runEspIdfInstallScript();
116100

117101
this.globalConfigHandler.updateBoardConfig(this.boardName, {
118-
idfVersion: ESP_IDF_VERSION,
119-
rootDir: ESP_ROOT_DIR,
120-
exportFile: ESP_IDF_EXPORT_FILE,
102+
idfVersion: GLOBAL_SETTINGS.ESP_IDF_VERSION,
103+
rootDir: GLOBAL_SETTINGS.ESP_ROOT_DIR,
104+
exportFile: GLOBAL_SETTINGS.ESP_IDF_EXPORT_FILE,
121105
xtensaGccDir: await this.getXtensaGccDir(),
122106
});
123107
}
@@ -179,28 +163,29 @@ export class ESP32SetupHandler extends SetupHandler {
179163
}
180164

181165
@LogStep(
182-
`Cloning ESP-IDF ${ESP_IDF_VERSION} from ${ESP_IDF_GIT_REPO}... It may take a while.`
166+
`Cloning ESP-IDF ${GLOBAL_SETTINGS.ESP_IDF_VERSION} from ${GLOBAL_SETTINGS.ESP_IDF_GIT_REPO}... It may take a while.`
183167
)
184168
private async cloneEspIdf() {
185-
if (fs.exists(ESP_ROOT_DIR)) {
186-
fs.removeDir(ESP_ROOT_DIR);
169+
if (fs.exists(GLOBAL_SETTINGS.ESP_ROOT_DIR)) {
170+
fs.removeDir(GLOBAL_SETTINGS.ESP_ROOT_DIR);
187171
}
188172
if (!(await this.isPackageInstalled('git'))) {
189173
throw new Error('Cannot find git command. Please install git and try again.');
190174
}
191175

192-
fs.makeDir(ESP_ROOT_DIR);
193-
await exec(`git clone --depth 1 -b ${ESP_IDF_VERSION} --recursive ${ESP_IDF_GIT_REPO}`, { cwd: ESP_ROOT_DIR });
176+
fs.makeDir(GLOBAL_SETTINGS.ESP_ROOT_DIR);
177+
await exec(`git clone --depth 1 -b ${GLOBAL_SETTINGS.ESP_IDF_VERSION} --recursive ${GLOBAL_SETTINGS.ESP_IDF_GIT_REPO}`,
178+
{ cwd: GLOBAL_SETTINGS.ESP_ROOT_DIR });
194179
}
195180

196181
@LogStep('Running ESP-IDF install script...')
197182
private async runEspIdfInstallScript() {
198-
await exec(ESP_IDF_INSTALL_FILE);
183+
await exec(GLOBAL_SETTINGS.ESP_IDF_INSTALL_FILE);
199184
}
200185

201186
private async getXtensaGccDir() {
202187
try {
203-
const gccPath = await exec(`source ${ESP_IDF_EXPORT_FILE} > /dev/null 2>&1 && which xtensa-esp32-elf-gcc`, { silent:true });
188+
const gccPath = await exec(`source ${GLOBAL_SETTINGS.ESP_IDF_EXPORT_FILE} > /dev/null 2>&1 && which xtensa-esp32-elf-gcc`, { silent:true });
204189
return path.dirname(gccPath);
205190
} catch (error) {
206191
throw new Error('Failed to get xtensa gcc path.', {cause: error});
@@ -249,7 +234,7 @@ export async function handleSetupCommand(board: string) {
249234
await setupHandler.setup();
250235

251236
logger.br();
252-
logger.success(`Success to se tup ${board}`);
237+
logger.success(`Success to set up ${board}`);
253238
logger.info(`Next step: run ${chalk.yellow(`bscript board flash-runtime ${board}`)}`);
254239

255240
} catch (error) {

0 commit comments

Comments
 (0)