Skip to content

Commit

Permalink
Merge d69174a into 117b2a4
Browse files Browse the repository at this point in the history
  • Loading branch information
kittaakos authored May 12, 2023
2 parents 117b2a4 + d69174a commit e203c61
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 183 deletions.
2 changes: 0 additions & 2 deletions arduino-ide-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,9 @@
"devDependencies": {
"@octokit/rest": "^18.12.0",
"@types/chai": "^4.2.7",
"@types/chai-string": "^1.4.2",
"@types/mocha": "^5.2.7",
"@types/react-window": "^1.8.5",
"chai": "^4.2.0",
"chai-string": "^1.5.0",
"decompress": "^4.2.0",
"decompress-tarbz2": "^4.1.1",
"decompress-targz": "^4.1.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ export interface ExecutableService {
clangdUri: string;
cliUri: string;
lsUri: string;
fwuploaderUri: string;
}>;
}
19 changes: 6 additions & 13 deletions arduino-ide-extension/src/node/arduino-daemon-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export class ArduinoDaemonImpl

private _running = false;
private _port = new Deferred<string>();
private _execPath: string | undefined;

// Backend application lifecycle.

Expand All @@ -68,7 +67,7 @@ export class ArduinoDaemonImpl
async start(): Promise<string> {
try {
this.toDispose.dispose(); // This will `kill` the previously started daemon process, if any.
const cliPath = await this.getExecPath();
const cliPath = this.getExecPath();
this.onData(`Starting daemon from ${cliPath}...`);
const { daemon, port } = await this.spawnDaemonProcess();
// Watchdog process for terminating the daemon process when the backend app terminates.
Expand Down Expand Up @@ -132,12 +131,8 @@ export class ArduinoDaemonImpl
return this.onDaemonStoppedEmitter.event;
}

async getExecPath(): Promise<string> {
if (this._execPath) {
return this._execPath;
}
this._execPath = await getExecPath('arduino-cli', this.onError.bind(this));
return this._execPath;
getExecPath(): string {
return getExecPath('arduino-cli');
}

protected async getSpawnArgs(): Promise<string[]> {
Expand All @@ -151,7 +146,7 @@ export class ArduinoDaemonImpl
'--port',
'0',
'--config-file',
`"${cliConfigPath}"`,
cliConfigPath,
'-v',
];
if (debug) {
Expand All @@ -173,10 +168,8 @@ export class ArduinoDaemonImpl
daemon: ChildProcess;
port: string;
}> {
const [cliPath, args] = await Promise.all([
this.getExecPath(),
this.getSpawnArgs(),
]);
const args = await this.getSpawnArgs();
const cliPath = this.getExecPath();
const ready = new Deferred<{ daemon: ChildProcess; port: string }>();
const options = { shell: true };
const daemon = spawn(`"${cliPath}"`, args, options);
Expand Down
51 changes: 17 additions & 34 deletions arduino-ide-extension/src/node/arduino-firmware-uploader-impl.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,22 @@
import { ILogger } from '@theia/core/lib/common/logger';
import { inject, injectable, named } from '@theia/core/shared/inversify';
import type { Port } from '../common/protocol';
import {
ArduinoFirmwareUploader,
FirmwareInfo,
} from '../common/protocol/arduino-firmware-uploader';
import { injectable, inject, named } from '@theia/core/shared/inversify';
import { ExecutableService, Port } from '../common/protocol';
import { getExecPath, spawnCommand } from './exec-util';
import { ILogger } from '@theia/core/lib/common/logger';
import { MonitorManager } from './monitor-manager';

@injectable()
export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
@inject(ExecutableService)
protected executableService: ExecutableService;

protected _execPath: string | undefined;

@inject(ILogger)
@named('fwuploader')
protected readonly logger: ILogger;

private readonly logger: ILogger;
@inject(MonitorManager)
protected readonly monitorManager: MonitorManager;

protected onError(error: any): void {
this.logger.error(error);
}

async getExecPath(): Promise<string> {
if (this._execPath) {
return this._execPath;
}
this._execPath = await getExecPath('arduino-fwuploader');
return this._execPath;
}

async runCommand(args: string[]): Promise<any> {
const execPath = await this.getExecPath();
return await spawnCommand(`"${execPath}"`, args, this.onError.bind(this));
}
private readonly monitorManager: MonitorManager;

async uploadCertificates(command: string): Promise<any> {
async uploadCertificates(command: string): Promise<string> {
return await this.runCommand(['certificates', 'flash', command]);
}

Expand Down Expand Up @@ -70,14 +47,13 @@ export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
}

async flash(firmware: FirmwareInfo, port: Port): Promise<string> {
let output;
const board = {
name: firmware.board_name,
fqbn: firmware.board_fqbn,
};
try {
await this.monitorManager.notifyUploadStarted(board.fqbn, port);
output = await this.runCommand([
const output = await this.runCommand([
'firmware',
'flash',
'--fqbn',
Expand All @@ -87,11 +63,18 @@ export class ArduinoFirmwareUploaderImpl implements ArduinoFirmwareUploader {
'--module',
`${firmware.module}@${firmware.firmware_version}`,
]);
} catch (e) {
throw e;
return output;
} finally {
await this.monitorManager.notifyUploadFinished(board.fqbn, port);
return output;
}
}

private onError(error: Error): void {
this.logger.error(error);
}

private async runCommand(args: string[]): Promise<string> {
const execPath = getExecPath('arduino-fwuploader');
return await spawnCommand(execPath, args, this.onError.bind(this));
}
}
9 changes: 2 additions & 7 deletions arduino-ide-extension/src/node/clang-formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,16 @@ export class ClangFormatter implements Formatter {
this.style(formatterConfigFolderUris, options),
]);
const formatted = await spawnCommand(
`"${execPath}"`,
execPath,
[style],
console.error,
content
);
return formatted;
}

private _execPath: string | undefined;
private async execPath(): Promise<string> {
if (this._execPath) {
return this._execPath;
}
this._execPath = await getExecPath('clang-format');
return this._execPath;
return getExecPath('clang-format');
}

/**
Expand Down
13 changes: 4 additions & 9 deletions arduino-ide-extension/src/node/config-service-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,8 @@ export class ConfigServiceImpl
}

private async getFallbackCliConfig(): Promise<DefaultCliConfig> {
const cliPath = await this.daemon.getExecPath();
const rawJson = await spawnCommand(`"${cliPath}"`, [
const cliPath = this.daemon.getExecPath();
const rawJson = await spawnCommand(cliPath, [
'config',
'dump',
'format',
Expand All @@ -233,13 +233,8 @@ export class ConfigServiceImpl
}

private async initCliConfigTo(fsPathToDir: string): Promise<void> {
const cliPath = await this.daemon.getExecPath();
await spawnCommand(`"${cliPath}"`, [
'config',
'init',
'--dest-dir',
`"${fsPathToDir}"`,
]);
const cliPath = this.daemon.getExecPath();
await spawnCommand(cliPath, ['config', 'init', '--dest-dir', fsPathToDir]);
}

private async mapCliConfigToAppConfig(
Expand Down
58 changes: 12 additions & 46 deletions arduino-ide-extension/src/node/exec-util.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,17 @@
import { spawn } from 'node:child_process';
import os from 'node:os';
import which from 'which';
import semver from 'semver';
import { join } from 'node:path';
import { spawn } from 'node:child_process';

export async function getExecPath(
commandName: string,
onError: (error: Error) => void = (error) => console.log(error),
versionArg?: string | undefined,
inBinDir?: boolean
): Promise<string> {
const execName = `${commandName}${os.platform() === 'win32' ? '.exe' : ''}`;
const relativePath = ['..', '..', 'build'];
if (inBinDir) {
relativePath.push('bin');
}
const buildCommand = join(__dirname, ...relativePath, execName);
if (!versionArg) {
return buildCommand;
}
const versionRegexp = /\d+\.\d+\.\d+/;
const buildVersion = await spawnCommand(
`"${buildCommand}"`,
[versionArg],
onError
);
const buildShortVersion = (buildVersion.match(versionRegexp) || [])[0];
const pathCommand = await new Promise<string | undefined>((resolve) =>
which(execName, (error, path) => resolve(error ? undefined : path))
);
if (!pathCommand) {
return buildCommand;
}
const pathVersion = await spawnCommand(
`"${pathCommand}"`,
[versionArg],
onError
);
const pathShortVersion = (pathVersion.match(versionRegexp) || [])[0];
if (
pathShortVersion &&
buildShortVersion &&
semver.gt(pathShortVersion, buildShortVersion)
) {
return pathCommand;
}
return buildCommand;
export type ArduinoBinaryName =
| 'arduino-cli'
| 'arduino-fwuploader'
| 'arduino-language-server';
export type ClangBinaryName = 'clangd' | 'clang-format';
export type BinaryName = ArduinoBinaryName | ClangBinaryName;

export function getExecPath(binaryName: BinaryName): string {
const filename = `${binaryName}${os.platform() === 'win32' ? '.exe' : ''}`;
return join(__dirname, '..', '..', 'build', filename);
}

export function spawnCommand(
Expand All @@ -55,7 +21,7 @@ export function spawnCommand(
stdIn?: string
): Promise<string> {
return new Promise<string>((resolve, reject) => {
const cp = spawn(command, args, { windowsHide: true, shell: true });
const cp = spawn(command, args, { windowsHide: true });
const outBuffers: Buffer[] = [];
const errBuffers: Buffer[] = [];
cp.stdout.on('data', (b: Buffer) => outBuffers.push(b));
Expand Down
26 changes: 5 additions & 21 deletions arduino-ide-extension/src/node/executable-service-impl.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,19 @@
import { injectable, inject } from '@theia/core/shared/inversify';
import { ILogger } from '@theia/core/lib/common/logger';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { getExecPath } from './exec-util';
import { injectable } from '@theia/core/shared/inversify';
import { ExecutableService } from '../common/protocol/executable-service';
import { getExecPath } from './exec-util';

@injectable()
export class ExecutableServiceImpl implements ExecutableService {
@inject(ILogger)
protected logger: ILogger;

async list(): Promise<{
clangdUri: string;
cliUri: string;
lsUri: string;
fwuploaderUri: string;
}> {
const [ls, clangd, cli, fwuploader] = await Promise.all([
getExecPath('arduino-language-server', this.onError.bind(this)),
getExecPath('clangd', this.onError.bind(this), undefined),
getExecPath('arduino-cli', this.onError.bind(this)),
getExecPath('arduino-fwuploader', this.onError.bind(this)),
]);
return {
clangdUri: FileUri.create(clangd).toString(),
cliUri: FileUri.create(cli).toString(),
lsUri: FileUri.create(ls).toString(),
fwuploaderUri: FileUri.create(fwuploader).toString(),
clangdUri: FileUri.create(getExecPath('clangd')).toString(),
cliUri: FileUri.create(getExecPath('arduino-cli')).toString(),
lsUri: FileUri.create(getExecPath('arduino-language-server')).toString(),
};
}

protected onError(error: Error): void {
this.logger.error(error);
}
}
12 changes: 3 additions & 9 deletions arduino-ide-extension/src/test/node/arduino-daemon-impl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,13 @@ class SilentArduinoDaemonImpl extends ArduinoDaemonImpl {
}

private async initCliConfig(): Promise<string> {
const cliPath = await this.getExecPath();
const cliPath = this.getExecPath();
const destDir = track.mkdirSync();
await spawnCommand(`"${cliPath}"`, [
'config',
'init',
'--dest-dir',
destDir,
]);
await spawnCommand(cliPath, ['config', 'init', '--dest-dir', destDir]);
const content = fs.readFileSync(path.join(destDir, CLI_CONFIG), {
encoding: 'utf8',
});
const cliConfig = safeLoad(content) as any;
// cliConfig.daemon.port = String(this.port);
const cliConfig = safeLoad(content);
const modifiedContent = safeDump(cliConfig);
fs.writeFileSync(path.join(destDir, CLI_CONFIG), modifiedContent, {
encoding: 'utf8',
Expand Down
Loading

0 comments on commit e203c61

Please sign in to comment.