mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-06-07 12:46:34 +00:00
ATL-983: Propose installing the required libs.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
0aef4b328f
commit
057904d38d
@ -124,7 +124,11 @@
|
|||||||
],
|
],
|
||||||
"arduino": {
|
"arduino": {
|
||||||
"cli": {
|
"cli": {
|
||||||
"version": "0.16.0"
|
"version": {
|
||||||
|
"owner": "arduino",
|
||||||
|
"repo": "arduino-cli",
|
||||||
|
"commitish": "scerza/lib-install-deps"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
import { injectable, postConstruct, inject } from 'inversify';
|
import { injectable, postConstruct, inject } from 'inversify';
|
||||||
|
import { Message } from '@phosphor/messaging';
|
||||||
|
import { addEventListener } from '@theia/core/lib/browser/widgets/widget';
|
||||||
|
import { AbstractDialog, DialogProps } from '@theia/core/lib/browser/dialogs';
|
||||||
import { LibraryPackage, LibraryService } from '../../common/protocol/library-service';
|
import { LibraryPackage, LibraryService } from '../../common/protocol/library-service';
|
||||||
import { ListWidget } from '../widgets/component-list/list-widget';
|
import { ListWidget } from '../widgets/component-list/list-widget';
|
||||||
|
import { Installable } from '../../common/protocol';
|
||||||
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
|
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
@ -33,4 +37,110 @@ export class LibraryListWidget extends ListWidget<LibraryPackage> {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async install({ item, version }: { item: LibraryPackage, version: Installable.Version }): Promise<void> {
|
||||||
|
const dependencies = await this.service.listDependencies({ item, version, filterSelf: true });
|
||||||
|
let installDependencies: boolean | undefined = undefined;
|
||||||
|
if (dependencies.length) {
|
||||||
|
const message = document.createElement('div');
|
||||||
|
message.innerHTML = `The library <b>${item.name}:${version}</b> needs ${dependencies.length === 1 ? 'another dependency' : 'some other dependencies'} currently not installed:`;
|
||||||
|
const listContainer = document.createElement('div');
|
||||||
|
listContainer.style.maxHeight = '300px';
|
||||||
|
listContainer.style.overflowY = 'auto';
|
||||||
|
const list = document.createElement('ul');
|
||||||
|
list.style.listStyleType = 'none';
|
||||||
|
for (const { name } of dependencies) {
|
||||||
|
const listItem = document.createElement('li');
|
||||||
|
listItem.textContent = ` - ${name}`;
|
||||||
|
listItem.style.fontWeight = 'bold';
|
||||||
|
list.appendChild(listItem);
|
||||||
|
}
|
||||||
|
listContainer.appendChild(list);
|
||||||
|
message.appendChild(listContainer);
|
||||||
|
const question = document.createElement('div');
|
||||||
|
question.textContent = `Would you like to install ${dependencies.length === 1 ? 'the missing dependency' : 'all the missing dependencies'}?`;
|
||||||
|
message.appendChild(question);
|
||||||
|
const result = await new MessageBoxDialog({
|
||||||
|
title: `Dependencies for library ${item.name}:${version}`,
|
||||||
|
message,
|
||||||
|
buttons: [
|
||||||
|
'Install all',
|
||||||
|
`Install ${item.name} only`,
|
||||||
|
'Cancel'
|
||||||
|
],
|
||||||
|
maxWidth: 740 // Aligned with `settings-dialog.css`.
|
||||||
|
}).open();
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
const { response } = result;
|
||||||
|
if (response === 0) { // All
|
||||||
|
installDependencies = true;
|
||||||
|
} else if (response === 1) { // Current only
|
||||||
|
installDependencies = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof installDependencies === 'boolean') {
|
||||||
|
return this.service.install({ item, version, installDependencies });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageBoxDialog extends AbstractDialog<MessageBoxDialog.Result> {
|
||||||
|
|
||||||
|
protected response: number;
|
||||||
|
|
||||||
|
constructor(protected readonly options: MessageBoxDialog.Options) {
|
||||||
|
super(options);
|
||||||
|
this.contentNode.appendChild(this.createMessageNode(this.options.message));
|
||||||
|
(options.buttons || ['OK']).forEach((text, index) => {
|
||||||
|
const button = this.createButton(text);
|
||||||
|
button.classList.add(index === 0 ? 'main' : 'secondary');
|
||||||
|
this.controlPanel.appendChild(button);
|
||||||
|
this.toDisposeOnDetach.push(addEventListener(button, 'click', () => {
|
||||||
|
this.response = index;
|
||||||
|
this.accept();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onCloseRequest(message: Message): void {
|
||||||
|
super.onCloseRequest(message);
|
||||||
|
this.accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
get value(): MessageBoxDialog.Result {
|
||||||
|
return { response: this.response };
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createMessageNode(message: string | HTMLElement): HTMLElement {
|
||||||
|
if (typeof message === 'string') {
|
||||||
|
const messageNode = document.createElement('div');
|
||||||
|
messageNode.textContent = message;
|
||||||
|
return messageNode;
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected handleEnter(event: KeyboardEvent): boolean | void {
|
||||||
|
this.response = 0;
|
||||||
|
super.handleEnter(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export namespace MessageBoxDialog {
|
||||||
|
export interface Options extends DialogProps {
|
||||||
|
/**
|
||||||
|
* When empty, `['OK']` will be inferred.
|
||||||
|
*/
|
||||||
|
buttons?: string[];
|
||||||
|
message: string | HTMLElement;
|
||||||
|
}
|
||||||
|
export interface Result {
|
||||||
|
/**
|
||||||
|
* The index of `buttons` that was clicked.
|
||||||
|
*/
|
||||||
|
readonly response: number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,11 +81,11 @@ export class FilterableListContainer<T extends ArduinoComponent> extends React.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async install(item: T, version: Installable.Version): Promise<void> {
|
protected async install(item: T, version: Installable.Version): Promise<void> {
|
||||||
const { installable, searchable, itemLabel } = this.props;
|
const { install, searchable, itemLabel } = this.props;
|
||||||
const dialog = new InstallationProgressDialog(itemLabel(item), version);
|
const dialog = new InstallationProgressDialog(itemLabel(item), version);
|
||||||
dialog.open();
|
|
||||||
try {
|
try {
|
||||||
await installable.install({ item, version });
|
dialog.open();
|
||||||
|
await install({ item, version });
|
||||||
const items = await searchable.search({ query: this.state.filterText });
|
const items = await searchable.search({ query: this.state.filterText });
|
||||||
this.setState({ items: this.sort(items) });
|
this.setState({ items: this.sort(items) });
|
||||||
} finally {
|
} finally {
|
||||||
@ -94,20 +94,20 @@ export class FilterableListContainer<T extends ArduinoComponent> extends React.C
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected async uninstall(item: T): Promise<void> {
|
protected async uninstall(item: T): Promise<void> {
|
||||||
const uninstall = await new ConfirmDialog({
|
const ok = await new ConfirmDialog({
|
||||||
title: 'Uninstall',
|
title: 'Uninstall',
|
||||||
msg: `Do you want to uninstall ${item.name}?`,
|
msg: `Do you want to uninstall ${item.name}?`,
|
||||||
ok: 'Yes',
|
ok: 'Yes',
|
||||||
cancel: 'No'
|
cancel: 'No'
|
||||||
}).open();
|
}).open();
|
||||||
if (!uninstall) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { installable, searchable, itemLabel } = this.props;
|
const { uninstall, searchable, itemLabel } = this.props;
|
||||||
const dialog = new UninstallationProgressDialog(itemLabel(item));
|
const dialog = new UninstallationProgressDialog(itemLabel(item));
|
||||||
dialog.open();
|
|
||||||
try {
|
try {
|
||||||
await installable.uninstall({ item });
|
dialog.open();
|
||||||
|
await uninstall({ item });
|
||||||
const items = await searchable.search({ query: this.state.filterText });
|
const items = await searchable.search({ query: this.state.filterText });
|
||||||
this.setState({ items: this.sort(items) });
|
this.setState({ items: this.sort(items) });
|
||||||
} finally {
|
} finally {
|
||||||
@ -121,13 +121,14 @@ export namespace FilterableListContainer {
|
|||||||
|
|
||||||
export interface Props<T extends ArduinoComponent> {
|
export interface Props<T extends ArduinoComponent> {
|
||||||
readonly container: ListWidget<T>;
|
readonly container: ListWidget<T>;
|
||||||
readonly installable: Installable<T>;
|
|
||||||
readonly searchable: Searchable<T>;
|
readonly searchable: Searchable<T>;
|
||||||
readonly itemLabel: (item: T) => string;
|
readonly itemLabel: (item: T) => string;
|
||||||
readonly itemRenderer: ListItemRenderer<T>;
|
readonly itemRenderer: ListItemRenderer<T>;
|
||||||
readonly resolveContainer: (element: HTMLElement) => void;
|
readonly resolveContainer: (element: HTMLElement) => void;
|
||||||
readonly resolveFocus: (element: HTMLElement | undefined) => void;
|
readonly resolveFocus: (element: HTMLElement | undefined) => void;
|
||||||
readonly filterTextChangeEvent: Event<string | undefined>;
|
readonly filterTextChangeEvent: Event<string | undefined>;
|
||||||
|
readonly install: ({ item, version }: { item: T, version: Installable.Version }) => Promise<void>;
|
||||||
|
readonly uninstall: ({ item }: { item: T }) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface State<T> {
|
export interface State<T> {
|
||||||
|
@ -67,6 +67,14 @@ export abstract class ListWidget<T extends ArduinoComponent> extends ReactWidget
|
|||||||
|
|
||||||
protected onFocusResolved = (element: HTMLElement | undefined) => {
|
protected onFocusResolved = (element: HTMLElement | undefined) => {
|
||||||
this.focusNode = element;
|
this.focusNode = element;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected async install({ item, version }: { item: T, version: Installable.Version }): Promise<void> {
|
||||||
|
return this.options.installable.install({ item, version });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async uninstall({ item }: { item: T }): Promise<void> {
|
||||||
|
return this.options.installable.uninstall({ item });
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): React.ReactNode {
|
render(): React.ReactNode {
|
||||||
@ -75,7 +83,8 @@ export abstract class ListWidget<T extends ArduinoComponent> extends ReactWidget
|
|||||||
resolveContainer={this.deferredContainer.resolve}
|
resolveContainer={this.deferredContainer.resolve}
|
||||||
resolveFocus={this.onFocusResolved}
|
resolveFocus={this.onFocusResolved}
|
||||||
searchable={this.options.searchable}
|
searchable={this.options.searchable}
|
||||||
installable={this.options.installable}
|
install={this.install.bind(this)}
|
||||||
|
uninstall={this.uninstall.bind(this)}
|
||||||
itemLabel={this.options.itemLabel}
|
itemLabel={this.options.itemLabel}
|
||||||
itemRenderer={this.options.itemRenderer}
|
itemRenderer={this.options.itemRenderer}
|
||||||
filterTextChangeEvent={this.filterTextChangeEmitter.event} />;
|
filterTextChangeEvent={this.filterTextChangeEmitter.event} />;
|
||||||
|
@ -6,6 +6,15 @@ export const LibraryServicePath = '/services/library-service';
|
|||||||
export const LibraryService = Symbol('LibraryService');
|
export const LibraryService = Symbol('LibraryService');
|
||||||
export interface LibraryService extends Installable<LibraryPackage>, Searchable<LibraryPackage> {
|
export interface LibraryService extends Installable<LibraryPackage>, Searchable<LibraryPackage> {
|
||||||
list(options: LibraryService.List.Options): Promise<LibraryPackage[]>;
|
list(options: LibraryService.List.Options): Promise<LibraryPackage[]>;
|
||||||
|
/**
|
||||||
|
* When `installDependencies` is not set, it is `true` by default. If you want to skip the installation of required dependencies, set it to `false`.
|
||||||
|
*/
|
||||||
|
install(options: { item: LibraryPackage, version?: Installable.Version, installDependencies?: boolean }): Promise<void>;
|
||||||
|
/**
|
||||||
|
* Set `filterSelf` to `true` if you want to avoid having `item` in the result set.
|
||||||
|
* Note: as of today (22.02.2021), the CLI works like this: `./arduino-cli lib deps Adaino@0.1.0 ✕ Adaino 0.1.0 must be installed.`.
|
||||||
|
*/
|
||||||
|
listDependencies({ item, version, filterSelf }: { item: LibraryPackage, version: Installable.Version, filterSelf?: boolean }): Promise<LibraryDependency[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export namespace LibraryService {
|
export namespace LibraryService {
|
||||||
@ -83,3 +92,9 @@ export namespace LibraryPackage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LibraryDependency {
|
||||||
|
readonly name: string;
|
||||||
|
readonly requiredVersion: Installable.Version;
|
||||||
|
readonly installedVersion: Installable.Version;
|
||||||
|
}
|
||||||
|
@ -11,12 +11,12 @@ import {
|
|||||||
PlatformListResp, Platform, PlatformUninstallResp, PlatformUninstallReq
|
PlatformListResp, Platform, PlatformUninstallResp, PlatformUninstallReq
|
||||||
} from './cli-protocol/commands/core_pb';
|
} from './cli-protocol/commands/core_pb';
|
||||||
import { BoardDiscovery } from './board-discovery';
|
import { BoardDiscovery } from './board-discovery';
|
||||||
import { CoreClientProvider } from './core-client-provider';
|
import { CoreClientAware } from './core-client-provider';
|
||||||
import { BoardDetailsReq, BoardDetailsResp } from './cli-protocol/commands/board_pb';
|
import { BoardDetailsReq, BoardDetailsResp } from './cli-protocol/commands/board_pb';
|
||||||
import { ListProgrammersAvailableForUploadReq, ListProgrammersAvailableForUploadResp } from './cli-protocol/commands/upload_pb';
|
import { ListProgrammersAvailableForUploadReq, ListProgrammersAvailableForUploadResp } from './cli-protocol/commands/upload_pb';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class BoardsServiceImpl implements BoardsService {
|
export class BoardsServiceImpl extends CoreClientAware implements BoardsService {
|
||||||
|
|
||||||
@inject(ILogger)
|
@inject(ILogger)
|
||||||
protected logger: ILogger;
|
protected logger: ILogger;
|
||||||
@ -25,9 +25,6 @@ export class BoardsServiceImpl implements BoardsService {
|
|||||||
@named('discovery')
|
@named('discovery')
|
||||||
protected discoveryLogger: ILogger;
|
protected discoveryLogger: ILogger;
|
||||||
|
|
||||||
@inject(CoreClientProvider)
|
|
||||||
protected readonly coreClientProvider: CoreClientProvider;
|
|
||||||
|
|
||||||
@inject(OutputService)
|
@inject(OutputService)
|
||||||
protected readonly outputService: OutputService;
|
protected readonly outputService: OutputService;
|
||||||
|
|
||||||
@ -49,25 +46,6 @@ export class BoardsServiceImpl implements BoardsService {
|
|||||||
return this.boardDiscovery.getAvailablePorts();
|
return this.boardDiscovery.getAvailablePorts();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async coreClient(): Promise<CoreClientProvider.Client> {
|
|
||||||
const coreClient = await new Promise<CoreClientProvider.Client>(async resolve => {
|
|
||||||
const client = await this.coreClientProvider.client();
|
|
||||||
if (client) {
|
|
||||||
resolve(client);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const toDispose = this.coreClientProvider.onClientReady(async () => {
|
|
||||||
const client = await this.coreClientProvider.client();
|
|
||||||
if (client) {
|
|
||||||
toDispose.dispose();
|
|
||||||
resolve(client);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return coreClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBoardDetails(options: { fqbn: string }): Promise<BoardDetails | undefined> {
|
async getBoardDetails(options: { fqbn: string }): Promise<BoardDetails | undefined> {
|
||||||
const coreClient = await this.coreClient();
|
const coreClient = await this.coreClient();
|
||||||
const { client, instance } = coreClient;
|
const { client, instance } = coreClient;
|
||||||
|
@ -76,6 +76,9 @@ export class LibraryInstallReq extends jspb.Message {
|
|||||||
getVersion(): string;
|
getVersion(): string;
|
||||||
setVersion(value: string): LibraryInstallReq;
|
setVersion(value: string): LibraryInstallReq;
|
||||||
|
|
||||||
|
getNodeps(): boolean;
|
||||||
|
setNodeps(value: boolean): LibraryInstallReq;
|
||||||
|
|
||||||
|
|
||||||
serializeBinary(): Uint8Array;
|
serializeBinary(): Uint8Array;
|
||||||
toObject(includeInstance?: boolean): LibraryInstallReq.AsObject;
|
toObject(includeInstance?: boolean): LibraryInstallReq.AsObject;
|
||||||
@ -92,6 +95,7 @@ export namespace LibraryInstallReq {
|
|||||||
instance?: commands_common_pb.Instance.AsObject,
|
instance?: commands_common_pb.Instance.AsObject,
|
||||||
name: string,
|
name: string,
|
||||||
version: string,
|
version: string,
|
||||||
|
nodeps: boolean,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,7 +965,8 @@ proto.cc.arduino.cli.commands.LibraryInstallReq.toObject = function(includeInsta
|
|||||||
var f, obj = {
|
var f, obj = {
|
||||||
instance: (f = msg.getInstance()) && commands_common_pb.Instance.toObject(includeInstance, f),
|
instance: (f = msg.getInstance()) && commands_common_pb.Instance.toObject(includeInstance, f),
|
||||||
name: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
name: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||||
version: jspb.Message.getFieldWithDefault(msg, 3, "")
|
version: jspb.Message.getFieldWithDefault(msg, 3, ""),
|
||||||
|
nodeps: jspb.Message.getBooleanFieldWithDefault(msg, 4, false)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (includeInstance) {
|
if (includeInstance) {
|
||||||
@ -1015,6 +1016,10 @@ proto.cc.arduino.cli.commands.LibraryInstallReq.deserializeBinaryFromReader = fu
|
|||||||
var value = /** @type {string} */ (reader.readString());
|
var value = /** @type {string} */ (reader.readString());
|
||||||
msg.setVersion(value);
|
msg.setVersion(value);
|
||||||
break;
|
break;
|
||||||
|
case 4:
|
||||||
|
var value = /** @type {boolean} */ (reader.readBool());
|
||||||
|
msg.setNodeps(value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
reader.skipField();
|
reader.skipField();
|
||||||
break;
|
break;
|
||||||
@ -1066,6 +1071,13 @@ proto.cc.arduino.cli.commands.LibraryInstallReq.serializeBinaryToWriter = functi
|
|||||||
f
|
f
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
f = message.getNodeps();
|
||||||
|
if (f) {
|
||||||
|
writer.writeBool(
|
||||||
|
4,
|
||||||
|
f
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1142,6 +1154,24 @@ proto.cc.arduino.cli.commands.LibraryInstallReq.prototype.setVersion = function(
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* optional bool noDeps = 4;
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
proto.cc.arduino.cli.commands.LibraryInstallReq.prototype.getNodeps = function() {
|
||||||
|
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 4, false));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} value
|
||||||
|
* @return {!proto.cc.arduino.cli.commands.LibraryInstallReq} returns this
|
||||||
|
*/
|
||||||
|
proto.cc.arduino.cli.commands.LibraryInstallReq.prototype.setNodeps = function(value) {
|
||||||
|
return jspb.Message.setProto3BooleanField(this, 4, value);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -167,3 +167,30 @@ export namespace CoreClientProvider {
|
|||||||
readonly instance: Instance;
|
readonly instance: Instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export abstract class CoreClientAware {
|
||||||
|
|
||||||
|
@inject(CoreClientProvider)
|
||||||
|
protected readonly coreClientProvider: CoreClientProvider;
|
||||||
|
|
||||||
|
protected async coreClient(): Promise<CoreClientProvider.Client> {
|
||||||
|
const coreClient = await new Promise<CoreClientProvider.Client>(async resolve => {
|
||||||
|
const client = await this.coreClientProvider.client();
|
||||||
|
if (client) {
|
||||||
|
resolve(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const toDispose = this.coreClientProvider.onClientReady(async () => {
|
||||||
|
const client = await this.coreClientProvider.client();
|
||||||
|
if (client) {
|
||||||
|
toDispose.dispose();
|
||||||
|
resolve(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return coreClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -4,7 +4,7 @@ import { relative } from 'path';
|
|||||||
import * as jspb from 'google-protobuf';
|
import * as jspb from 'google-protobuf';
|
||||||
import { CoreService } from '../common/protocol/core-service';
|
import { CoreService } from '../common/protocol/core-service';
|
||||||
import { CompileReq, CompileResp } from './cli-protocol/commands/compile_pb';
|
import { CompileReq, CompileResp } from './cli-protocol/commands/compile_pb';
|
||||||
import { CoreClientProvider } from './core-client-provider';
|
import { CoreClientAware } from './core-client-provider';
|
||||||
import { UploadReq, UploadResp, BurnBootloaderReq, BurnBootloaderResp, UploadUsingProgrammerReq, UploadUsingProgrammerResp } from './cli-protocol/commands/upload_pb';
|
import { UploadReq, UploadResp, BurnBootloaderReq, BurnBootloaderResp, UploadUsingProgrammerReq, UploadUsingProgrammerResp } from './cli-protocol/commands/upload_pb';
|
||||||
import { OutputService } from '../common/protocol/output-service';
|
import { OutputService } from '../common/protocol/output-service';
|
||||||
import { NotificationServiceServer } from '../common/protocol';
|
import { NotificationServiceServer } from '../common/protocol';
|
||||||
@ -14,10 +14,7 @@ import { firstToUpperCase, firstToLowerCase } from '../common/utils';
|
|||||||
import { BoolValue } from 'google-protobuf/google/protobuf/wrappers_pb';
|
import { BoolValue } from 'google-protobuf/google/protobuf/wrappers_pb';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class CoreServiceImpl implements CoreService {
|
export class CoreServiceImpl extends CoreClientAware implements CoreService {
|
||||||
|
|
||||||
@inject(CoreClientProvider)
|
|
||||||
protected readonly coreClientProvider: CoreClientProvider;
|
|
||||||
|
|
||||||
@inject(OutputService)
|
@inject(OutputService)
|
||||||
protected readonly outputService: OutputService;
|
protected readonly outputService: OutputService;
|
||||||
@ -152,25 +149,6 @@ export class CoreServiceImpl implements CoreService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async coreClient(): Promise<CoreClientProvider.Client> {
|
|
||||||
const coreClient = await new Promise<CoreClientProvider.Client>(async resolve => {
|
|
||||||
const client = await this.coreClientProvider.client();
|
|
||||||
if (client) {
|
|
||||||
resolve(client);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const toDispose = this.coreClientProvider.onClientReady(async () => {
|
|
||||||
const client = await this.coreClientProvider.client();
|
|
||||||
if (client) {
|
|
||||||
toDispose.dispose();
|
|
||||||
resolve(client);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
return coreClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
private mergeSourceOverrides(req: { getSourceOverrideMap(): jspb.Map<string, string> }, options: CoreService.Compile.Options): void {
|
private mergeSourceOverrides(req: { getSourceOverrideMap(): jspb.Map<string, string> }, options: CoreService.Compile.Options): void {
|
||||||
const sketchPath = FileUri.fsPath(options.sketchUri);
|
const sketchPath = FileUri.fsPath(options.sketchUri);
|
||||||
for (const uri of Object.keys(options.sourceOverride)) {
|
for (const uri of Object.keys(options.sourceOverride)) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { injectable, inject, postConstruct } from 'inversify';
|
import { injectable, inject } from 'inversify';
|
||||||
import { LibraryPackage, LibraryService } from '../common/protocol/library-service';
|
import { LibraryDependency, LibraryPackage, LibraryService } from '../common/protocol/library-service';
|
||||||
import { CoreClientProvider } from './core-client-provider';
|
import { CoreClientAware } from './core-client-provider';
|
||||||
import {
|
import {
|
||||||
LibrarySearchReq,
|
LibrarySearchReq,
|
||||||
LibrarySearchResp,
|
LibrarySearchResp,
|
||||||
@ -12,48 +12,28 @@ import {
|
|||||||
LibraryInstallResp,
|
LibraryInstallResp,
|
||||||
LibraryUninstallReq,
|
LibraryUninstallReq,
|
||||||
LibraryUninstallResp,
|
LibraryUninstallResp,
|
||||||
Library
|
Library,
|
||||||
|
LibraryResolveDependenciesReq
|
||||||
} from './cli-protocol/commands/lib_pb';
|
} from './cli-protocol/commands/lib_pb';
|
||||||
import { Installable } from '../common/protocol/installable';
|
import { Installable } from '../common/protocol/installable';
|
||||||
import { ILogger, notEmpty } from '@theia/core';
|
import { ILogger, notEmpty } from '@theia/core';
|
||||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
|
||||||
import { FileUri } from '@theia/core/lib/node';
|
import { FileUri } from '@theia/core/lib/node';
|
||||||
import { OutputService, NotificationServiceServer } from '../common/protocol';
|
import { OutputService, NotificationServiceServer } from '../common/protocol';
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class LibraryServiceImpl implements LibraryService {
|
export class LibraryServiceImpl extends CoreClientAware implements LibraryService {
|
||||||
|
|
||||||
@inject(ILogger)
|
@inject(ILogger)
|
||||||
protected logger: ILogger;
|
protected logger: ILogger;
|
||||||
|
|
||||||
@inject(CoreClientProvider)
|
|
||||||
protected readonly coreClientProvider: CoreClientProvider;
|
|
||||||
|
|
||||||
@inject(OutputService)
|
@inject(OutputService)
|
||||||
protected readonly outputService: OutputService;
|
protected readonly outputService: OutputService;
|
||||||
|
|
||||||
@inject(NotificationServiceServer)
|
@inject(NotificationServiceServer)
|
||||||
protected readonly notificationServer: NotificationServiceServer;
|
protected readonly notificationServer: NotificationServiceServer;
|
||||||
|
|
||||||
protected ready = new Deferred<void>();
|
|
||||||
|
|
||||||
@postConstruct()
|
|
||||||
protected init(): void {
|
|
||||||
this.coreClientProvider.client().then(client => {
|
|
||||||
if (client) {
|
|
||||||
this.ready.resolve();
|
|
||||||
} else {
|
|
||||||
this.coreClientProvider.onClientReady(() => this.ready.resolve());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async search(options: { query?: string }): Promise<LibraryPackage[]> {
|
async search(options: { query?: string }): Promise<LibraryPackage[]> {
|
||||||
await this.ready.promise;
|
const coreClient = await this.coreClient();
|
||||||
const coreClient = await this.coreClientProvider.client();
|
|
||||||
if (!coreClient) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const { client, instance } = coreClient;
|
const { client, instance } = coreClient;
|
||||||
|
|
||||||
const listReq = new LibraryListReq();
|
const listReq = new LibraryListReq();
|
||||||
@ -96,12 +76,7 @@ export class LibraryServiceImpl implements LibraryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async list({ fqbn }: { fqbn?: string | undefined }): Promise<LibraryPackage[]> {
|
async list({ fqbn }: { fqbn?: string | undefined }): Promise<LibraryPackage[]> {
|
||||||
await this.ready.promise;
|
const coreClient = await this.coreClient();
|
||||||
const coreClient = await this.coreClientProvider.client();
|
|
||||||
if (!coreClient) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const { client, instance } = coreClient;
|
const { client, instance } = coreClient;
|
||||||
const req = new LibraryListReq();
|
const req = new LibraryListReq();
|
||||||
req.setInstance(instance);
|
req.setInstance(instance);
|
||||||
@ -157,20 +132,42 @@ export class LibraryServiceImpl implements LibraryService {
|
|||||||
}).filter(notEmpty);
|
}).filter(notEmpty);
|
||||||
}
|
}
|
||||||
|
|
||||||
async install(options: { item: LibraryPackage, version?: Installable.Version }): Promise<void> {
|
async listDependencies({ item, version, filterSelf }: { item: LibraryPackage, version: Installable.Version, filterSelf?: boolean }): Promise<LibraryDependency[]> {
|
||||||
await this.ready.promise;
|
const coreClient = await this.coreClient();
|
||||||
|
const { client, instance } = coreClient;
|
||||||
|
const req = new LibraryResolveDependenciesReq();
|
||||||
|
req.setInstance(instance);
|
||||||
|
req.setName(item.name);
|
||||||
|
req.setVersion(version);
|
||||||
|
const dependencies = await new Promise<LibraryDependency[]>((resolve, reject) => {
|
||||||
|
client.libraryResolveDependencies(req, (error, resp) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resolve(resp.getDependenciesList().map(dep => <LibraryDependency>{
|
||||||
|
name: dep.getName(),
|
||||||
|
installedVersion: dep.getVersioninstalled(),
|
||||||
|
requiredVersion: dep.getVersionrequired()
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
});
|
||||||
|
return filterSelf ? dependencies.filter(({ name }) => name !== item.name) : dependencies;
|
||||||
|
}
|
||||||
|
|
||||||
|
async install(options: { item: LibraryPackage, version?: Installable.Version, installDependencies?: boolean }): Promise<void> {
|
||||||
const item = options.item;
|
const item = options.item;
|
||||||
const version = !!options.version ? options.version : item.availableVersions[0];
|
const version = !!options.version ? options.version : item.availableVersions[0];
|
||||||
const coreClient = await this.coreClientProvider.client();
|
const coreClient = await this.coreClient();
|
||||||
if (!coreClient) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { client, instance } = coreClient;
|
const { client, instance } = coreClient;
|
||||||
|
|
||||||
const req = new LibraryInstallReq();
|
const req = new LibraryInstallReq();
|
||||||
req.setInstance(instance);
|
req.setInstance(instance);
|
||||||
req.setName(item.name);
|
req.setName(item.name);
|
||||||
req.setVersion(version);
|
req.setVersion(version);
|
||||||
|
if (options.installDependencies === false) {
|
||||||
|
req.setNodeps(true);
|
||||||
|
}
|
||||||
|
|
||||||
console.info('>>> Starting library package installation...', item);
|
console.info('>>> Starting library package installation...', item);
|
||||||
const resp = client.libraryInstall(req);
|
const resp = client.libraryInstall(req);
|
||||||
@ -193,10 +190,7 @@ export class LibraryServiceImpl implements LibraryService {
|
|||||||
|
|
||||||
async uninstall(options: { item: LibraryPackage }): Promise<void> {
|
async uninstall(options: { item: LibraryPackage }): Promise<void> {
|
||||||
const item = options.item;
|
const item = options.item;
|
||||||
const coreClient = await this.coreClientProvider.client();
|
const coreClient = await this.coreClient();
|
||||||
if (!coreClient) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { client, instance } = coreClient;
|
const { client, instance } = coreClient;
|
||||||
|
|
||||||
const req = new LibraryUninstallReq();
|
const req = new LibraryUninstallReq();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user