mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-13 22:36:32 +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 { 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 { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||
import { ConfigService } from '../common/protocol/config-service';
|
||||
import { SketchesService } from '../common/protocol/sketches-service';
|
||||
// import { ArduinoAdvancedMode } from './arduino-frontend-contribution';
|
||||
import { ArduinoWorkspaceRootResolver } from './arduino-workspace-resolver';
|
||||
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()
|
||||
export class ArduinoWorkspaceService extends WorkspaceService {
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { FileSystem } from '@theia/filesystem/lib/common';
|
||||
import { FrontendApplication } from '@theia/core/lib/browser';
|
||||
import { FileSystem } from '@theia/filesystem/lib/common/filesystem';
|
||||
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 { WorkspaceService } from '@theia/workspace/lib/browser';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoFrontendApplication extends FrontendApplication {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import * as os from 'os';
|
||||
import * as which from 'which';
|
||||
import * as cp from 'child_process';
|
||||
import { spawn } from 'child_process';
|
||||
import { join, delimiter } from 'path';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { ILogger } from '@theia/core';
|
||||
@ -28,43 +28,72 @@ export class ArduinoCli {
|
||||
|
||||
async getVersion(): Promise<string> {
|
||||
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> {
|
||||
const command = await this.getExecPath();
|
||||
return new Promise<Config>((resolve, reject) => {
|
||||
cp.execFile(
|
||||
command,
|
||||
['config', 'dump', '--format', 'json'],
|
||||
{ encoding: 'utf8' },
|
||||
(error, stdout, stderr) => {
|
||||
const execPath = await this.getExecPath();
|
||||
const result = await this.spawn(`"${execPath}"`, ['config', 'dump', '--format', 'json']);
|
||||
const { sketchbook_path, arduino_data } = JSON.parse(result);
|
||||
if (!sketchbook_path) {
|
||||
throw new Error(`Could not parse config. 'sketchbook_path' was missing from: ${result}`);
|
||||
}
|
||||
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) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (stderr) {
|
||||
throw new Error(stderr);
|
||||
}
|
||||
|
||||
const { sketchbook_path, arduino_data } = JSON.parse(stdout.trim());
|
||||
|
||||
if (!sketchbook_path) {
|
||||
reject(new Error(`Could not parse config. 'sketchbook_path' was missing from: ${stdout}`));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!arduino_data) {
|
||||
reject(new Error(`Could not parse config. 'arduino_data' was missing from: ${stdout}`));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve({
|
||||
sketchDirUri: FileUri.create(sketchbook_path).toString(),
|
||||
dataDirUri: FileUri.create(arduino_data).toString()
|
||||
});
|
||||
});
|
||||
private spawn(command: string, args?: string[]): Promise<string> {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const buffers: Buffer[] = [];
|
||||
const cp = spawn(command, args, { windowsHide: true, shell: true });
|
||||
cp.stdout.on('data', (b: Buffer) => buffers.push(b));
|
||||
cp.on('error', error => {
|
||||
this.logger.error(`Error executing ${command} with args: ${JSON.stringify(args)}.`, error);
|
||||
reject(error);
|
||||
});
|
||||
cp.on('exit', (code, signal) => {
|
||||
if (code === 0) {
|
||||
const result = Buffer.concat(buffers).toString('utf8').trim()
|
||||
resolve(result);
|
||||
return;
|
||||
}
|
||||
if (signal) {
|
||||
this.logger.error(`Unexpected signal '${signal}' when executing ${command} with args: ${JSON.stringify(args)}.`);
|
||||
reject(new Error(`Process exited with signal: ${signal}`));
|
||||
return;
|
||||
}
|
||||
if (code) {
|
||||
this.logger.error(`Unexpected exit code '${code}' when executing ${command} with args: ${JSON.stringify(args)}.`);
|
||||
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 version = await this.cli.getVersion();
|
||||
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) => {
|
||||
if (err || stderr) {
|
||||
console.log(err || new Error(stderr));
|
||||
|
@ -191,8 +191,6 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
async search(options: { query?: string }): Promise<{ items: BoardPackage[] }> {
|
||||
const coreClient = await this.coreClientProvider.getClient();
|
||||
if (!coreClient) {
|
||||
|
@ -108,14 +108,8 @@ export class CoreClientProviderImpl implements CoreClientProvider {
|
||||
const initResp = await new Promise<InitResp>(resolve => {
|
||||
let resp: InitResp | undefined = undefined;
|
||||
const stream = client.init(initReq);
|
||||
stream.on('data', (data: InitResp) => {
|
||||
if (!resp) {
|
||||
resp = data;
|
||||
}
|
||||
})
|
||||
stream.on('end', () => {
|
||||
resolve(resp);
|
||||
})
|
||||
stream.on('data', (data: InitResp) => resp = data);
|
||||
stream.on('end', () => resolve(resp));
|
||||
});
|
||||
|
||||
const instance = initResp.getInstance();
|
||||
|
@ -94,7 +94,7 @@ export class SketchesServiceImpl implements SketchesService {
|
||||
|
||||
const sketchDir = path.join(parent, sketchName)
|
||||
const sketchFile = path.join(sketchDir, `${sketchName}.ino`);
|
||||
fs.mkdirSync(sketchDir);
|
||||
fs.mkdirpSync(sketchDir);
|
||||
fs.writeFileSync(sketchFile, `
|
||||
void setup() {
|
||||
// put your setup code here, to run once:
|
||||
|
Loading…
x
Reference in New Issue
Block a user