import { inject, injectable } from 'inversify'; import * as remote from '@theia/core/electron-shared/@electron/remote'; import URI from '@theia/core/lib/common/uri'; import { ConfirmDialog } from '@theia/core/lib/browser/dialogs'; import { EnvVariablesServer } from '@theia/core/lib/common/env-variables'; import { ArduinoMenus } from '../menu/arduino-menus'; import { Installable, LibraryService, ResponseServiceArduino, } from '../../common/protocol'; import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, } from './contribution'; import { nls } from '@theia/core/lib/common'; @injectable() export class AddZipLibrary extends SketchContribution { @inject(EnvVariablesServer) protected readonly envVariableServer: EnvVariablesServer; @inject(ResponseServiceArduino) protected readonly responseService: ResponseServiceArduino; @inject(LibraryService) protected readonly libraryService: LibraryService; registerCommands(registry: CommandRegistry): void { registry.registerCommand(AddZipLibrary.Commands.ADD_ZIP_LIBRARY, { execute: () => this.addZipLibrary(), }); } registerMenus(registry: MenuModelRegistry): void { const includeLibMenuPath = [ ...ArduinoMenus.SKETCH__UTILS_GROUP, '0_include', ]; registry.registerMenuAction([...includeLibMenuPath, '1_install'], { commandId: AddZipLibrary.Commands.ADD_ZIP_LIBRARY.id, label: nls.localize('arduino/library/addZip', 'Add .ZIP Library...'), order: '1', }); } async addZipLibrary(): Promise<void> { const homeUri = await this.envVariableServer.getHomeDirUri(); const defaultPath = await this.fileService.fsPath(new URI(homeUri)); const { canceled, filePaths } = await remote.dialog.showOpenDialog({ title: nls.localize( 'arduino/selectZip', "Select a zip file containing the library you'd like to add" ), defaultPath, properties: ['openFile'], filters: [ { name: nls.localize('arduino/library/zipLibrary', 'Library'), extensions: ['zip'], }, ], }); if (!canceled && filePaths.length) { const zipUri = await this.fileSystemExt.getUri(filePaths[0]); try { await this.doInstall(zipUri); } catch (error) { if (error instanceof AlreadyInstalledError) { const result = await new ConfirmDialog({ msg: error.message, title: nls.localize( 'arduino/library/overwriteExistingLibrary', 'Do you want to overwrite the existing library?' ), ok: nls.localize('vscode/extensionsUtils/yes', 'Yes'), cancel: nls.localize('vscode/extensionsUtils/no', 'No'), }).open(); if (result) { await this.doInstall(zipUri, true); } } } } } private async doInstall(zipUri: string, overwrite?: boolean): Promise<void> { try { await Installable.doWithProgress({ messageService: this.messageService, progressText: nls.localize('arduino/common/processing', 'Processing') + ` ${new URI(zipUri).path.base}`, responseService: this.responseService, run: () => this.libraryService.installZip({ zipUri, overwrite }), }); this.messageService.info( nls.localize( 'arduino/library/successfullyInstalledZipLibrary', 'Successfully installed library from {0} archive', new URI(zipUri).path.base ), { timeout: 3000 } ); } catch (error) { if (error instanceof Error) { const match = error.message.match(/library (.*?) already installed/); if (match && match.length >= 2) { const name = match[1].trim(); if (name) { throw new AlreadyInstalledError( nls.localize( 'arduino/library/namedLibraryAlreadyExists', 'A library folder named {0} already exists. Do you want to overwrite it?', name ), name ); } else { throw new AlreadyInstalledError( nls.localize( 'arduino/library/libraryAlreadyExists', 'A library already exists. Do you want to overwrite it?' ) ); } } } this.messageService.error(error.toString()); throw error; } } } class AlreadyInstalledError extends Error { constructor(message: string, readonly libraryName?: string) { super(message); Object.setPrototypeOf(this, AlreadyInstalledError.prototype); } } export namespace AddZipLibrary { export namespace Commands { export const ADD_ZIP_LIBRARY: Command = { id: 'arduino-add-zip-library', }; } }