mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-17 08:16:33 +00:00
Switched from execFile
to spawn
.
So that we can add guards against whitespaces in the path. Also cleaned up the code a bit. Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
4353bfb5b9
commit
3efb5a4e08
@ -1,30 +1,11 @@
|
|||||||
import { injectable, inject } from 'inversify';
|
import { injectable, inject } from 'inversify';
|
||||||
// import { toUnix } from 'upath';
|
|
||||||
// import URI from '@theia/core/lib/common/uri';
|
|
||||||
// import { isWindows } from '@theia/core/lib/common/os';
|
|
||||||
import { LabelProvider } from '@theia/core/lib/browser';
|
import { LabelProvider } from '@theia/core/lib/browser';
|
||||||
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||||
import { ConfigService } from '../common/protocol/config-service';
|
import { ConfigService } from '../common/protocol/config-service';
|
||||||
import { SketchesService } from '../common/protocol/sketches-service';
|
import { SketchesService } from '../common/protocol/sketches-service';
|
||||||
// import { ArduinoAdvancedMode } from './arduino-frontend-contribution';
|
|
||||||
import { ArduinoWorkspaceRootResolver } from './arduino-workspace-resolver';
|
import { ArduinoWorkspaceRootResolver } from './arduino-workspace-resolver';
|
||||||
import { ArduinoAdvancedMode } from './arduino-frontend-contribution';
|
import { ArduinoAdvancedMode } from './arduino-frontend-contribution';
|
||||||
|
|
||||||
/**
|
|
||||||
* This is workaround to have custom frontend binding for the default workspace, although we
|
|
||||||
* already have a custom binding for the backend.
|
|
||||||
*
|
|
||||||
* The following logic is used for determining the default workspace location:
|
|
||||||
* - #hash exists in location?
|
|
||||||
* - Yes
|
|
||||||
* - `validateHash`. Is valid sketch location?
|
|
||||||
* - Yes
|
|
||||||
* - Done.
|
|
||||||
* - No
|
|
||||||
* - `checkHistoricalWorkspaceRoots`, `try open last modified sketch`,create new sketch`.
|
|
||||||
* - No
|
|
||||||
* - `checkHistoricalWorkspaceRoots`, `try open last modified sketch`, `create new sketch`.
|
|
||||||
*/
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class ArduinoWorkspaceService extends WorkspaceService {
|
export class ArduinoWorkspaceService extends WorkspaceService {
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { injectable, inject } from 'inversify';
|
import { injectable, inject } from 'inversify';
|
||||||
import { FileSystem } from '@theia/filesystem/lib/common';
|
import { FileSystem } from '@theia/filesystem/lib/common/filesystem';
|
||||||
import { FrontendApplication } from '@theia/core/lib/browser';
|
import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||||
|
import { FrontendApplication } from '@theia/core/lib/browser/frontend-application';
|
||||||
import { ArduinoFrontendContribution, ArduinoAdvancedMode } from '../arduino-frontend-contribution';
|
import { ArduinoFrontendContribution, ArduinoAdvancedMode } from '../arduino-frontend-contribution';
|
||||||
import { WorkspaceService } from '@theia/workspace/lib/browser';
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class ArduinoFrontendApplication extends FrontendApplication {
|
export class ArduinoFrontendApplication extends FrontendApplication {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as which from 'which';
|
import * as which from 'which';
|
||||||
import * as cp from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
import { join, delimiter } from 'path';
|
import { join, delimiter } from 'path';
|
||||||
import { injectable, inject } from 'inversify';
|
import { injectable, inject } from 'inversify';
|
||||||
import { ILogger } from '@theia/core';
|
import { ILogger } from '@theia/core';
|
||||||
@ -28,43 +28,72 @@ export class ArduinoCli {
|
|||||||
|
|
||||||
async getVersion(): Promise<string> {
|
async getVersion(): Promise<string> {
|
||||||
const execPath = await this.getExecPath();
|
const execPath = await this.getExecPath();
|
||||||
return cp.execFileSync(`${execPath}`, ['version']).toString().trim();
|
return this.spawn(`"${execPath}"`, ['version']);
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
const buffers: Buffer[] = [];
|
||||||
|
const cp = spawn(`"${execPath}"`, ['version'], { windowsHide: true, shell: true });
|
||||||
|
cp.stdout.on('data', (b: Buffer) => buffers.push(b));
|
||||||
|
cp.on('error', error => reject(error));
|
||||||
|
cp.on('exit', (code, signal) => {
|
||||||
|
if (code === 0) {
|
||||||
|
const result = Buffer.concat(buffers).toString('utf8').trim()
|
||||||
|
resolve(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (signal) {
|
||||||
|
reject(new Error(`Process exited with signal: ${signal}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (code) {
|
||||||
|
reject(new Error(`Process exited with exit code: ${code}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDefaultConfig(): Promise<Config> {
|
async getDefaultConfig(): Promise<Config> {
|
||||||
const command = await this.getExecPath();
|
const execPath = await this.getExecPath();
|
||||||
return new Promise<Config>((resolve, reject) => {
|
const result = await this.spawn(`"${execPath}"`, ['config', 'dump', '--format', 'json']);
|
||||||
cp.execFile(
|
const { sketchbook_path, arduino_data } = JSON.parse(result);
|
||||||
command,
|
if (!sketchbook_path) {
|
||||||
['config', 'dump', '--format', 'json'],
|
throw new Error(`Could not parse config. 'sketchbook_path' was missing from: ${result}`);
|
||||||
{ encoding: 'utf8' },
|
}
|
||||||
(error, stdout, stderr) => {
|
if (!arduino_data) {
|
||||||
|
throw new Error(`Could not parse config. 'arduino_data' was missing from: ${result}`);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
sketchDirUri: FileUri.create(sketchbook_path).toString(),
|
||||||
|
dataDirUri: FileUri.create(arduino_data).toString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (error) {
|
private spawn(command: string, args?: string[]): Promise<string> {
|
||||||
throw error;
|
return new Promise<string>((resolve, reject) => {
|
||||||
}
|
const buffers: Buffer[] = [];
|
||||||
|
const cp = spawn(command, args, { windowsHide: true, shell: true });
|
||||||
if (stderr) {
|
cp.stdout.on('data', (b: Buffer) => buffers.push(b));
|
||||||
throw new Error(stderr);
|
cp.on('error', error => {
|
||||||
}
|
this.logger.error(`Error executing ${command} with args: ${JSON.stringify(args)}.`, error);
|
||||||
|
reject(error);
|
||||||
const { sketchbook_path, arduino_data } = JSON.parse(stdout.trim());
|
});
|
||||||
|
cp.on('exit', (code, signal) => {
|
||||||
if (!sketchbook_path) {
|
if (code === 0) {
|
||||||
reject(new Error(`Could not parse config. 'sketchbook_path' was missing from: ${stdout}`));
|
const result = Buffer.concat(buffers).toString('utf8').trim()
|
||||||
return;
|
resolve(result);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
if (!arduino_data) {
|
if (signal) {
|
||||||
reject(new Error(`Could not parse config. 'arduino_data' was missing from: ${stdout}`));
|
this.logger.error(`Unexpected signal '${signal}' when executing ${command} with args: ${JSON.stringify(args)}.`);
|
||||||
return;
|
reject(new Error(`Process exited with signal: ${signal}`));
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
resolve({
|
if (code) {
|
||||||
sketchDirUri: FileUri.create(sketchbook_path).toString(),
|
this.logger.error(`Unexpected exit code '${code}' when executing ${command} with args: ${JSON.stringify(args)}.`);
|
||||||
dataDirUri: FileUri.create(arduino_data).toString()
|
reject(new Error(`Process exited with exit code: ${code}`));
|
||||||
});
|
return;
|
||||||
});
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ export class ArduinoDaemon implements BackendApplicationContribution {
|
|||||||
const executable = await this.cli.getExecPath();
|
const executable = await this.cli.getExecPath();
|
||||||
const version = await this.cli.getVersion();
|
const version = await this.cli.getVersion();
|
||||||
this.logger.info(`>>> Starting ${version.toLocaleLowerCase()} daemon from ${executable}...`);
|
this.logger.info(`>>> Starting ${version.toLocaleLowerCase()} daemon from ${executable}...`);
|
||||||
const daemon = exec(`${executable} daemon -v --log-level info --format json --log-format json`,
|
const daemon = exec(`"${executable}" daemon -v --log-level info --format json --log-format json`,
|
||||||
{ encoding: 'utf8', maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
|
{ encoding: 'utf8', maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => {
|
||||||
if (err || stderr) {
|
if (err || stderr) {
|
||||||
console.log(err || new Error(stderr));
|
console.log(err || new Error(stderr));
|
||||||
|
@ -191,8 +191,6 @@ export class BoardsServiceImpl implements BoardsService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async search(options: { query?: string }): Promise<{ items: BoardPackage[] }> {
|
async search(options: { query?: string }): Promise<{ items: BoardPackage[] }> {
|
||||||
const coreClient = await this.coreClientProvider.getClient();
|
const coreClient = await this.coreClientProvider.getClient();
|
||||||
if (!coreClient) {
|
if (!coreClient) {
|
||||||
|
@ -108,14 +108,8 @@ export class CoreClientProviderImpl implements CoreClientProvider {
|
|||||||
const initResp = await new Promise<InitResp>(resolve => {
|
const initResp = await new Promise<InitResp>(resolve => {
|
||||||
let resp: InitResp | undefined = undefined;
|
let resp: InitResp | undefined = undefined;
|
||||||
const stream = client.init(initReq);
|
const stream = client.init(initReq);
|
||||||
stream.on('data', (data: InitResp) => {
|
stream.on('data', (data: InitResp) => resp = data);
|
||||||
if (!resp) {
|
stream.on('end', () => resolve(resp));
|
||||||
resp = data;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
stream.on('end', () => {
|
|
||||||
resolve(resp);
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const instance = initResp.getInstance();
|
const instance = initResp.getInstance();
|
||||||
|
@ -94,7 +94,7 @@ export class SketchesServiceImpl implements SketchesService {
|
|||||||
|
|
||||||
const sketchDir = path.join(parent, sketchName)
|
const sketchDir = path.join(parent, sketchName)
|
||||||
const sketchFile = path.join(sketchDir, `${sketchName}.ino`);
|
const sketchFile = path.join(sketchDir, `${sketchName}.ino`);
|
||||||
fs.mkdirSync(sketchDir);
|
fs.mkdirpSync(sketchDir);
|
||||||
fs.writeFileSync(sketchFile, `
|
fs.writeFileSync(sketchFile, `
|
||||||
void setup() {
|
void setup() {
|
||||||
// put your setup code here, to run once:
|
// put your setup code here, to run once:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user