mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-11-10 18:59:28 +00:00
More robust workspace initialization: guard against errors creating sketch dir
This commit is contained in:
@@ -71,7 +71,7 @@ export class ArduinoDaemon implements BackendApplicationContribution {
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
this.isReady.resolve();
|
||||
if (!this.cliContribution.debugCli) {
|
||||
this.logger.info(`<<< The 'arduino-cli' daemon is up an running.`);
|
||||
this.logger.info(`<<< The 'arduino-cli' daemon is up and running.`);
|
||||
} else {
|
||||
this.logger.info(`Assuming the 'arduino-cli' already runs in debug mode.`);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mkdirpSync, existsSync } from 'fs-extra';
|
||||
import * as fs from './fs-extra';
|
||||
import { injectable, inject, postConstruct } from 'inversify';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||
@@ -14,32 +14,35 @@ export class ConfigServiceImpl implements ConfigService {
|
||||
protected readonly config: Deferred<Config> = new Deferred();
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.cli.getDefaultConfig().then(config => {
|
||||
protected async init(): Promise<void> {
|
||||
try {
|
||||
const config = await this.cli.getDefaultConfig();
|
||||
const { dataDirUri, sketchDirUri } = config;
|
||||
for (const uri of [dataDirUri, sketchDirUri]) {
|
||||
const path = FileUri.fsPath(uri);
|
||||
if (!existsSync(path)) {
|
||||
mkdirpSync(path);
|
||||
if (!fs.existsSync(path)) {
|
||||
await fs.mkdirp(path);
|
||||
}
|
||||
}
|
||||
this.config.resolve(config);
|
||||
});
|
||||
} catch (err) {
|
||||
this.config.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
async getConfiguration(): Promise<Config> {
|
||||
getConfiguration(): Promise<Config> {
|
||||
return this.config.promise;
|
||||
}
|
||||
|
||||
async getVersion(): Promise<string> {
|
||||
getVersion(): Promise<string> {
|
||||
return this.cli.getVersion();
|
||||
}
|
||||
|
||||
async isInDataDir(uri: string): Promise<boolean> {
|
||||
isInDataDir(uri: string): Promise<boolean> {
|
||||
return this.getConfiguration().then(({ dataDirUri }) => new URI(dataDirUri).isEqualOrParent(new URI(uri)));
|
||||
}
|
||||
|
||||
async isInSketchDir(uri: string): Promise<boolean> {
|
||||
isInSketchDir(uri: string): Promise<boolean> {
|
||||
return this.getConfiguration().then(({ sketchDirUri }) => new URI(sketchDirUri).isEqualOrParent(new URI(uri)));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { ILogger } from '@theia/core';
|
||||
import { DefaultWorkspaceServer } from '@theia/workspace/lib/node/default-workspace-server';
|
||||
import { ConfigService } from '../common/protocol/config-service';
|
||||
|
||||
@injectable()
|
||||
export class DefaultWorkspaceServerExt extends DefaultWorkspaceServer {
|
||||
|
||||
@inject(ConfigService) protected readonly configService: ConfigService;
|
||||
@inject(ConfigService)
|
||||
protected readonly configService: ConfigService;
|
||||
|
||||
@inject(ILogger)
|
||||
protected readonly logger: ILogger;
|
||||
|
||||
protected async getWorkspaceURIFromCli(): Promise<string | undefined> {
|
||||
const config = await this.configService.getConfiguration();
|
||||
return config.sketchDirUri;
|
||||
try {
|
||||
const config = await this.configService.getConfiguration();
|
||||
return config.sketchDirUri;
|
||||
} catch (err) {
|
||||
this.logger.error(`Failed to determine the sketch directory: ${err}`);
|
||||
return super.getWorkspaceURIFromCli();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
36
arduino-ide-extension/src/node/fs-extra.ts
Normal file
36
arduino-ide-extension/src/node/fs-extra.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import * as fs from 'fs';
|
||||
import { promisify } from 'util';
|
||||
|
||||
export const existsSync = fs.existsSync;
|
||||
export const lstatSync = fs.lstatSync;
|
||||
export const readdirSync = fs.readdirSync;
|
||||
export const statSync = fs.statSync;
|
||||
export const writeFileSync = fs.writeFileSync;
|
||||
|
||||
export const exists = promisify(fs.exists);
|
||||
export const lstat = promisify(fs.lstat);
|
||||
export const readdir = promisify(fs.readdir);
|
||||
export const stat = promisify(fs.stat);
|
||||
export const writeFile = promisify(fs.writeFile);
|
||||
|
||||
export function mkdirp(path: string, timeout: number = 3000): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let timeoutHandle: NodeJS.Timeout;
|
||||
if (timeout > 0) {
|
||||
timeoutHandle = setTimeout(() => {
|
||||
reject(new Error(`Timeout of ${timeout} ms exceeded while trying to create the directory "${path}"`));
|
||||
}, timeout);
|
||||
}
|
||||
fs.mkdir(path, { recursive: true }, err => {
|
||||
clearTimeout(timeoutHandle);
|
||||
if (err)
|
||||
reject(err);
|
||||
else
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function mkdirpSync(path: string): void {
|
||||
fs.mkdirSync(path, { recursive: true });
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as fs from './fs-extra';
|
||||
import { FileUri } from '@theia/core/lib/node';
|
||||
import { ConfigService } from '../common/protocol/config-service';
|
||||
import { SketchesService, Sketch } from '../common/protocol/sketches-service';
|
||||
@@ -18,7 +18,7 @@ export class SketchesServiceImpl implements SketchesService {
|
||||
const sketches: Array<Sketch & { mtimeMs: number }> = [];
|
||||
let fsPath: undefined | string;
|
||||
if (!uri) {
|
||||
const { sketchDirUri } = (await this.configService.getConfiguration());
|
||||
const { sketchDirUri } = await this.configService.getConfiguration();
|
||||
fsPath = FileUri.fsPath(sketchDirUri);
|
||||
if (!fs.existsSync(fsPath)) {
|
||||
await fs.mkdirp(fsPath);
|
||||
@@ -29,11 +29,11 @@ export class SketchesServiceImpl implements SketchesService {
|
||||
if (!fs.existsSync(fsPath)) {
|
||||
return [];
|
||||
}
|
||||
const fileNames = fs.readdirSync(fsPath);
|
||||
const fileNames = await fs.readdir(fsPath);
|
||||
for (const fileName of fileNames) {
|
||||
const filePath = path.join(fsPath, fileName);
|
||||
if (await this.isSketchFolder(FileUri.create(filePath).toString())) {
|
||||
const stat = fs.statSync(filePath);
|
||||
const stat = await fs.stat(filePath);
|
||||
sketches.push({
|
||||
mtimeMs: stat.mtimeMs,
|
||||
name: fileName,
|
||||
@@ -51,10 +51,9 @@ export class SketchesServiceImpl implements SketchesService {
|
||||
async getSketchFiles(uri: string): Promise<string[]> {
|
||||
const uris: string[] = [];
|
||||
const fsPath = FileUri.fsPath(uri);
|
||||
const stats = fs.lstatSync(fsPath);
|
||||
if (stats.isDirectory) {
|
||||
if (fs.lstatSync(fsPath).isDirectory()) {
|
||||
if (await this.isSketchFolder(uri)) {
|
||||
const fileNames = fs.readdirSync(fsPath);
|
||||
const fileNames = await fs.readdir(fsPath);
|
||||
for (const fileName of fileNames) {
|
||||
const filePath = path.join(fsPath, fileName);
|
||||
if (ALLOWED_FILE_EXTENSIONS.indexOf(path.extname(filePath)) !== -1
|
||||
@@ -116,26 +115,13 @@ void loop() {
|
||||
|
||||
async isSketchFolder(uri: string): Promise<boolean> {
|
||||
const fsPath = FileUri.fsPath(uri);
|
||||
const exists = await fs.pathExists(fsPath);
|
||||
if (exists) {
|
||||
const stats = await fs.lstat(fsPath);
|
||||
if (stats.isDirectory()) {
|
||||
const basename = path.basename(fsPath);
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
fs.readdir(fsPath, (error, files) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
if (files[i] === basename + '.ino') {
|
||||
resolve(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
resolve(false);
|
||||
});
|
||||
})
|
||||
if (fs.existsSync(fsPath) && fs.lstatSync(fsPath).isDirectory()) {
|
||||
const basename = path.basename(fsPath);
|
||||
const files = await fs.readdir(fsPath);
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
if (files[i] === basename + '.ino') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user