Skip to content

Commit 3e2f048

Browse files
author
Akos Kitta
committed
Clients can show index update errors.
Signed-off-by: Akos Kitta <[email protected]>
1 parent a4d71c7 commit 3e2f048

13 files changed

+114
-48
lines changed

arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ import { MonacoTextModelService } from './theia/monaco/monaco-text-model-service
164164
import { ResponseServiceImpl } from './response-service-impl';
165165
import {
166166
ResponseService,
167-
ResponseServiceArduino,
167+
ResponseServiceClient,
168168
ResponseServicePath,
169169
} from '../common/protocol/response-service';
170170
import { NotificationCenter } from './notification-center';
@@ -723,7 +723,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
723723
});
724724

725725
bind(ResponseService).toService(ResponseServiceImpl);
726-
bind(ResponseServiceArduino).toService(ResponseServiceImpl);
726+
bind(ResponseServiceClient).toService(ResponseServiceImpl);
727727

728728
bind(NotificationCenter).toSelf().inSingletonScope();
729729
bind(FrontendApplicationContribution).toService(NotificationCenter);

arduino-ide-extension/src/browser/boards/boards-auto-installer.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
} from '../../common/protocol/boards-service';
99
import { BoardsServiceProvider } from './boards-service-provider';
1010
import { BoardsConfig } from './boards-config';
11-
import { Installable, ResponseServiceArduino } from '../../common/protocol';
11+
import { Installable, ResponseServiceClient } from '../../common/protocol';
1212
import { BoardsListWidgetFrontendContribution } from './boards-widget-frontend-contribution';
1313
import { nls } from '@theia/core/lib/common';
1414

@@ -27,8 +27,8 @@ export class BoardsAutoInstaller implements FrontendApplicationContribution {
2727
@inject(BoardsServiceProvider)
2828
protected readonly boardsServiceClient: BoardsServiceProvider;
2929

30-
@inject(ResponseServiceArduino)
31-
protected readonly responseService: ResponseServiceArduino;
30+
@inject(ResponseServiceClient)
31+
protected readonly responseService: ResponseServiceClient;
3232

3333
@inject(BoardsListWidgetFrontendContribution)
3434
protected readonly boardsManagerFrontendContribution: BoardsListWidgetFrontendContribution;

arduino-ide-extension/src/browser/contributions/add-zip-library.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { ArduinoMenus } from '../menu/arduino-menus';
77
import {
88
Installable,
99
LibraryService,
10-
ResponseServiceArduino,
10+
ResponseServiceClient,
1111
} from '../../common/protocol';
1212
import {
1313
SketchContribution,
@@ -22,8 +22,8 @@ export class AddZipLibrary extends SketchContribution {
2222
@inject(EnvVariablesServer)
2323
protected readonly envVariableServer: EnvVariablesServer;
2424

25-
@inject(ResponseServiceArduino)
26-
protected readonly responseService: ResponseServiceArduino;
25+
@inject(ResponseServiceClient)
26+
protected readonly responseService: ResponseServiceClient;
2727

2828
@inject(LibraryService)
2929
protected readonly libraryService: LibraryService;

arduino-ide-extension/src/browser/contributions/indexes-update-progress.ts

+17-9
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,11 @@ export class IndexesUpdateProgress extends Contribution {
2525
);
2626
});
2727
this.notificationCenter.onIndexDidUpdate((progressId) => {
28-
if (this.currentProgress) {
29-
if (this.currentProgress.progressId !== progressId) {
30-
console.warn(
31-
`Mismatching progress IDs. Expected ${progressId}, got ${this.currentProgress.progressId}. Canceling anyway.`
32-
);
33-
}
34-
this.currentProgress.cancel();
35-
this.currentProgress = undefined;
36-
}
28+
this.cancelProgress(progressId);
29+
});
30+
this.notificationCenter.onIndexUpdateDidFail(({ progressId, message }) => {
31+
this.cancelProgress(progressId);
32+
this.messageService.error(message);
3733
});
3834
}
3935

@@ -65,4 +61,16 @@ export class IndexesUpdateProgress extends Contribution {
6561
this.currentProgress = { ...progress, progressId };
6662
return this.currentProgress;
6763
}
64+
65+
private cancelProgress(progressId: string) {
66+
if (this.currentProgress) {
67+
if (this.currentProgress.progressId !== progressId) {
68+
console.warn(
69+
`Mismatching progress IDs. Expected ${progressId}, got ${this.currentProgress.progressId}. Canceling anyway.`
70+
);
71+
}
72+
this.currentProgress.cancel();
73+
this.currentProgress = undefined;
74+
}
75+
}
6876
}

arduino-ide-extension/src/browser/notification-center.ts

+16
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ export class NotificationCenter
3838
protected readonly indexWillUpdateEmitter = new Emitter<string>();
3939
protected readonly indexUpdateDidProgressEmitter =
4040
new Emitter<ProgressMessage>();
41+
protected readonly indexUpdateDidFailEmitter = new Emitter<{
42+
progressId: string;
43+
message: string;
44+
}>();
4145
protected readonly daemonDidStartEmitter = new Emitter<string>();
4246
protected readonly daemonDidStopEmitter = new Emitter<void>();
4347
protected readonly configDidChangeEmitter = new Emitter<{
@@ -67,6 +71,7 @@ export class NotificationCenter
6771
this.indexWillUpdateEmitter,
6872
this.indexUpdateDidProgressEmitter,
6973
this.indexDidUpdateEmitter,
74+
this.indexUpdateDidFailEmitter,
7075
this.daemonDidStartEmitter,
7176
this.daemonDidStopEmitter,
7277
this.configDidChangeEmitter,
@@ -80,6 +85,7 @@ export class NotificationCenter
8085
readonly onIndexDidUpdate = this.indexDidUpdateEmitter.event;
8186
readonly onIndexWillUpdate = this.indexDidUpdateEmitter.event;
8287
readonly onIndexUpdateDidProgress = this.indexUpdateDidProgressEmitter.event;
88+
readonly onIndexUpdateDidFail = this.indexUpdateDidFailEmitter.event;
8389
readonly onDaemonDidStart = this.daemonDidStartEmitter.event;
8490
readonly onDaemonDidStop = this.daemonDidStopEmitter.event;
8591
readonly onConfigDidChange = this.configDidChangeEmitter.event;
@@ -118,6 +124,16 @@ export class NotificationCenter
118124
this.indexDidUpdateEmitter.fire(progressId);
119125
}
120126

127+
notifyIndexUpdateDidFail({
128+
progressId,
129+
message,
130+
}: {
131+
progressId: string;
132+
message: string;
133+
}): void {
134+
this.indexUpdateDidFailEmitter.fire({ progressId, message });
135+
}
136+
121137
notifyDaemonDidStart(port: string): void {
122138
this.daemonDidStartEmitter.fire(port);
123139
}

arduino-ide-extension/src/browser/response-service-impl.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ import {
77
import {
88
OutputMessage,
99
ProgressMessage,
10-
ResponseServiceArduino,
10+
ResponseServiceClient,
1111
} from '../common/protocol/response-service';
1212

1313
@injectable()
14-
export class ResponseServiceImpl implements ResponseServiceArduino {
14+
export class ResponseServiceImpl implements ResponseServiceClient {
1515
@inject(OutputChannelManager)
1616
private readonly outputChannelManager: OutputChannelManager;
1717

1818
private readonly progressDidChangeEmitter = new Emitter<ProgressMessage>();
1919

2020
readonly onProgressDidChange = this.progressDidChangeEmitter.event;
2121

22-
clearArduinoChannel(): void {
22+
clearOutput(): void {
2323
this.outputChannelManager.getChannel('Arduino').clear();
2424
}
2525

arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { SearchBar } from './search-bar';
1111
import { ListWidget } from './list-widget';
1212
import { ComponentList } from './component-list';
1313
import { ListItemRenderer } from './list-item-renderer';
14-
import { ResponseServiceArduino } from '../../../common/protocol';
14+
import { ResponseServiceClient } from '../../../common/protocol';
1515
import { nls } from '@theia/core/lib/common';
1616

1717
export class FilterableListContainer<
@@ -162,7 +162,7 @@ export namespace FilterableListContainer {
162162
readonly resolveFocus: (element: HTMLElement | undefined) => void;
163163
readonly filterTextChangeEvent: Event<string | undefined>;
164164
readonly messageService: MessageService;
165-
readonly responseService: ResponseServiceArduino;
165+
readonly responseService: ResponseServiceClient;
166166
readonly install: ({
167167
item,
168168
progressId,

arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import * as React from '@theia/core/shared/react';
2-
import { injectable, postConstruct, inject } from '@theia/core/shared/inversify';
2+
import {
3+
injectable,
4+
postConstruct,
5+
inject,
6+
} from '@theia/core/shared/inversify';
37
import { Widget } from '@theia/core/shared/@phosphor/widgets';
48
import { Message } from '@theia/core/shared/@phosphor/messaging';
59
import { Deferred } from '@theia/core/lib/common/promise-util';
@@ -12,7 +16,7 @@ import {
1216
Installable,
1317
Searchable,
1418
ArduinoComponent,
15-
ResponseServiceArduino,
19+
ResponseServiceClient,
1620
} from '../../../common/protocol';
1721
import { FilterableListContainer } from './filterable-list-container';
1822
import { ListItemRenderer } from './list-item-renderer';
@@ -21,15 +25,15 @@ import { NotificationCenter } from '../../notification-center';
2125
@injectable()
2226
export abstract class ListWidget<
2327
T extends ArduinoComponent
24-
> extends ReactWidget {
28+
> extends ReactWidget {
2529
@inject(MessageService)
2630
protected readonly messageService: MessageService;
2731

2832
@inject(CommandService)
2933
protected readonly commandService: CommandService;
3034

31-
@inject(ResponseServiceArduino)
32-
protected readonly responseService: ResponseServiceArduino;
35+
@inject(ResponseServiceClient)
36+
protected readonly responseService: ResponseServiceClient;
3337

3438
@inject(NotificationCenter)
3539
protected readonly notificationCenter: NotificationCenter;

arduino-ide-extension/src/common/protocol/installable.ts

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import * as semver from 'semver';
2-
import { Progress } from '@theia/core/lib/common/message-service-protocol';
2+
import type { Progress } from '@theia/core/lib/common/message-service-protocol';
33
import {
44
CancellationToken,
55
CancellationTokenSource,
66
} from '@theia/core/lib/common/cancellation';
77
import { naturalCompare } from './../utils';
8-
import { ArduinoComponent } from './arduino-component';
9-
import { MessageService } from '@theia/core';
10-
import { ResponseServiceArduino } from './response-service';
8+
import type { ArduinoComponent } from './arduino-component';
9+
import type { MessageService } from '@theia/core/lib/common/message-service';
10+
import type { ResponseServiceClient } from './response-service';
1111

1212
export interface Installable<T extends ArduinoComponent> {
1313
/**
@@ -44,7 +44,7 @@ export namespace Installable {
4444
>(options: {
4545
installable: Installable<T>;
4646
messageService: MessageService;
47-
responseService: ResponseServiceArduino;
47+
responseService: ResponseServiceClient;
4848
item: T;
4949
version: Installable.Version;
5050
}): Promise<void> {
@@ -66,7 +66,7 @@ export namespace Installable {
6666
>(options: {
6767
installable: Installable<T>;
6868
messageService: MessageService;
69-
responseService: ResponseServiceArduino;
69+
responseService: ResponseServiceClient;
7070
item: T;
7171
}): Promise<void> {
7272
const { item } = options;
@@ -86,7 +86,7 @@ export namespace Installable {
8686
export async function doWithProgress(options: {
8787
run: ({ progressId }: { progressId: string }) => Promise<void>;
8888
messageService: MessageService;
89-
responseService: ResponseServiceArduino;
89+
responseService: ResponseServiceClient;
9090
progressText: string;
9191
}): Promise<void> {
9292
return withProgress(
@@ -103,7 +103,7 @@ export namespace Installable {
103103
}
104104
);
105105
try {
106-
options.responseService.clearArduinoChannel();
106+
options.responseService.clearOutput();
107107
await options.run({ progressId });
108108
} finally {
109109
toDispose.dispose();

arduino-ide-extension/src/common/protocol/notification-service.ts

+7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ export interface NotificationServiceClient {
1212
notifyIndexWillUpdate(progressId: string): void;
1313
notifyIndexUpdateDidProgress(progressMessage: ProgressMessage): void;
1414
notifyIndexDidUpdate(progressId: string): void;
15+
notifyIndexUpdateDidFail({
16+
progressId,
17+
message,
18+
}: {
19+
progressId: string;
20+
message: string;
21+
}): void;
1522
notifyDaemonDidStart(port: string): void;
1623
notifyDaemonDidStop(): void;
1724
notifyConfigDidChange(event: { config: Config | undefined }): void;

arduino-ide-extension/src/common/protocol/response-service.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ export interface ResponseService {
4343
reportProgress(message: ProgressMessage): void;
4444
}
4545

46-
export const ResponseServiceArduino = Symbol('ResponseServiceArduino');
47-
export interface ResponseServiceArduino extends ResponseService {
46+
export const ResponseServiceClient = Symbol('ResponseServiceClient');
47+
export interface ResponseServiceClient extends ResponseService {
4848
onProgressDidChange: Event<ProgressMessage>;
49-
clearArduinoChannel: () => void;
49+
clearOutput: () => void;
5050
}

arduino-ide-extension/src/node/core-client-provider.ts

+29-10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { join } from 'path';
12
import * as grpc from '@grpc/grpc-js';
23
import {
34
inject,
@@ -30,6 +31,8 @@ import { DisposableCollection } from '@theia/core/lib/common/disposable';
3031
import { Disposable } from '@theia/core/shared/vscode-languageserver-protocol';
3132
import { v4 } from 'uuid';
3233
import { InstallWithProgress } from './grpc-installable';
34+
import type { DefaultCliConfig } from './cli-config';
35+
import { ServiceError } from './service-error';
3336

3437
@injectable()
3538
export class CoreClientProvider {
@@ -228,8 +231,12 @@ export class CoreClientProvider {
228231
}
229232

230233
private evaluateErrorStatus(status: RpcStatus[]): Error | undefined {
231-
const error = isIndexUpdateRequiredBeforeInit(status); // put future error matching here
232-
return error;
234+
const { cliConfiguration } = this.configService;
235+
if (!cliConfiguration) {
236+
// If the CLI config is not available, do not even try to guess what went wrong.
237+
return new Error(`Could not read the CLI configuration file.`);
238+
}
239+
return isIndexUpdateRequiredBeforeInit(status, cliConfiguration); // put future error matching here
233240
}
234241

235242
private async updateIndexes(
@@ -281,10 +288,15 @@ export class CoreClientProvider {
281288
this.updateLibraryIndex(client, progressId, onDidProgressEmitter),
282289
]);
283290
this.notificationService.notifyIndexDidUpdate(progressId);
284-
return client;
291+
} catch (err) {
292+
this.notificationService.notifyIndexUpdateDidFail({
293+
progressId,
294+
message: ServiceError.is(err) ? err.details : String(err),
295+
});
285296
} finally {
286297
toDispose.dispose();
287298
}
299+
return client;
288300
}
289301

290302
private async updateIndex(
@@ -425,13 +437,14 @@ ${causes
425437
}
426438

427439
function isIndexUpdateRequiredBeforeInit(
428-
status: RpcStatus[]
440+
status: RpcStatus[],
441+
cliConfig: DefaultCliConfig
429442
): IndexUpdateRequiredBeforeInitError | undefined {
430443
const causes = status
431444
.filter((s) =>
432-
IndexUpdateRequiredBeforeInit.map((predicate) => predicate(s)).some(
433-
Boolean
434-
)
445+
IndexUpdateRequiredBeforeInit.map((predicate) =>
446+
predicate(s, cliConfig)
447+
).some(Boolean)
435448
)
436449
.map((s) => RpcStatus.toObject(false, s));
437450
return causes.length
@@ -442,9 +455,14 @@ const IndexUpdateRequiredBeforeInit = [
442455
isPackageIndexMissingStatus,
443456
isDiscoveryNotFoundStatus,
444457
];
445-
function isPackageIndexMissingStatus(status: RpcStatus): boolean {
458+
function isPackageIndexMissingStatus(
459+
status: RpcStatus,
460+
{ directories: { data } }: DefaultCliConfig
461+
): boolean {
446462
const predicate = ({ message }: RpcStatus.AsObject) =>
447-
message.includes('loading json index file');
463+
message.includes('loading json index file') &&
464+
(message.includes(join(data, 'package_index.json')) ||
465+
message.includes(join(data, 'library_index.json')));
448466
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/package_manager.go#L247
449467
return evaluate(status, predicate);
450468
}
@@ -461,5 +479,6 @@ function evaluate(
461479
predicate: (error: RpcStatus.AsObject) => boolean
462480
): boolean {
463481
const status = RpcStatus.toObject(false, subject);
464-
return predicate(status);
482+
const result = predicate(status);
483+
return result;
465484
}

0 commit comments

Comments
 (0)