From bfb0edf50cc7c3798949372459597da776789485 Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Wed, 8 May 2019 12:10:29 +0200 Subject: [PATCH] Guard against no workspaces root. Signed-off-by: Akos Kitta --- .../src/browser/workspace-service-ext-impl.ts | 30 ++++++++++++++- .../src/browser/workspace-service-ext.ts | 7 ++++ .../src/node/boards-service-impl.ts | 20 ++++++++-- .../src/node/core-client-provider-impl.ts | 38 +++++++++++++++---- .../src/node/core-client-provider.ts | 2 +- .../src/node/core-service-impl.ts | 12 +++++- .../src/node/library-service-impl.ts | 6 ++- 7 files changed, 98 insertions(+), 17 deletions(-) diff --git a/arduino-ide-extension/src/browser/workspace-service-ext-impl.ts b/arduino-ide-extension/src/browser/workspace-service-ext-impl.ts index 444317c0..3c036ad2 100644 --- a/arduino-ide-extension/src/browser/workspace-service-ext-impl.ts +++ b/arduino-ide-extension/src/browser/workspace-service-ext-impl.ts @@ -1,4 +1,6 @@ import { inject, injectable } from 'inversify'; +import URI from '@theia/core/lib/common/uri'; +import { FileSystem } from '@theia/filesystem/lib/common'; import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service'; import { WorkspaceServiceExt } from './workspace-service-ext'; @@ -8,6 +10,9 @@ import { WorkspaceServiceExt } from './workspace-service-ext'; @injectable() export class WorkspaceServiceExtImpl implements WorkspaceServiceExt { + @inject(FileSystem) + protected readonly fileSystem: FileSystem; + @inject(WorkspaceService) protected readonly delegate: WorkspaceService; @@ -16,4 +21,27 @@ export class WorkspaceServiceExtImpl implements WorkspaceServiceExt { return stats.map(stat => stat.uri); } -} \ No newline at end of file + async defaultWorkspaceUri(): Promise { + const home = await this.fileSystem.getCurrentUserHome(); + if (home) { + return new URI(home.uri).resolve('Arduino-PoC').resolve('workspace').toString(); + } + throw new Error(`Could not locate current user's home folder.`); + } + + async defaultDownloadsDirUri(): Promise { + const home = await this.fileSystem.getCurrentUserHome(); + if (home) { + return new URI(home.uri).resolve('Arduino-PoC').resolve('downloads').toString(); + } + throw new Error(`Could not locate current user's home folder.`); + } + + async defaultDataDirUri(): Promise { + const home = await this.fileSystem.getCurrentUserHome(); + if (home) { + return new URI(home.uri).resolve('Arduino-PoC').resolve('data').toString(); + } + throw new Error(`Could not locate current user's home folder.`); + } +} diff --git a/arduino-ide-extension/src/browser/workspace-service-ext.ts b/arduino-ide-extension/src/browser/workspace-service-ext.ts index 8d77fbac..82c46208 100644 --- a/arduino-ide-extension/src/browser/workspace-service-ext.ts +++ b/arduino-ide-extension/src/browser/workspace-service-ext.ts @@ -2,4 +2,11 @@ export const WorkspaceServiceExtPath = '/services/workspace-service-ext'; export const WorkspaceServiceExt = Symbol('WorkspaceServiceExt'); export interface WorkspaceServiceExt { roots(): Promise; + /** + * By default it is under `~/Arduino-PoC/workspace`. + * It might not exist yet. + */ + defaultWorkspaceUri(): Promise; + defaultDownloadsDirUri(): Promise; + defaultDataDirUri(): Promise; } diff --git a/arduino-ide-extension/src/node/boards-service-impl.ts b/arduino-ide-extension/src/node/boards-service-impl.ts index cb46bb40..18b6c1b0 100644 --- a/arduino-ide-extension/src/node/boards-service-impl.ts +++ b/arduino-ide-extension/src/node/boards-service-impl.ts @@ -17,7 +17,11 @@ export class BoardsServiceImpl implements BoardsService { protected selectedBoard: Board | undefined; public async getAttachedBoards(): Promise<{ boards: Board[] }> { - const { client, instance } = await this.coreClientProvider.getClient(); + const coreClient = await this.coreClientProvider.getClient(); + if (!coreClient) { + return { boards: [] }; + } + const { client, instance } = coreClient; const req = new BoardListReq(); req.setInstance(instance); @@ -51,12 +55,16 @@ export class BoardsServiceImpl implements BoardsService { } async search(options: { query?: string }): Promise<{ items: BoardPackage[] }> { - const { client, instance } = await this.coreClientProvider.getClient(); + const coreClient = await this.coreClientProvider.getClient(); + if (!coreClient) { + return { items: [] }; + } + const { client, instance } = coreClient; const installedPlatformsReq = new PlatformListReq(); installedPlatformsReq.setInstance(instance); const installedPlatformsResp = await new Promise((resolve, reject) => - client.platformList(installedPlatformsReq, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp)) + client.platformList(installedPlatformsReq, (err, resp) => (!!err ? reject : resolve)(!!err ? err : resp)) ); const installedPlatforms = installedPlatformsResp.getInstalledPlatformList(); @@ -90,7 +98,11 @@ export class BoardsServiceImpl implements BoardsService { } async install(pkg: BoardPackage): Promise { - const { client, instance } = await this.coreClientProvider.getClient(); + const coreClient = await this.coreClientProvider.getClient(); + if (!coreClient) { + return; + } + const { client, instance } = coreClient; const [ platform, boardName ] = pkg.id.split(":"); diff --git a/arduino-ide-extension/src/node/core-client-provider-impl.ts b/arduino-ide-extension/src/node/core-client-provider-impl.ts index 880dbb27..45b7f5fb 100644 --- a/arduino-ide-extension/src/node/core-client-provider-impl.ts +++ b/arduino-ide-extension/src/node/core-client-provider-impl.ts @@ -9,10 +9,12 @@ import { CoreClientProvider, Client } from './core-client-provider'; import * as PQueue from 'p-queue'; import { ToolOutputServiceServer } from '../common/protocol/tool-output-service'; import { Instance } from './cli-protocol/common_pb'; +import * as fs from 'fs-extra'; @injectable() export class CoreClientProviderImpl implements CoreClientProvider { + protected clients = new Map(); protected readonly clientRequestQueue = new PQueue({ autoStart: true, concurrency: 1 }); @inject(FileSystem) @@ -24,10 +26,8 @@ export class CoreClientProviderImpl implements CoreClientProvider { @inject(ToolOutputServiceServer) protected readonly toolOutputService: ToolOutputServiceServer; - protected clients = new Map(); - - async getClient(workspaceRootOrResourceUri?: string): Promise { - return this.clientRequestQueue.add(() => new Promise(async resolve => { + async getClient(workspaceRootOrResourceUri?: string): Promise { + return this.clientRequestQueue.add(() => new Promise(async resolve => { const roots = await this.workspaceServiceExt.roots(); if (!workspaceRootOrResourceUri) { resolve(this.getOrCreateClient(roots[0])); @@ -47,7 +47,10 @@ export class CoreClientProviderImpl implements CoreClientProvider { })); } - protected async getOrCreateClient(rootUri: string): Promise { + protected async getOrCreateClient(rootUri: string | undefined): Promise { + if (!rootUri) { + return undefined; + } const existing = this.clients.get(rootUri); if (existing) { console.debug(`Reusing existing client for ${rootUri}.`); @@ -60,11 +63,30 @@ export class CoreClientProviderImpl implements CoreClientProvider { const config = new Configuration(); const rootPath = await this.fileSystem.getFsPath(rootUri); if (!rootPath) { - throw new Error(`Could not resolve file-system path of URI: ${rootUri}.`); + throw new Error(`Could not resolve filesystem path of URI: ${rootUri}.`); } + + const defaultDownloadsDirUri = await this.workspaceServiceExt.defaultDownloadsDirUri(); + const defaultDownloadsDirPath = await this.fileSystem.getFsPath(defaultDownloadsDirUri); + if (!defaultDownloadsDirPath) { + throw new Error(`Could not resolve filesystem path of URI: ${defaultDownloadsDirUri}.`); + } + if (!fs.existsSync(defaultDownloadsDirPath)) { + fs.mkdirpSync(defaultDownloadsDirPath); + } + + const defaultDataDirUri = await this.workspaceServiceExt.defaultDataDirUri(); + const defaultDataDirPath = await this.fileSystem.getFsPath(defaultDataDirUri); + if (!defaultDataDirPath) { + throw new Error(`Could not resolve filesystem path of URI: ${defaultDataDirUri}.`); + } + if (!fs.existsSync(defaultDataDirPath)) { + fs.mkdirpSync(defaultDataDirPath); + } + config.setSketchbookdir(rootPath); - config.setDatadir(rootPath); - config.setDownloadsdir(rootPath); + config.setDatadir(defaultDataDirPath); + config.setDownloadsdir(defaultDownloadsDirPath); const initReq = new InitReq(); initReq.setConfiguration(config); diff --git a/arduino-ide-extension/src/node/core-client-provider.ts b/arduino-ide-extension/src/node/core-client-provider.ts index bc3831f9..44bd54cb 100644 --- a/arduino-ide-extension/src/node/core-client-provider.ts +++ b/arduino-ide-extension/src/node/core-client-provider.ts @@ -4,7 +4,7 @@ import { ArduinoCoreClient } from './cli-protocol/commands_grpc_pb'; export const CoreClientProviderPath = '/services/core-client-provider'; export const CoreClientProvider = Symbol('CoreClientProvider'); export interface CoreClientProvider { - getClient(workspaceRootOrResourceUri?: string): Promise; + getClient(workspaceRootOrResourceUri?: string): Promise; } export interface Client { diff --git a/arduino-ide-extension/src/node/core-service-impl.ts b/arduino-ide-extension/src/node/core-service-impl.ts index f6d7fd58..2f014ca6 100644 --- a/arduino-ide-extension/src/node/core-service-impl.ts +++ b/arduino-ide-extension/src/node/core-service-impl.ts @@ -32,7 +32,11 @@ export class CoreServiceImpl implements CoreService { } const sketchpath = path.dirname(sketchFilePath); - const { client, instance } = await this.coreClientProvider.getClient(uri); + const coreClient = await this.coreClientProvider.getClient(uri); + if (!coreClient) { + return; + } + const { client, instance } = coreClient; const currentBoard = await this.boardsService.getSelectBoard(); if (!currentBoard) { @@ -86,7 +90,11 @@ export class CoreServiceImpl implements CoreService { throw new Error(`selected board (${currentBoard.name}) has no FQBN`); } - const { client, instance } = await this.coreClientProvider.getClient(uri); + const coreClient = await this.coreClientProvider.getClient(uri); + if (!coreClient) { + return; + } + const { client, instance } = coreClient; const req = new UploadReq(); req.setInstance(instance); diff --git a/arduino-ide-extension/src/node/library-service-impl.ts b/arduino-ide-extension/src/node/library-service-impl.ts index b23677b7..17c0b921 100644 --- a/arduino-ide-extension/src/node/library-service-impl.ts +++ b/arduino-ide-extension/src/node/library-service-impl.ts @@ -15,7 +15,11 @@ export class LibraryServiceImpl implements LibraryService { protected readonly toolOutputService: ToolOutputServiceServer; async search(options: { query?: string; }): Promise<{ items: Library[] }> { - const { client, instance } = await this.coreClientProvider.getClient(); + const coreClient = await this.coreClientProvider.getClient(); + if (!coreClient) { + return { items: [] }; + } + const { client, instance } = coreClient; const listReq = new LibraryListReq(); listReq.setInstance(instance);