mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-04-19 12:57:17 +00:00
Various library/platform index update fixes
- IDE2 can start if the package index download fails. Closes #1084 - Split the lib and platform index update. Closes #1156 Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
parent
945a8f4841
commit
0c20ae0e28
@ -158,7 +158,11 @@
|
||||
],
|
||||
"arduino": {
|
||||
"cli": {
|
||||
"version": "0.27.1"
|
||||
"version": {
|
||||
"owner": "cmaglie",
|
||||
"repo": "arduino-cli",
|
||||
"commitish": "download_progress_refactor"
|
||||
}
|
||||
},
|
||||
"fwuploader": {
|
||||
"version": "2.2.0"
|
||||
|
@ -332,6 +332,7 @@ import { OutputEditorFactory } from './theia/output/output-editor-factory';
|
||||
import { StartupTaskProvider } from '../electron-common/startup-task';
|
||||
import { DeleteSketch } from './contributions/delete-sketch';
|
||||
import { UserFields } from './contributions/user-fields';
|
||||
import { UpdateIndexes } from './contributions/update-indexes';
|
||||
|
||||
const registerArduinoThemes = () => {
|
||||
const themes: MonacoThemeJson[] = [
|
||||
@ -744,6 +745,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
Contribution.configure(bind, CheckForUpdates);
|
||||
Contribution.configure(bind, UserFields);
|
||||
Contribution.configure(bind, DeleteSketch);
|
||||
Contribution.configure(bind, UpdateIndexes);
|
||||
|
||||
bindContributionProvider(bind, StartupTaskProvider);
|
||||
bind(StartupTaskProvider).toService(BoardsServiceProvider); // to reuse the boards config in another window
|
||||
|
@ -132,7 +132,7 @@ export class BoardsConfig extends React.Component<
|
||||
this.props.notificationCenter.onPlatformDidUninstall(() =>
|
||||
this.updateBoards(this.state.query)
|
||||
),
|
||||
this.props.notificationCenter.onIndexDidUpdate(() =>
|
||||
this.props.notificationCenter.onIndexUpdateDidComplete(() =>
|
||||
this.updateBoards(this.state.query)
|
||||
),
|
||||
this.props.notificationCenter.onDaemonDidStart(() =>
|
||||
|
@ -16,7 +16,7 @@ export class IndexesUpdateProgress extends Contribution {
|
||||
| undefined;
|
||||
|
||||
override onStart(): void {
|
||||
this.notificationCenter.onIndexWillUpdate((progressId) =>
|
||||
this.notificationCenter.onIndexUpdateWillStart(({ progressId }) =>
|
||||
this.getOrCreateProgress(progressId)
|
||||
);
|
||||
this.notificationCenter.onIndexUpdateDidProgress((progress) => {
|
||||
@ -24,7 +24,7 @@ export class IndexesUpdateProgress extends Contribution {
|
||||
delegate.report(progress)
|
||||
);
|
||||
});
|
||||
this.notificationCenter.onIndexDidUpdate((progressId) => {
|
||||
this.notificationCenter.onIndexUpdateDidComplete(({ progressId }) => {
|
||||
this.cancelProgress(progressId);
|
||||
});
|
||||
this.notificationCenter.onIndexUpdateDidFail(({ progressId, message }) => {
|
||||
|
@ -0,0 +1,193 @@
|
||||
import { LocalStorageService } from '@theia/core/lib/browser/storage-service';
|
||||
import { nls } from '@theia/core/lib/common/nls';
|
||||
import { inject, injectable } from '@theia/core/shared/inversify';
|
||||
import { CoreService, IndexType } from '../../common/protocol';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
import { WindowServiceExt } from '../theia/core/window-service-ext';
|
||||
import { Command, CommandRegistry, Contribution } from './contribution';
|
||||
|
||||
@injectable()
|
||||
export class UpdateIndexes extends Contribution {
|
||||
@inject(WindowServiceExt)
|
||||
private readonly windowService: WindowServiceExt;
|
||||
@inject(LocalStorageService)
|
||||
private readonly localStorage: LocalStorageService;
|
||||
@inject(CoreService)
|
||||
private readonly coreService: CoreService;
|
||||
@inject(NotificationCenter)
|
||||
private readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected override init(): void {
|
||||
super.init();
|
||||
this.notificationCenter.onIndexUpdateDidComplete(({ summary }) =>
|
||||
Promise.all(
|
||||
Object.entries(summary).map(([type, updatedAt]) =>
|
||||
this.setLastUpdateDateTime(type as IndexType, updatedAt)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
override onReady(): void {
|
||||
this.checkForUpdates();
|
||||
}
|
||||
|
||||
override registerCommands(registry: CommandRegistry): void {
|
||||
registry.registerCommand(UpdateIndexes.Commands.UPDATE_INDEXES, {
|
||||
execute: () => this.updateIndexes(IndexType.All, true),
|
||||
});
|
||||
registry.registerCommand(UpdateIndexes.Commands.UPDATE_PLATFORM_INDEX, {
|
||||
execute: () => this.updateIndexes(['platform'], true),
|
||||
});
|
||||
registry.registerCommand(UpdateIndexes.Commands.UPDATE_LIBRARY_INDEX, {
|
||||
execute: () => this.updateIndexes(['library'], true),
|
||||
});
|
||||
}
|
||||
|
||||
private async checkForUpdates(): Promise<void> {
|
||||
const checkForUpdates = this.preferences['arduino.checkForUpdates'];
|
||||
if (!checkForUpdates) {
|
||||
console.debug(
|
||||
'[update-indexes]: `arduino.checkForUpdates` is `false`. Skipping updating the indexes.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (await this.windowService.isFirstWindow()) {
|
||||
const summary = await this.coreService.indexUpdateSummaryBeforeInit();
|
||||
if (summary.message) {
|
||||
this.messageService.error(summary.message);
|
||||
}
|
||||
const typesToCheck = IndexType.All.filter((type) => !(type in summary));
|
||||
if (Object.keys(summary).length) {
|
||||
console.debug(
|
||||
`[update-indexes]: Detected an index update summary before the core gRPC client initialization. Updating local storage with ${JSON.stringify(
|
||||
summary
|
||||
)}`
|
||||
);
|
||||
} else {
|
||||
console.debug(
|
||||
'[update-indexes]: No index update summary was available before the core gRPC client initialization. Checking the status of the all the index types.'
|
||||
);
|
||||
}
|
||||
await Promise.allSettled([
|
||||
...Object.entries(summary).map(([type, updatedAt]) =>
|
||||
this.setLastUpdateDateTime(type as IndexType, updatedAt)
|
||||
),
|
||||
this.updateIndexes(typesToCheck),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private async updateIndexes(
|
||||
types: IndexType[],
|
||||
force = false
|
||||
): Promise<void> {
|
||||
const updatedAt = new Date().toISOString();
|
||||
return Promise.all(
|
||||
types.map((type) => this.needsIndexUpdate(type, updatedAt, force))
|
||||
).then((needsIndexUpdateResults) => {
|
||||
const typesToUpdate = needsIndexUpdateResults.filter(IndexType.is);
|
||||
if (typesToUpdate.length) {
|
||||
console.debug(
|
||||
`[update-indexes]: Requesting the index update of type: ${JSON.stringify(
|
||||
typesToUpdate
|
||||
)} with date time: ${updatedAt}.`
|
||||
);
|
||||
return this.coreService.updateIndex({ types: typesToUpdate });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async needsIndexUpdate(
|
||||
type: IndexType,
|
||||
now: string,
|
||||
force = false
|
||||
): Promise<IndexType | false> {
|
||||
if (force) {
|
||||
console.debug(
|
||||
`[update-indexes]: Update for index type: '${type}' was forcefully requested.`
|
||||
);
|
||||
return type;
|
||||
}
|
||||
const lastUpdateIsoDateTime = await this.getLastUpdateDateTime(type);
|
||||
if (!lastUpdateIsoDateTime) {
|
||||
console.debug(
|
||||
`[update-indexes]: No last update date time was persisted for index type: '${type}'. Index update is required.`
|
||||
);
|
||||
return type;
|
||||
}
|
||||
const lastUpdateDateTime = Date.parse(lastUpdateIsoDateTime);
|
||||
if (Number.isNaN(lastUpdateDateTime)) {
|
||||
console.debug(
|
||||
`[update-indexes]: Invalid last update date time was persisted for index type: '${type}'. Last update date time was: ${lastUpdateDateTime}. Index update is required.`
|
||||
);
|
||||
return type;
|
||||
}
|
||||
const diff = new Date(now).getTime() - lastUpdateDateTime;
|
||||
const needsIndexUpdate = diff >= this.threshold;
|
||||
console.debug(
|
||||
`[update-indexes]: Update for index type '${type}' is ${
|
||||
needsIndexUpdate ? '' : 'not '
|
||||
}required. Now: ${now}, Last index update date time: ${new Date(
|
||||
lastUpdateDateTime
|
||||
).toISOString()}, diff: ${diff} ms, threshold: ${this.threshold} ms.`
|
||||
);
|
||||
return needsIndexUpdate ? type : false;
|
||||
}
|
||||
|
||||
private async getLastUpdateDateTime(
|
||||
type: IndexType
|
||||
): Promise<string | undefined> {
|
||||
const key = this.storageKeyOf(type);
|
||||
return this.localStorage.getData<string>(key);
|
||||
}
|
||||
|
||||
private async setLastUpdateDateTime(
|
||||
type: IndexType,
|
||||
updatedAt: string
|
||||
): Promise<void> {
|
||||
const key = this.storageKeyOf(type);
|
||||
return this.localStorage.setData<string>(key, updatedAt).finally(() => {
|
||||
console.debug(
|
||||
`[update-indexes]: Updated the last index update date time of '${type}' to ${updatedAt}.`
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private storageKeyOf(type: IndexType): string {
|
||||
return `index-last-update-time--${type}`;
|
||||
}
|
||||
|
||||
private get threshold(): number {
|
||||
return 4 * 60 * 60 * 1_000; // four hours in millis
|
||||
}
|
||||
}
|
||||
export namespace UpdateIndexes {
|
||||
export namespace Commands {
|
||||
export const UPDATE_INDEXES: Command & { label: string } = {
|
||||
id: 'arduino-update-indexes',
|
||||
label: nls.localize(
|
||||
'arduino/updateIndexes/updateIndexes',
|
||||
'Update Indexes'
|
||||
),
|
||||
category: 'Arduino',
|
||||
};
|
||||
export const UPDATE_PLATFORM_INDEX: Command & { label: string } = {
|
||||
id: 'arduino-update-package-index',
|
||||
label: nls.localize(
|
||||
'arduino/updateIndexes/updatePackageIndex',
|
||||
'Update Package Index'
|
||||
),
|
||||
category: 'Arduino',
|
||||
};
|
||||
export const UPDATE_LIBRARY_INDEX: Command & { label: string } = {
|
||||
id: 'arduino-update-library-index',
|
||||
label: nls.localize(
|
||||
'arduino/updateIndexes/updateLibraryIndex',
|
||||
'Update Library Index'
|
||||
),
|
||||
category: 'Arduino',
|
||||
};
|
||||
}
|
||||
}
|
@ -8,6 +8,9 @@ import { JsonRpcProxy } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
|
||||
import {
|
||||
IndexUpdateDidCompleteParams,
|
||||
IndexUpdateDidFailParams,
|
||||
IndexUpdateWillStartParams,
|
||||
NotificationServiceClient,
|
||||
NotificationServiceServer,
|
||||
} from '../common/protocol/notification-service';
|
||||
@ -29,48 +32,48 @@ export class NotificationCenter
|
||||
implements NotificationServiceClient, FrontendApplicationContribution
|
||||
{
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly server: JsonRpcProxy<NotificationServiceServer>;
|
||||
private readonly server: JsonRpcProxy<NotificationServiceServer>;
|
||||
|
||||
@inject(FrontendApplicationStateService)
|
||||
private readonly appStateService: FrontendApplicationStateService;
|
||||
|
||||
protected readonly indexDidUpdateEmitter = new Emitter<string>();
|
||||
protected readonly indexWillUpdateEmitter = new Emitter<string>();
|
||||
protected readonly indexUpdateDidProgressEmitter =
|
||||
private readonly indexUpdateDidCompleteEmitter =
|
||||
new Emitter<IndexUpdateDidCompleteParams>();
|
||||
private readonly indexUpdateWillStartEmitter =
|
||||
new Emitter<IndexUpdateWillStartParams>();
|
||||
private readonly indexUpdateDidProgressEmitter =
|
||||
new Emitter<ProgressMessage>();
|
||||
protected readonly indexUpdateDidFailEmitter = new Emitter<{
|
||||
progressId: string;
|
||||
message: string;
|
||||
}>();
|
||||
protected readonly daemonDidStartEmitter = new Emitter<string>();
|
||||
protected readonly daemonDidStopEmitter = new Emitter<void>();
|
||||
protected readonly configDidChangeEmitter = new Emitter<{
|
||||
private readonly indexUpdateDidFailEmitter =
|
||||
new Emitter<IndexUpdateDidFailParams>();
|
||||
private readonly daemonDidStartEmitter = new Emitter<string>();
|
||||
private readonly daemonDidStopEmitter = new Emitter<void>();
|
||||
private readonly configDidChangeEmitter = new Emitter<{
|
||||
config: Config | undefined;
|
||||
}>();
|
||||
protected readonly platformDidInstallEmitter = new Emitter<{
|
||||
private readonly platformDidInstallEmitter = new Emitter<{
|
||||
item: BoardsPackage;
|
||||
}>();
|
||||
protected readonly platformDidUninstallEmitter = new Emitter<{
|
||||
private readonly platformDidUninstallEmitter = new Emitter<{
|
||||
item: BoardsPackage;
|
||||
}>();
|
||||
protected readonly libraryDidInstallEmitter = new Emitter<{
|
||||
private readonly libraryDidInstallEmitter = new Emitter<{
|
||||
item: LibraryPackage;
|
||||
}>();
|
||||
protected readonly libraryDidUninstallEmitter = new Emitter<{
|
||||
private readonly libraryDidUninstallEmitter = new Emitter<{
|
||||
item: LibraryPackage;
|
||||
}>();
|
||||
protected readonly attachedBoardsDidChangeEmitter =
|
||||
private readonly attachedBoardsDidChangeEmitter =
|
||||
new Emitter<AttachedBoardsChangeEvent>();
|
||||
protected readonly recentSketchesChangedEmitter = new Emitter<{
|
||||
private readonly recentSketchesChangedEmitter = new Emitter<{
|
||||
sketches: Sketch[];
|
||||
}>();
|
||||
private readonly onAppStateDidChangeEmitter =
|
||||
new Emitter<FrontendApplicationState>();
|
||||
|
||||
protected readonly toDispose = new DisposableCollection(
|
||||
this.indexWillUpdateEmitter,
|
||||
private readonly toDispose = new DisposableCollection(
|
||||
this.indexUpdateWillStartEmitter,
|
||||
this.indexUpdateDidProgressEmitter,
|
||||
this.indexDidUpdateEmitter,
|
||||
this.indexUpdateDidCompleteEmitter,
|
||||
this.indexUpdateDidFailEmitter,
|
||||
this.daemonDidStartEmitter,
|
||||
this.daemonDidStopEmitter,
|
||||
@ -82,8 +85,8 @@ export class NotificationCenter
|
||||
this.attachedBoardsDidChangeEmitter
|
||||
);
|
||||
|
||||
readonly onIndexDidUpdate = this.indexDidUpdateEmitter.event;
|
||||
readonly onIndexWillUpdate = this.indexDidUpdateEmitter.event;
|
||||
readonly onIndexUpdateDidComplete = this.indexUpdateDidCompleteEmitter.event;
|
||||
readonly onIndexUpdateWillStart = this.indexUpdateWillStartEmitter.event;
|
||||
readonly onIndexUpdateDidProgress = this.indexUpdateDidProgressEmitter.event;
|
||||
readonly onIndexUpdateDidFail = this.indexUpdateDidFailEmitter.event;
|
||||
readonly onDaemonDidStart = this.daemonDidStartEmitter.event;
|
||||
@ -112,26 +115,20 @@ export class NotificationCenter
|
||||
this.toDispose.dispose();
|
||||
}
|
||||
|
||||
notifyIndexWillUpdate(progressId: string): void {
|
||||
this.indexWillUpdateEmitter.fire(progressId);
|
||||
notifyIndexUpdateWillStart(params: IndexUpdateWillStartParams): void {
|
||||
this.indexUpdateWillStartEmitter.fire(params);
|
||||
}
|
||||
|
||||
notifyIndexUpdateDidProgress(progressMessage: ProgressMessage): void {
|
||||
this.indexUpdateDidProgressEmitter.fire(progressMessage);
|
||||
}
|
||||
|
||||
notifyIndexDidUpdate(progressId: string): void {
|
||||
this.indexDidUpdateEmitter.fire(progressId);
|
||||
notifyIndexUpdateDidComplete(params: IndexUpdateDidCompleteParams): void {
|
||||
this.indexUpdateDidCompleteEmitter.fire(params);
|
||||
}
|
||||
|
||||
notifyIndexUpdateDidFail({
|
||||
progressId,
|
||||
message,
|
||||
}: {
|
||||
progressId: string;
|
||||
message: string;
|
||||
}): void {
|
||||
this.indexUpdateDidFailEmitter.fire({ progressId, message });
|
||||
notifyIndexUpdateDidFail(params: IndexUpdateDidFailParams): void {
|
||||
this.indexUpdateDidFailEmitter.fire(params);
|
||||
}
|
||||
|
||||
notifyDaemonDidStart(port: string): void {
|
||||
|
@ -68,7 +68,7 @@ export abstract class ListWidget<
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.toDispose.pushAll([
|
||||
this.notificationCenter.onIndexDidUpdate(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onIndexUpdateDidComplete(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onDaemonDidStart(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onDaemonDidStop(() => this.refresh(undefined)),
|
||||
]);
|
||||
|
@ -11,6 +11,7 @@ import type {
|
||||
} from '../../common/protocol/boards-service';
|
||||
import type { Programmer } from './boards-service';
|
||||
import type { Sketch } from './sketches-service';
|
||||
import { IndexUpdateSummary } from './notification-service';
|
||||
|
||||
export const CompilerWarningLiterals = [
|
||||
'None',
|
||||
@ -112,6 +113,33 @@ export interface CoreService {
|
||||
* Refreshes the underling core gRPC client for the Arduino CLI.
|
||||
*/
|
||||
refresh(): Promise<void>;
|
||||
/**
|
||||
* Updates the index of the given index types and refreshes (`init`) the underlying core gRPC client.
|
||||
* If `types` is empty, only the refresh part will be executed.
|
||||
*/
|
||||
updateIndex({ types }: { types: IndexType[] }): Promise<void>;
|
||||
/**
|
||||
* If the IDE2 detects invalid or missing indexes on core client init,
|
||||
* IDE2 tries to update the indexes before the first frontend connects.
|
||||
* Use this method to determine whether the backend has already updated
|
||||
* the indexes before updating them.
|
||||
*
|
||||
* If yes, the connected frontend can update the local storage with the most
|
||||
* recent index update date-time for a particular index type,
|
||||
* and IDE2 can avoid the double indexes update.
|
||||
*/
|
||||
indexUpdateSummaryBeforeInit(): Promise<Readonly<IndexUpdateSummary>>;
|
||||
}
|
||||
|
||||
export const IndexTypeLiterals = ['platform', 'library'] as const;
|
||||
export type IndexType = typeof IndexTypeLiterals[number];
|
||||
export namespace IndexType {
|
||||
export function is(arg: unknown): arg is IndexType {
|
||||
return (
|
||||
typeof arg === 'string' && IndexTypeLiterals.includes(arg as IndexType)
|
||||
);
|
||||
}
|
||||
export const All: IndexType[] = IndexTypeLiterals.filter(is);
|
||||
}
|
||||
|
||||
export namespace CoreService {
|
||||
|
@ -5,27 +5,62 @@ import type {
|
||||
Config,
|
||||
ProgressMessage,
|
||||
Sketch,
|
||||
IndexType,
|
||||
} from '../protocol';
|
||||
import type { LibraryPackage } from './library-service';
|
||||
|
||||
/**
|
||||
* Values are [ISO 8601](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
||||
* strings representing the date-time when the update of the index has been completed.
|
||||
*/
|
||||
export type IndexUpdateSummary = {
|
||||
[T in IndexType]: string;
|
||||
} & { message?: string };
|
||||
export interface IndexUpdateParams {
|
||||
/**
|
||||
* Application unique ID of the progress.
|
||||
*/
|
||||
readonly progressId: string;
|
||||
/**
|
||||
* The type of the index is which is being updated.
|
||||
*/
|
||||
readonly types: IndexType[];
|
||||
}
|
||||
export type IndexUpdateWillStartParams = IndexUpdateParams;
|
||||
export interface IndexUpdateDidCompleteParams
|
||||
extends Omit<IndexUpdateParams, 'types'> {
|
||||
readonly summary: IndexUpdateSummary;
|
||||
}
|
||||
export interface IndexUpdateDidFailParams extends IndexUpdateParams {
|
||||
/**
|
||||
* Describes the reason of the index update failure.
|
||||
*/
|
||||
readonly message: string;
|
||||
}
|
||||
|
||||
export interface NotificationServiceClient {
|
||||
notifyIndexWillUpdate(progressId: string): void;
|
||||
// Index
|
||||
notifyIndexUpdateWillStart(params: IndexUpdateWillStartParams): void;
|
||||
notifyIndexUpdateDidProgress(progressMessage: ProgressMessage): void;
|
||||
notifyIndexDidUpdate(progressId: string): void;
|
||||
notifyIndexUpdateDidFail({
|
||||
progressId,
|
||||
message,
|
||||
}: {
|
||||
progressId: string;
|
||||
message: string;
|
||||
}): void;
|
||||
notifyIndexUpdateDidComplete(params: IndexUpdateDidCompleteParams): void;
|
||||
notifyIndexUpdateDidFail(params: IndexUpdateDidFailParams): void;
|
||||
|
||||
// Daemon
|
||||
notifyDaemonDidStart(port: string): void;
|
||||
notifyDaemonDidStop(): void;
|
||||
|
||||
// CLI config
|
||||
notifyConfigDidChange(event: { config: Config | undefined }): void;
|
||||
|
||||
// Platforms
|
||||
notifyPlatformDidInstall(event: { item: BoardsPackage }): void;
|
||||
notifyPlatformDidUninstall(event: { item: BoardsPackage }): void;
|
||||
|
||||
// Libraries
|
||||
notifyLibraryDidInstall(event: { item: LibraryPackage }): void;
|
||||
notifyLibraryDidUninstall(event: { item: LibraryPackage }): void;
|
||||
|
||||
// Boards discovery
|
||||
notifyAttachedBoardsDidChange(event: AttachedBoardsChangeEvent): void;
|
||||
notifyRecentSketchesDidChange(event: { sketches: Sketch[] }): void;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import { deepClone } from '@theia/core/lib/common/objects';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import { BackendApplicationContribution } from '@theia/core/lib/node';
|
||||
import { inject, injectable, named } from '@theia/core/shared/inversify';
|
||||
import { Disposable } from '@theia/core/shared/vscode-languageserver-protocol';
|
||||
import { Disposable } from '@theia/core/lib/common/disposable';
|
||||
import { v4 } from 'uuid';
|
||||
import { Unknown } from '../common/nls';
|
||||
import {
|
||||
@ -78,14 +78,6 @@ export class BoardDiscovery
|
||||
|
||||
onStart(): void {
|
||||
this.start();
|
||||
this.onClientDidRefresh(() => this.restart());
|
||||
}
|
||||
|
||||
private async restart(): Promise<void> {
|
||||
this.logger.info('restarting before stop');
|
||||
await this.stop();
|
||||
this.logger.info('restarting after stop');
|
||||
return this.start();
|
||||
}
|
||||
|
||||
onStop(): void {
|
||||
|
@ -220,6 +220,9 @@ export class UpdateIndexRequest extends jspb.Message {
|
||||
getInstance(): cc_arduino_cli_commands_v1_common_pb.Instance | undefined;
|
||||
setInstance(value?: cc_arduino_cli_commands_v1_common_pb.Instance): UpdateIndexRequest;
|
||||
|
||||
getIgnoreCustomPackageIndexes(): boolean;
|
||||
setIgnoreCustomPackageIndexes(value: boolean): UpdateIndexRequest;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): UpdateIndexRequest.AsObject;
|
||||
@ -234,6 +237,7 @@ export class UpdateIndexRequest extends jspb.Message {
|
||||
export namespace UpdateIndexRequest {
|
||||
export type AsObject = {
|
||||
instance?: cc_arduino_cli_commands_v1_common_pb.Instance.AsObject,
|
||||
ignoreCustomPackageIndexes: boolean,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1811,7 +1811,8 @@ proto.cc.arduino.cli.commands.v1.UpdateIndexRequest.prototype.toObject = functio
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.UpdateIndexRequest.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
instance: (f = msg.getInstance()) && cc_arduino_cli_commands_v1_common_pb.Instance.toObject(includeInstance, f)
|
||||
instance: (f = msg.getInstance()) && cc_arduino_cli_commands_v1_common_pb.Instance.toObject(includeInstance, f),
|
||||
ignoreCustomPackageIndexes: jspb.Message.getBooleanFieldWithDefault(msg, 2, false)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@ -1853,6 +1854,10 @@ proto.cc.arduino.cli.commands.v1.UpdateIndexRequest.deserializeBinaryFromReader
|
||||
reader.readMessage(value,cc_arduino_cli_commands_v1_common_pb.Instance.deserializeBinaryFromReader);
|
||||
msg.setInstance(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setIgnoreCustomPackageIndexes(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
@ -1890,6 +1895,13 @@ proto.cc.arduino.cli.commands.v1.UpdateIndexRequest.serializeBinaryToWriter = fu
|
||||
cc_arduino_cli_commands_v1_common_pb.Instance.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getIgnoreCustomPackageIndexes();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1930,6 +1942,24 @@ proto.cc.arduino.cli.commands.v1.UpdateIndexRequest.prototype.hasInstance = func
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool ignore_custom_package_indexes = 2;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.UpdateIndexRequest.prototype.getIgnoreCustomPackageIndexes = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.UpdateIndexRequest} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.UpdateIndexRequest.prototype.setIgnoreCustomPackageIndexes = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -28,21 +28,26 @@ export namespace Instance {
|
||||
}
|
||||
|
||||
export class DownloadProgress extends jspb.Message {
|
||||
getUrl(): string;
|
||||
setUrl(value: string): DownloadProgress;
|
||||
|
||||
getFile(): string;
|
||||
setFile(value: string): DownloadProgress;
|
||||
hasStart(): boolean;
|
||||
clearStart(): void;
|
||||
getStart(): DownloadProgressStart | undefined;
|
||||
setStart(value?: DownloadProgressStart): DownloadProgress;
|
||||
|
||||
getTotalSize(): number;
|
||||
setTotalSize(value: number): DownloadProgress;
|
||||
|
||||
getDownloaded(): number;
|
||||
setDownloaded(value: number): DownloadProgress;
|
||||
hasUpdate(): boolean;
|
||||
clearUpdate(): void;
|
||||
getUpdate(): DownloadProgressUpdate | undefined;
|
||||
setUpdate(value?: DownloadProgressUpdate): DownloadProgress;
|
||||
|
||||
getCompleted(): boolean;
|
||||
setCompleted(value: boolean): DownloadProgress;
|
||||
|
||||
hasEnd(): boolean;
|
||||
clearEnd(): void;
|
||||
getEnd(): DownloadProgressEnd | undefined;
|
||||
setEnd(value?: DownloadProgressEnd): DownloadProgress;
|
||||
|
||||
|
||||
getMessageCase(): DownloadProgress.MessageCase;
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): DownloadProgress.AsObject;
|
||||
@ -55,12 +60,97 @@ export class DownloadProgress extends jspb.Message {
|
||||
}
|
||||
|
||||
export namespace DownloadProgress {
|
||||
export type AsObject = {
|
||||
start?: DownloadProgressStart.AsObject,
|
||||
update?: DownloadProgressUpdate.AsObject,
|
||||
end?: DownloadProgressEnd.AsObject,
|
||||
}
|
||||
|
||||
export enum MessageCase {
|
||||
MESSAGE_NOT_SET = 0,
|
||||
|
||||
START = 1,
|
||||
|
||||
UPDATE = 2,
|
||||
|
||||
END = 3,
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class DownloadProgressStart extends jspb.Message {
|
||||
getUrl(): string;
|
||||
setUrl(value: string): DownloadProgressStart;
|
||||
|
||||
getLabel(): string;
|
||||
setLabel(value: string): DownloadProgressStart;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): DownloadProgressStart.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: DownloadProgressStart): DownloadProgressStart.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: DownloadProgressStart, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): DownloadProgressStart;
|
||||
static deserializeBinaryFromReader(message: DownloadProgressStart, reader: jspb.BinaryReader): DownloadProgressStart;
|
||||
}
|
||||
|
||||
export namespace DownloadProgressStart {
|
||||
export type AsObject = {
|
||||
url: string,
|
||||
file: string,
|
||||
totalSize: number,
|
||||
label: string,
|
||||
}
|
||||
}
|
||||
|
||||
export class DownloadProgressUpdate extends jspb.Message {
|
||||
getDownloaded(): number;
|
||||
setDownloaded(value: number): DownloadProgressUpdate;
|
||||
|
||||
getTotalSize(): number;
|
||||
setTotalSize(value: number): DownloadProgressUpdate;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): DownloadProgressUpdate.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: DownloadProgressUpdate): DownloadProgressUpdate.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: DownloadProgressUpdate, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): DownloadProgressUpdate;
|
||||
static deserializeBinaryFromReader(message: DownloadProgressUpdate, reader: jspb.BinaryReader): DownloadProgressUpdate;
|
||||
}
|
||||
|
||||
export namespace DownloadProgressUpdate {
|
||||
export type AsObject = {
|
||||
downloaded: number,
|
||||
completed: boolean,
|
||||
totalSize: number,
|
||||
}
|
||||
}
|
||||
|
||||
export class DownloadProgressEnd extends jspb.Message {
|
||||
getSuccess(): boolean;
|
||||
setSuccess(value: boolean): DownloadProgressEnd;
|
||||
|
||||
getMessage(): string;
|
||||
setMessage(value: string): DownloadProgressEnd;
|
||||
|
||||
|
||||
serializeBinary(): Uint8Array;
|
||||
toObject(includeInstance?: boolean): DownloadProgressEnd.AsObject;
|
||||
static toObject(includeInstance: boolean, msg: DownloadProgressEnd): DownloadProgressEnd.AsObject;
|
||||
static extensions: {[key: number]: jspb.ExtensionFieldInfo<jspb.Message>};
|
||||
static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo<jspb.Message>};
|
||||
static serializeBinaryToWriter(message: DownloadProgressEnd, writer: jspb.BinaryWriter): void;
|
||||
static deserializeBinary(bytes: Uint8Array): DownloadProgressEnd;
|
||||
static deserializeBinaryFromReader(message: DownloadProgressEnd, reader: jspb.BinaryReader): DownloadProgressEnd;
|
||||
}
|
||||
|
||||
export namespace DownloadProgressEnd {
|
||||
export type AsObject = {
|
||||
success: boolean,
|
||||
message: string,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,10 @@ var global = Function('return this')();
|
||||
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.v1.Board', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.v1.DownloadProgress', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.v1.DownloadProgress.MessageCase', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.v1.DownloadProgressEnd', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.v1.DownloadProgressStart', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.v1.InstalledPlatformReference', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.v1.Instance', null, global);
|
||||
goog.exportSymbol('proto.cc.arduino.cli.commands.v1.Platform', null, global);
|
||||
@ -55,7 +59,7 @@ if (goog.DEBUG && !COMPILED) {
|
||||
* @constructor
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, proto.cc.arduino.cli.commands.v1.DownloadProgress.oneofGroups_);
|
||||
};
|
||||
goog.inherits(proto.cc.arduino.cli.commands.v1.DownloadProgress, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
@ -65,6 +69,69 @@ if (goog.DEBUG && !COMPILED) {
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.displayName = 'proto.cc.arduino.cli.commands.v1.DownloadProgress';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.cc.arduino.cli.commands.v1.DownloadProgressStart, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.displayName = 'proto.cc.arduino.cli.commands.v1.DownloadProgressStart';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.displayName = 'proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
* server response, or constructed directly in Javascript. The array is used
|
||||
* in place and becomes part of the constructed object. It is not cloned.
|
||||
* If no data is provided, the constructed object will be empty, but still
|
||||
* valid.
|
||||
* @extends {jspb.Message}
|
||||
* @constructor
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd = function(opt_data) {
|
||||
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
|
||||
};
|
||||
goog.inherits(proto.cc.arduino.cli.commands.v1.DownloadProgressEnd, jspb.Message);
|
||||
if (goog.DEBUG && !COMPILED) {
|
||||
/**
|
||||
* @public
|
||||
* @override
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.displayName = 'proto.cc.arduino.cli.commands.v1.DownloadProgressEnd';
|
||||
}
|
||||
/**
|
||||
* Generated by JsPbCodeGenerator.
|
||||
* @param {Array=} opt_data Optional initial data array, typically from a
|
||||
@ -322,6 +389,33 @@ proto.cc.arduino.cli.commands.v1.Instance.prototype.setId = function(value) {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Oneof group definitions for this message. Each group defines the field
|
||||
* numbers belonging to that group. When of these fields' value is set, all
|
||||
* other fields in the group are cleared. During deserialization, if multiple
|
||||
* fields are encountered for a group, only the last value seen will be kept.
|
||||
* @private {!Array<!Array<number>>}
|
||||
* @const
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.oneofGroups_ = [[1,2,3]];
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.MessageCase = {
|
||||
MESSAGE_NOT_SET: 0,
|
||||
START: 1,
|
||||
UPDATE: 2,
|
||||
END: 3
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {proto.cc.arduino.cli.commands.v1.DownloadProgress.MessageCase}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.getMessageCase = function() {
|
||||
return /** @type {proto.cc.arduino.cli.commands.v1.DownloadProgress.MessageCase} */(jspb.Message.computeOneofCase(this, proto.cc.arduino.cli.commands.v1.DownloadProgress.oneofGroups_[0]));
|
||||
};
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
@ -353,11 +447,9 @@ proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.toObject = function(
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
url: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
file: jspb.Message.getFieldWithDefault(msg, 2, ""),
|
||||
totalSize: jspb.Message.getFieldWithDefault(msg, 3, 0),
|
||||
downloaded: jspb.Message.getFieldWithDefault(msg, 4, 0),
|
||||
completed: jspb.Message.getBooleanFieldWithDefault(msg, 5, false)
|
||||
start: (f = msg.getStart()) && proto.cc.arduino.cli.commands.v1.DownloadProgressStart.toObject(includeInstance, f),
|
||||
update: (f = msg.getUpdate()) && proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.toObject(includeInstance, f),
|
||||
end: (f = msg.getEnd()) && proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.toObject(includeInstance, f)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
@ -395,24 +487,19 @@ proto.cc.arduino.cli.commands.v1.DownloadProgress.deserializeBinaryFromReader =
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setUrl(value);
|
||||
var value = new proto.cc.arduino.cli.commands.v1.DownloadProgressStart;
|
||||
reader.readMessage(value,proto.cc.arduino.cli.commands.v1.DownloadProgressStart.deserializeBinaryFromReader);
|
||||
msg.setStart(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setFile(value);
|
||||
var value = new proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate;
|
||||
reader.readMessage(value,proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.deserializeBinaryFromReader);
|
||||
msg.setUpdate(value);
|
||||
break;
|
||||
case 3:
|
||||
var value = /** @type {number} */ (reader.readInt64());
|
||||
msg.setTotalSize(value);
|
||||
break;
|
||||
case 4:
|
||||
var value = /** @type {number} */ (reader.readInt64());
|
||||
msg.setDownloaded(value);
|
||||
break;
|
||||
case 5:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setCompleted(value);
|
||||
var value = new proto.cc.arduino.cli.commands.v1.DownloadProgressEnd;
|
||||
reader.readMessage(value,proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.deserializeBinaryFromReader);
|
||||
msg.setEnd(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
@ -442,6 +529,251 @@ proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.serializeBinary = fu
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getStart();
|
||||
if (f != null) {
|
||||
writer.writeMessage(
|
||||
1,
|
||||
f,
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getUpdate();
|
||||
if (f != null) {
|
||||
writer.writeMessage(
|
||||
2,
|
||||
f,
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
f = message.getEnd();
|
||||
if (f != null) {
|
||||
writer.writeMessage(
|
||||
3,
|
||||
f,
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.serializeBinaryToWriter
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional DownloadProgressStart start = 1;
|
||||
* @return {?proto.cc.arduino.cli.commands.v1.DownloadProgressStart}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.getStart = function() {
|
||||
return /** @type{?proto.cc.arduino.cli.commands.v1.DownloadProgressStart} */ (
|
||||
jspb.Message.getWrapperField(this, proto.cc.arduino.cli.commands.v1.DownloadProgressStart, 1));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?proto.cc.arduino.cli.commands.v1.DownloadProgressStart|undefined} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.setStart = function(value) {
|
||||
return jspb.Message.setOneofWrapperField(this, 1, proto.cc.arduino.cli.commands.v1.DownloadProgress.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.clearStart = function() {
|
||||
return this.setStart(undefined);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.hasStart = function() {
|
||||
return jspb.Message.getField(this, 1) != null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional DownloadProgressUpdate update = 2;
|
||||
* @return {?proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.getUpdate = function() {
|
||||
return /** @type{?proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate} */ (
|
||||
jspb.Message.getWrapperField(this, proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate, 2));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate|undefined} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.setUpdate = function(value) {
|
||||
return jspb.Message.setOneofWrapperField(this, 2, proto.cc.arduino.cli.commands.v1.DownloadProgress.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.clearUpdate = function() {
|
||||
return this.setUpdate(undefined);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.hasUpdate = function() {
|
||||
return jspb.Message.getField(this, 2) != null;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional DownloadProgressEnd end = 3;
|
||||
* @return {?proto.cc.arduino.cli.commands.v1.DownloadProgressEnd}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.getEnd = function() {
|
||||
return /** @type{?proto.cc.arduino.cli.commands.v1.DownloadProgressEnd} */ (
|
||||
jspb.Message.getWrapperField(this, proto.cc.arduino.cli.commands.v1.DownloadProgressEnd, 3));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {?proto.cc.arduino.cli.commands.v1.DownloadProgressEnd|undefined} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.setEnd = function(value) {
|
||||
return jspb.Message.setOneofWrapperField(this, 3, proto.cc.arduino.cli.commands.v1.DownloadProgress.oneofGroups_[0], value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clears the message field making it undefined.
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.clearEnd = function() {
|
||||
return this.setEnd(undefined);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns whether this field is set.
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.hasEnd = function() {
|
||||
return jspb.Message.getField(this, 3) != null;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.cc.arduino.cli.commands.v1.DownloadProgressStart.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.cc.arduino.cli.commands.v1.DownloadProgressStart} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
url: jspb.Message.getFieldWithDefault(msg, 1, ""),
|
||||
label: jspb.Message.getFieldWithDefault(msg, 2, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressStart}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.cc.arduino.cli.commands.v1.DownloadProgressStart;
|
||||
return proto.cc.arduino.cli.commands.v1.DownloadProgressStart.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.cc.arduino.cli.commands.v1.DownloadProgressStart} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressStart}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setUrl(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setLabel(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.cc.arduino.cli.commands.v1.DownloadProgressStart} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getUrl();
|
||||
if (f.length > 0) {
|
||||
@ -450,34 +782,13 @@ proto.cc.arduino.cli.commands.v1.DownloadProgress.serializeBinaryToWriter = func
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getFile();
|
||||
f = message.getLabel();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getTotalSize();
|
||||
if (f !== 0) {
|
||||
writer.writeInt64(
|
||||
3,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getDownloaded();
|
||||
if (f !== 0) {
|
||||
writer.writeInt64(
|
||||
4,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getCompleted();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
5,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -485,89 +796,355 @@ proto.cc.arduino.cli.commands.v1.DownloadProgress.serializeBinaryToWriter = func
|
||||
* optional string url = 1;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.getUrl = function() {
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.prototype.getUrl = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressStart} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.setUrl = function(value) {
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.prototype.setUrl = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string file = 2;
|
||||
* optional string label = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.getFile = function() {
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.prototype.getLabel = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressStart} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.setFile = function(value) {
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressStart.prototype.setLabel = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* optional int64 total_size = 3;
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
downloaded: jspb.Message.getFieldWithDefault(msg, 1, 0),
|
||||
totalSize: jspb.Message.getFieldWithDefault(msg, 2, 0)
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate;
|
||||
return proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {number} */ (reader.readInt64());
|
||||
msg.setDownloaded(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {number} */ (reader.readInt64());
|
||||
msg.setTotalSize(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getDownloaded();
|
||||
if (f !== 0) {
|
||||
writer.writeInt64(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getTotalSize();
|
||||
if (f !== 0) {
|
||||
writer.writeInt64(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional int64 downloaded = 1;
|
||||
* @return {number}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.getTotalSize = function() {
|
||||
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 3, 0));
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.prototype.getDownloaded = function() {
|
||||
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.setTotalSize = function(value) {
|
||||
return jspb.Message.setProto3IntField(this, 3, value);
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.prototype.setDownloaded = function(value) {
|
||||
return jspb.Message.setProto3IntField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional int64 downloaded = 4;
|
||||
* optional int64 total_size = 2;
|
||||
* @return {number}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.getDownloaded = function() {
|
||||
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 4, 0));
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.prototype.getTotalSize = function() {
|
||||
return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.setDownloaded = function(value) {
|
||||
return jspb.Message.setProto3IntField(this, 4, value);
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressUpdate.prototype.setTotalSize = function(value) {
|
||||
return jspb.Message.setProto3IntField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (jspb.Message.GENERATE_TO_OBJECT) {
|
||||
/**
|
||||
* Creates an object representation of this proto.
|
||||
* Field names that are reserved in JavaScript and will be renamed to pb_name.
|
||||
* Optional fields that are not set will be set to undefined.
|
||||
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
|
||||
* For the list of reserved names please see:
|
||||
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
|
||||
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
|
||||
* JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @return {!Object}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.prototype.toObject = function(opt_includeInstance) {
|
||||
return proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.toObject(opt_includeInstance, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool completed = 5;
|
||||
* Static version of the {@see toObject} method.
|
||||
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
|
||||
* the JSPB instance for transitional soy proto support:
|
||||
* http://goto/soy-param-migration
|
||||
* @param {!proto.cc.arduino.cli.commands.v1.DownloadProgressEnd} msg The msg instance to transform.
|
||||
* @return {!Object}
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.toObject = function(includeInstance, msg) {
|
||||
var f, obj = {
|
||||
success: jspb.Message.getBooleanFieldWithDefault(msg, 1, false),
|
||||
message: jspb.Message.getFieldWithDefault(msg, 2, "")
|
||||
};
|
||||
|
||||
if (includeInstance) {
|
||||
obj.$jspbMessageInstance = msg;
|
||||
}
|
||||
return obj;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format).
|
||||
* @param {jspb.ByteSource} bytes The bytes to deserialize.
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressEnd}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.deserializeBinary = function(bytes) {
|
||||
var reader = new jspb.BinaryReader(bytes);
|
||||
var msg = new proto.cc.arduino.cli.commands.v1.DownloadProgressEnd;
|
||||
return proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.deserializeBinaryFromReader(msg, reader);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Deserializes binary data (in protobuf wire format) from the
|
||||
* given reader into the given message object.
|
||||
* @param {!proto.cc.arduino.cli.commands.v1.DownloadProgressEnd} msg The message object to deserialize into.
|
||||
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressEnd}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.deserializeBinaryFromReader = function(msg, reader) {
|
||||
while (reader.nextField()) {
|
||||
if (reader.isEndGroup()) {
|
||||
break;
|
||||
}
|
||||
var field = reader.getFieldNumber();
|
||||
switch (field) {
|
||||
case 1:
|
||||
var value = /** @type {boolean} */ (reader.readBool());
|
||||
msg.setSuccess(value);
|
||||
break;
|
||||
case 2:
|
||||
var value = /** @type {string} */ (reader.readString());
|
||||
msg.setMessage(value);
|
||||
break;
|
||||
default:
|
||||
reader.skipField();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the message to binary data (in protobuf wire format).
|
||||
* @return {!Uint8Array}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.prototype.serializeBinary = function() {
|
||||
var writer = new jspb.BinaryWriter();
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.serializeBinaryToWriter(this, writer);
|
||||
return writer.getResultBuffer();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Serializes the given message to binary data (in protobuf wire
|
||||
* format), writing to the given BinaryWriter.
|
||||
* @param {!proto.cc.arduino.cli.commands.v1.DownloadProgressEnd} message
|
||||
* @param {!jspb.BinaryWriter} writer
|
||||
* @suppress {unusedLocalVariables} f is only used for nested messages
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.serializeBinaryToWriter = function(message, writer) {
|
||||
var f = undefined;
|
||||
f = message.getSuccess();
|
||||
if (f) {
|
||||
writer.writeBool(
|
||||
1,
|
||||
f
|
||||
);
|
||||
}
|
||||
f = message.getMessage();
|
||||
if (f.length > 0) {
|
||||
writer.writeString(
|
||||
2,
|
||||
f
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional bool success = 1;
|
||||
* @return {boolean}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.getCompleted = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 5, false));
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.prototype.getSuccess = function() {
|
||||
return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgress} returns this
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressEnd} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgress.prototype.setCompleted = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 5, value);
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.prototype.setSuccess = function(value) {
|
||||
return jspb.Message.setProto3BooleanField(this, 1, value);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* optional string message = 2;
|
||||
* @return {string}
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.prototype.getMessage = function() {
|
||||
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, ""));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {!proto.cc.arduino.cli.commands.v1.DownloadProgressEnd} returns this
|
||||
*/
|
||||
proto.cc.arduino.cli.commands.v1.DownloadProgressEnd.prototype.setMessage = function(value) {
|
||||
return jspb.Message.setProto3StringField(this, 2, value);
|
||||
};
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
injectable,
|
||||
postConstruct,
|
||||
} from '@theia/core/shared/inversify';
|
||||
import { Emitter, Event } from '@theia/core/lib/common/event';
|
||||
import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { ArduinoCoreServiceClient } from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb';
|
||||
import { Instance } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb';
|
||||
import {
|
||||
@ -19,8 +19,15 @@ import {
|
||||
UpdateLibrariesIndexResponse,
|
||||
} from './cli-protocol/cc/arduino/cli/commands/v1/commands_pb';
|
||||
import * as commandsGrpcPb from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb';
|
||||
import { NotificationServiceServer } from '../common/protocol';
|
||||
import { Deferred, retry } from '@theia/core/lib/common/promise-util';
|
||||
import {
|
||||
IndexType,
|
||||
IndexUpdateDidCompleteParams,
|
||||
IndexUpdateSummary,
|
||||
IndexUpdateDidFailParams,
|
||||
IndexUpdateWillStartParams,
|
||||
NotificationServiceServer,
|
||||
} from '../common/protocol';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import {
|
||||
Status as RpcStatus,
|
||||
Status,
|
||||
@ -32,6 +39,7 @@ import { Disposable } from '@theia/core/shared/vscode-languageserver-protocol';
|
||||
import {
|
||||
IndexesUpdateProgressHandler,
|
||||
ExecuteWithProgress,
|
||||
DownloadResult,
|
||||
} from './grpc-progressible';
|
||||
import type { DefaultCliConfig } from './cli-config';
|
||||
import { ServiceError } from './service-error';
|
||||
@ -45,16 +53,19 @@ export class CoreClientProvider {
|
||||
@inject(NotificationServiceServer)
|
||||
private readonly notificationService: NotificationServiceServer;
|
||||
|
||||
private ready = new Deferred<void>();
|
||||
private pending: Deferred<CoreClientProvider.Client> | undefined;
|
||||
private _client: CoreClientProvider.Client | undefined;
|
||||
private readonly toDisposeBeforeCreate = new DisposableCollection();
|
||||
/**
|
||||
* See `CoreService#indexUpdateSummaryBeforeInit`.
|
||||
*/
|
||||
private readonly beforeInitSummary = {} as IndexUpdateSummary;
|
||||
private readonly toDisposeOnCloseClient = new DisposableCollection();
|
||||
private readonly toDisposeAfterDidCreate = new DisposableCollection();
|
||||
private readonly onClientReadyEmitter =
|
||||
new Emitter<CoreClientProvider.Client>();
|
||||
private readonly onClientReady = this.onClientReadyEmitter.event;
|
||||
private readonly onClientDidRefreshEmitter =
|
||||
new Emitter<CoreClientProvider.Client>();
|
||||
|
||||
private ready = new Deferred<void>();
|
||||
private pending: Deferred<CoreClientProvider.Client> | undefined;
|
||||
private _client: CoreClientProvider.Client | undefined;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
@ -65,7 +76,9 @@ export class CoreClientProvider {
|
||||
});
|
||||
this.daemon.onDaemonStarted((port) => this.create(port));
|
||||
this.daemon.onDaemonStopped(() => this.closeClient());
|
||||
this.configService.onConfigChange(() => this.refreshIndexes());
|
||||
this.configService.onConfigChange(
|
||||
() => this.client.then((client) => this.updateIndex(client, ['platform'])) // Assuming 3rd party URL changes. No library index update is required.
|
||||
);
|
||||
}
|
||||
|
||||
get tryGetClient(): CoreClientProvider.Client | undefined {
|
||||
@ -80,7 +93,7 @@ export class CoreClientProvider {
|
||||
if (!this.pending) {
|
||||
this.pending = new Deferred();
|
||||
this.toDisposeAfterDidCreate.pushAll([
|
||||
Disposable.create(() => (this.pending = undefined)),
|
||||
Disposable.create(() => (this.pending = undefined)), // TODO: reject all pending requests before unsetting the ref?
|
||||
this.onClientReady((client) => {
|
||||
this.pending?.resolve(client);
|
||||
this.toDisposeAfterDidCreate.dispose();
|
||||
@ -90,10 +103,6 @@ export class CoreClientProvider {
|
||||
return this.pending.promise;
|
||||
}
|
||||
|
||||
get onClientDidRefresh(): Event<CoreClientProvider.Client> {
|
||||
return this.onClientDidRefreshEmitter.event;
|
||||
}
|
||||
|
||||
async refresh(): Promise<void> {
|
||||
const client = await this.client;
|
||||
await this.initInstance(client);
|
||||
@ -106,7 +115,7 @@ export class CoreClientProvider {
|
||||
this.closeClient();
|
||||
const address = this.address(port);
|
||||
const client = await this.createClient(address);
|
||||
this.toDisposeBeforeCreate.pushAll([
|
||||
this.toDisposeOnCloseClient.pushAll([
|
||||
Disposable.create(() => client.client.close()),
|
||||
Disposable.create(() => {
|
||||
this.ready.reject(
|
||||
@ -118,7 +127,6 @@ export class CoreClientProvider {
|
||||
}),
|
||||
]);
|
||||
await this.initInstanceWithFallback(client);
|
||||
setTimeout(async () => this.refreshIndexes(), 10_000); // Update the indexes asynchronously
|
||||
return this.useClient(client);
|
||||
}
|
||||
|
||||
@ -141,12 +149,17 @@ export class CoreClientProvider {
|
||||
try {
|
||||
await this.initInstance(client);
|
||||
} catch (err) {
|
||||
if (err instanceof IndexUpdateRequiredBeforeInitError) {
|
||||
if (err instanceof MustUpdateIndexesBeforeInitError) {
|
||||
console.error(
|
||||
'The primary packages indexes are missing. Running indexes update before initializing the core gRPC client',
|
||||
err.message
|
||||
);
|
||||
await this.updateIndexes(client); // TODO: this should run without the 3rd party URLs
|
||||
await this.updateIndex(client, Array.from(err.indexTypesToUpdate));
|
||||
const updatedAt = new Date().toISOString();
|
||||
// Clients will ask for it after they connect.
|
||||
err.indexTypesToUpdate.forEach(
|
||||
(type) => (this.beforeInitSummary[type] = updatedAt)
|
||||
);
|
||||
await this.initInstance(client);
|
||||
console.info(
|
||||
`Downloaded the primary package indexes, and successfully initialized the core gRPC client.`
|
||||
@ -170,7 +183,7 @@ export class CoreClientProvider {
|
||||
}
|
||||
|
||||
private closeClient(): void {
|
||||
return this.toDisposeBeforeCreate.dispose();
|
||||
return this.toDisposeOnCloseClient.dispose();
|
||||
}
|
||||
|
||||
private async createClient(
|
||||
@ -253,45 +266,66 @@ export class CoreClientProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates all indexes and runs an init to [reload the indexes](https://github.com/arduino/arduino-cli/pull/1274#issue-866154638).
|
||||
* `update3rdPartyPlatforms` has not effect if `types` is `['library']`.
|
||||
*/
|
||||
private async refreshIndexes(): Promise<void> {
|
||||
const client = this._client;
|
||||
if (client) {
|
||||
const progressHandler = this.createProgressHandler();
|
||||
try {
|
||||
await this.updateIndexes(client, progressHandler);
|
||||
async updateIndex(
|
||||
client: CoreClientProvider.Client,
|
||||
types: IndexType[]
|
||||
): Promise<void> {
|
||||
let error: unknown | undefined = undefined;
|
||||
const progressHandler = this.createProgressHandler(types);
|
||||
try {
|
||||
const updates: Promise<void>[] = [];
|
||||
if (types.includes('platform')) {
|
||||
updates.push(this.updatePlatformIndex(client, progressHandler));
|
||||
}
|
||||
if (types.includes('library')) {
|
||||
updates.push(this.updateLibraryIndex(client, progressHandler));
|
||||
}
|
||||
await Promise.all(updates);
|
||||
} catch (err) {
|
||||
// This is suboptimal but the core client must be re-initialized even if the index update has failed and the request was rejected.
|
||||
error = err;
|
||||
} finally {
|
||||
// IDE2 reloads the index only and if only at least one download success is available.
|
||||
if (
|
||||
progressHandler.results.some(
|
||||
(result) => !DownloadResult.isError(result)
|
||||
)
|
||||
) {
|
||||
await this.initInstance(client);
|
||||
// notify clients about the index update only after the client has been "re-initialized" and the new content is available.
|
||||
progressHandler.reportEnd();
|
||||
this.onClientDidRefreshEmitter.fire(client);
|
||||
} catch (err) {
|
||||
console.error('Failed to update indexes', err);
|
||||
progressHandler.reportError(
|
||||
ServiceError.is(err) ? err.details : String(err)
|
||||
);
|
||||
}
|
||||
if (error) {
|
||||
console.error(`Failed to update ${types.join(', ')} indexes.`, error);
|
||||
const downloadErrors = progressHandler.results
|
||||
.filter(DownloadResult.isError)
|
||||
.map(({ url, message }) => `${message}: ${url}`)
|
||||
.join(' ');
|
||||
const message = ServiceError.is(error)
|
||||
? `${error.details}${downloadErrors ? ` ${downloadErrors}` : ''}`
|
||||
: String(error);
|
||||
// IDE2 keeps only the most recent error message. Previous errors might have been fixed with the fallback initialization.
|
||||
this.beforeInitSummary.message = message;
|
||||
// Toast the error message, so tha the user has chance to fix it if it was a client error (HTTP 4xx).
|
||||
progressHandler.reportError(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async updateIndexes(
|
||||
client: CoreClientProvider.Client,
|
||||
progressHandler?: IndexesUpdateProgressHandler
|
||||
): Promise<void> {
|
||||
await Promise.all([
|
||||
this.updateIndex(client, progressHandler),
|
||||
this.updateLibraryIndex(client, progressHandler),
|
||||
]);
|
||||
get indexUpdateSummaryBeforeInit(): IndexUpdateSummary {
|
||||
return { ...this.beforeInitSummary };
|
||||
}
|
||||
|
||||
private async updateIndex(
|
||||
private async updatePlatformIndex(
|
||||
client: CoreClientProvider.Client,
|
||||
progressHandler?: IndexesUpdateProgressHandler
|
||||
): Promise<void> {
|
||||
return this.doUpdateIndex(
|
||||
() =>
|
||||
client.client.updateIndex(
|
||||
new UpdateIndexRequest().setInstance(client.instance)
|
||||
new UpdateIndexRequest().setInstance(client.instance) // Always updates both the primary and the 3rd party package indexes.
|
||||
),
|
||||
progressHandler,
|
||||
'platform-index'
|
||||
@ -323,50 +357,45 @@ export class CoreClientProvider {
|
||||
task?: string
|
||||
): Promise<void> {
|
||||
const progressId = progressHandler?.progressId;
|
||||
return retry(
|
||||
() =>
|
||||
new Promise<void>((resolve, reject) => {
|
||||
responseProvider()
|
||||
.on(
|
||||
'data',
|
||||
ExecuteWithProgress.createDataCallback({
|
||||
responseService: {
|
||||
appendToOutput: ({ chunk: message }) => {
|
||||
console.log(
|
||||
`core-client-provider${task ? ` [${task}]` : ''}`,
|
||||
message
|
||||
);
|
||||
progressHandler?.reportProgress(message);
|
||||
},
|
||||
},
|
||||
progressId,
|
||||
})
|
||||
)
|
||||
.on('error', reject)
|
||||
.on('end', resolve);
|
||||
}),
|
||||
50,
|
||||
3
|
||||
);
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
responseProvider()
|
||||
.on(
|
||||
'data',
|
||||
ExecuteWithProgress.createDataCallback({
|
||||
responseService: {
|
||||
appendToOutput: ({ chunk: message }) => {
|
||||
console.log(
|
||||
`core-client-provider${task ? ` [${task}]` : ''}`,
|
||||
message
|
||||
);
|
||||
progressHandler?.reportProgress(message);
|
||||
},
|
||||
reportResult: (result) => progressHandler?.reportResult(result),
|
||||
},
|
||||
progressId,
|
||||
})
|
||||
)
|
||||
.on('error', reject)
|
||||
.on('end', resolve);
|
||||
});
|
||||
}
|
||||
|
||||
private createProgressHandler(): IndexesUpdateProgressHandler {
|
||||
private createProgressHandler(
|
||||
types: IndexType[]
|
||||
): IndexesUpdateProgressHandler {
|
||||
const additionalUrlsCount =
|
||||
this.configService.cliConfiguration?.board_manager?.additional_urls
|
||||
?.length ?? 0;
|
||||
return new IndexesUpdateProgressHandler(
|
||||
additionalUrlsCount,
|
||||
(progressMessage) =>
|
||||
return new IndexesUpdateProgressHandler(types, additionalUrlsCount, {
|
||||
onProgress: (progressMessage) =>
|
||||
this.notificationService.notifyIndexUpdateDidProgress(progressMessage),
|
||||
({ progressId, message }) =>
|
||||
this.notificationService.notifyIndexUpdateDidFail({
|
||||
progressId,
|
||||
message,
|
||||
}),
|
||||
(progressId) =>
|
||||
this.notificationService.notifyIndexWillUpdate(progressId),
|
||||
(progressId) => this.notificationService.notifyIndexDidUpdate(progressId)
|
||||
);
|
||||
onError: (params: IndexUpdateDidFailParams) =>
|
||||
this.notificationService.notifyIndexUpdateDidFail(params),
|
||||
onStart: (params: IndexUpdateWillStartParams) =>
|
||||
this.notificationService.notifyIndexUpdateWillStart(params),
|
||||
onComplete: (params: IndexUpdateDidCompleteParams) =>
|
||||
this.notificationService.notifyIndexUpdateDidComplete(params),
|
||||
});
|
||||
}
|
||||
|
||||
private address(port: string): string {
|
||||
@ -410,6 +439,7 @@ export namespace CoreClientProvider {
|
||||
export abstract class CoreClientAware {
|
||||
@inject(CoreClientProvider)
|
||||
private readonly coreClientProvider: CoreClientProvider;
|
||||
|
||||
/**
|
||||
* Returns with a promise that resolves when the core client is initialized and ready.
|
||||
*/
|
||||
@ -417,8 +447,17 @@ export abstract class CoreClientAware {
|
||||
return this.coreClientProvider.client;
|
||||
}
|
||||
|
||||
protected get onClientDidRefresh(): Event<CoreClientProvider.Client> {
|
||||
return this.coreClientProvider.onClientDidRefresh;
|
||||
/**
|
||||
* Updates the index of the given `type` and returns with a promise which resolves when the core gPRC client has been reinitialized.
|
||||
*/
|
||||
async updateIndex({ types }: { types: IndexType[] }): Promise<void> {
|
||||
const client = await this.coreClient;
|
||||
return this.coreClientProvider.updateIndex(client, types);
|
||||
}
|
||||
|
||||
async indexUpdateSummaryBeforeInit(): Promise<IndexUpdateSummary> {
|
||||
await this.coreClient;
|
||||
return this.coreClientProvider.indexUpdateSummaryBeforeInit;
|
||||
}
|
||||
|
||||
refresh(): Promise<void> {
|
||||
@ -426,15 +465,20 @@ export abstract class CoreClientAware {
|
||||
}
|
||||
}
|
||||
|
||||
class IndexUpdateRequiredBeforeInitError extends Error {
|
||||
constructor(causes: RpcStatus.AsObject[]) {
|
||||
class MustUpdateIndexesBeforeInitError extends Error {
|
||||
readonly indexTypesToUpdate: Set<IndexType>;
|
||||
constructor(causes: [RpcStatus.AsObject, IndexType][]) {
|
||||
super(`The index of the cores and libraries must be updated before initializing the core gRPC client.
|
||||
The following problems were detected during the gRPC client initialization:
|
||||
${causes
|
||||
.map(({ code, message }) => ` - code: ${code}, message: ${message}`)
|
||||
.map(
|
||||
([{ code, message }, type]) =>
|
||||
`[${type}-index] - code: ${code}, message: ${message}`
|
||||
)
|
||||
.join('\n')}
|
||||
`);
|
||||
Object.setPrototypeOf(this, IndexUpdateRequiredBeforeInitError.prototype);
|
||||
Object.setPrototypeOf(this, MustUpdateIndexesBeforeInitError.prototype);
|
||||
this.indexTypesToUpdate = new Set(causes.map(([, type]) => type));
|
||||
if (!causes.length) {
|
||||
throw new Error(`expected non-empty 'causes'`);
|
||||
}
|
||||
@ -444,41 +488,66 @@ ${causes
|
||||
function isIndexUpdateRequiredBeforeInit(
|
||||
status: RpcStatus[],
|
||||
cliConfig: DefaultCliConfig
|
||||
): IndexUpdateRequiredBeforeInitError | undefined {
|
||||
const causes = status
|
||||
.filter((s) =>
|
||||
IndexUpdateRequiredBeforeInit.map((predicate) =>
|
||||
predicate(s, cliConfig)
|
||||
).some(Boolean)
|
||||
)
|
||||
.map((s) => RpcStatus.toObject(false, s));
|
||||
): MustUpdateIndexesBeforeInitError | undefined {
|
||||
const causes = status.reduce((acc, curr) => {
|
||||
for (const [predicate, type] of IndexUpdateRequiredPredicates) {
|
||||
if (predicate(curr, cliConfig)) {
|
||||
acc.push([curr.toObject(false), type]);
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, [] as [RpcStatus.AsObject, IndexType][]);
|
||||
return causes.length
|
||||
? new IndexUpdateRequiredBeforeInitError(causes)
|
||||
? new MustUpdateIndexesBeforeInitError(causes)
|
||||
: undefined;
|
||||
}
|
||||
const IndexUpdateRequiredBeforeInit = [
|
||||
isPackageIndexMissingStatus,
|
||||
isDiscoveryNotFoundStatus,
|
||||
interface Predicate {
|
||||
(
|
||||
status: RpcStatus,
|
||||
{
|
||||
directories: { data },
|
||||
}: DefaultCliConfig
|
||||
): boolean;
|
||||
}
|
||||
const IndexUpdateRequiredPredicates: [Predicate, IndexType][] = [
|
||||
[isPrimaryPackageIndexMissingStatus, 'platform'],
|
||||
[isDiscoveryNotFoundStatus, 'platform'],
|
||||
[isLibraryIndexMissingStatus, 'library'],
|
||||
];
|
||||
function isPackageIndexMissingStatus(
|
||||
// Loading index file: loading json index file /path/to/package_index.json: open /path/to/package_index.json: no such file or directory
|
||||
function isPrimaryPackageIndexMissingStatus(
|
||||
status: RpcStatus,
|
||||
{ directories: { data } }: DefaultCliConfig
|
||||
): boolean {
|
||||
const predicate = ({ message }: RpcStatus.AsObject) =>
|
||||
message.includes('loading json index file') &&
|
||||
(message.includes(join(data, 'package_index.json')) ||
|
||||
message.includes(join(data, 'library_index.json')));
|
||||
message.includes(join(data, 'package_index.json'));
|
||||
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/package_manager.go#L247
|
||||
return evaluate(status, predicate);
|
||||
}
|
||||
// Error loading hardware platform: discovery $TOOL_NAME not found
|
||||
function isDiscoveryNotFoundStatus(status: RpcStatus): boolean {
|
||||
const predicate = ({ message }: RpcStatus.AsObject) =>
|
||||
message.includes('discovery') &&
|
||||
(message.includes('not found') || message.includes('not installed'));
|
||||
(message.includes('not found') ||
|
||||
message.includes('loading hardware platform'));
|
||||
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/loader.go#L740
|
||||
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/loader.go#L744
|
||||
return evaluate(status, predicate);
|
||||
}
|
||||
// Loading index file: reading library_index.json: open /path/to/library_index.json: no such file or directory
|
||||
function isLibraryIndexMissingStatus(
|
||||
status: RpcStatus,
|
||||
{ directories: { data } }: DefaultCliConfig
|
||||
): boolean {
|
||||
const predicate = ({ message }: RpcStatus.AsObject) =>
|
||||
message.includes('index file') &&
|
||||
message.includes('reading') &&
|
||||
message.includes(join(data, 'library_index.json'));
|
||||
// https://github.com/arduino/arduino-cli/blob/f0245bc2da6a56fccea7b2c9ea09e85fdcc52cb8/arduino/cores/packagemanager/package_manager.go#L247
|
||||
return evaluate(status, predicate);
|
||||
}
|
||||
function evaluate(
|
||||
subject: RpcStatus,
|
||||
predicate: (error: RpcStatus.AsObject) => boolean
|
||||
|
@ -1,4 +1,11 @@
|
||||
import { v4 } from 'uuid';
|
||||
import {
|
||||
IndexType,
|
||||
IndexUpdateDidCompleteParams,
|
||||
IndexUpdateDidFailParams,
|
||||
IndexUpdateSummary,
|
||||
IndexUpdateWillStartParams,
|
||||
} from '../common/protocol';
|
||||
import {
|
||||
ProgressMessage,
|
||||
ResponseService,
|
||||
@ -11,6 +18,9 @@ import {
|
||||
import {
|
||||
DownloadProgress,
|
||||
TaskProgress,
|
||||
DownloadProgressStart,
|
||||
DownloadProgressUpdate,
|
||||
DownloadProgressEnd,
|
||||
} from './cli-protocol/cc/arduino/cli/commands/v1/common_pb';
|
||||
import { CompileResponse } from './cli-protocol/cc/arduino/cli/commands/v1/compile_pb';
|
||||
import {
|
||||
@ -81,7 +91,9 @@ namespace IndexProgressResponse {
|
||||
);
|
||||
}
|
||||
export function workUnit(response: IndexProgressResponse): UnitOfWork {
|
||||
return { download: response.getDownloadProgress() };
|
||||
return {
|
||||
download: response.getDownloadProgress(),
|
||||
};
|
||||
}
|
||||
}
|
||||
/**
|
||||
@ -151,7 +163,9 @@ export namespace ExecuteWithProgress {
|
||||
* _unknown_ progress if falsy.
|
||||
*/
|
||||
readonly progressId?: string;
|
||||
readonly responseService: Partial<ResponseService>;
|
||||
readonly responseService: Partial<
|
||||
ResponseService & { reportResult: (result: DownloadResult) => void }
|
||||
>;
|
||||
}
|
||||
|
||||
export function createDataCallback<R extends ProgressResponse>({
|
||||
@ -159,19 +173,21 @@ export namespace ExecuteWithProgress {
|
||||
progressId,
|
||||
}: ExecuteWithProgress.Options): (response: R) => void {
|
||||
const uuid = v4();
|
||||
let localFile = '';
|
||||
let localTotalSize = Number.NaN;
|
||||
let message = '';
|
||||
let url = '';
|
||||
return (response: R) => {
|
||||
if (DEBUG) {
|
||||
const json = toJson(response);
|
||||
if (json) {
|
||||
console.log(`Progress response [${uuid}]: ${json}`);
|
||||
console.debug(`[gRPC progress] Progress response [${uuid}]: ${json}`);
|
||||
}
|
||||
}
|
||||
const unitOfWork = resolve(response);
|
||||
const { task, download } = unitOfWork;
|
||||
if (!download && !task) {
|
||||
// report a fake unknown progress.
|
||||
// Report a fake unknown progress if progress ID is available.
|
||||
// When a progress ID is available, a connected client is setting the progress ID.
|
||||
// Hence, it's listening to progress updates.
|
||||
if (unitOfWork === UnitOfWork.Unknown && progressId) {
|
||||
if (progressId) {
|
||||
responseService.reportProgress?.({
|
||||
@ -187,7 +203,7 @@ export namespace ExecuteWithProgress {
|
||||
// Technically, it does not cause an error, but could mess up the progress reporting.
|
||||
// See an example of an empty object `{}` repose here: https://github.com/arduino/arduino-ide/issues/906#issuecomment-1171145630.
|
||||
console.warn(
|
||||
"Implementation error. Neither 'download' nor 'task' is available."
|
||||
`Implementation error. None of the following properties were available on the response: 'task', 'download'`
|
||||
);
|
||||
}
|
||||
return;
|
||||
@ -219,43 +235,32 @@ export namespace ExecuteWithProgress {
|
||||
}
|
||||
}
|
||||
} else if (download) {
|
||||
if (download.getFile() && !localFile) {
|
||||
localFile = download.getFile();
|
||||
}
|
||||
if (download.getTotalSize() > 0 && Number.isNaN(localTotalSize)) {
|
||||
localTotalSize = download.getTotalSize();
|
||||
}
|
||||
|
||||
// This happens only once per file download.
|
||||
if (download.getTotalSize() && localFile) {
|
||||
responseService.appendToOutput?.({ chunk: `${localFile}\n` });
|
||||
}
|
||||
|
||||
if (progressId && localFile) {
|
||||
let work: ProgressMessage.Work | undefined = undefined;
|
||||
if (download.getDownloaded() > 0 && !Number.isNaN(localTotalSize)) {
|
||||
work = {
|
||||
total: localTotalSize,
|
||||
done: download.getDownloaded(),
|
||||
};
|
||||
}
|
||||
responseService.reportProgress?.({
|
||||
progressId,
|
||||
message: `Downloading ${localFile}`,
|
||||
work,
|
||||
});
|
||||
}
|
||||
if (download.getCompleted()) {
|
||||
// Discard local state.
|
||||
if (progressId && !Number.isNaN(localTotalSize)) {
|
||||
const phase = phaseOf(download);
|
||||
if (phase instanceof DownloadProgressStart) {
|
||||
message = phase.getLabel();
|
||||
url = phase.getUrl();
|
||||
responseService.appendToOutput?.({ chunk: `${message}\n` });
|
||||
} else if (phase instanceof DownloadProgressUpdate) {
|
||||
if (progressId && message) {
|
||||
responseService.reportProgress?.({
|
||||
progressId,
|
||||
message: '',
|
||||
work: { done: Number.NaN, total: Number.NaN },
|
||||
message,
|
||||
work: {
|
||||
total: phase.getTotalSize(),
|
||||
done: phase.getDownloaded(),
|
||||
},
|
||||
});
|
||||
}
|
||||
localFile = '';
|
||||
localTotalSize = Number.NaN;
|
||||
} else if (phase instanceof DownloadProgressEnd) {
|
||||
if (url) {
|
||||
responseService.reportResult?.({
|
||||
url,
|
||||
message: phase.getMessage(),
|
||||
success: phase.getSuccess(),
|
||||
});
|
||||
}
|
||||
message = '';
|
||||
url = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -274,31 +279,40 @@ export namespace ExecuteWithProgress {
|
||||
return {};
|
||||
}
|
||||
function toJson(response: ProgressResponse): string | undefined {
|
||||
let object: Record<string, unknown> | undefined = undefined;
|
||||
if (response instanceof LibraryInstallResponse) {
|
||||
object = LibraryInstallResponse.toObject(false, response);
|
||||
} else if (response instanceof LibraryUninstallResponse) {
|
||||
object = LibraryUninstallResponse.toObject(false, response);
|
||||
} else if (response instanceof ZipLibraryInstallResponse) {
|
||||
object = ZipLibraryInstallResponse.toObject(false, response);
|
||||
} else if (response instanceof PlatformInstallResponse) {
|
||||
object = PlatformInstallResponse.toObject(false, response);
|
||||
} else if (response instanceof PlatformUninstallResponse) {
|
||||
object = PlatformUninstallResponse.toObject(false, response);
|
||||
} else if (response instanceof UpdateIndexResponse) {
|
||||
object = UpdateIndexResponse.toObject(false, response);
|
||||
} else if (response instanceof UpdateLibrariesIndexResponse) {
|
||||
object = UpdateLibrariesIndexResponse.toObject(false, response);
|
||||
} else if (response instanceof UpdateCoreLibrariesIndexResponse) {
|
||||
object = UpdateCoreLibrariesIndexResponse.toObject(false, response);
|
||||
} else if (response instanceof CompileResponse) {
|
||||
object = CompileResponse.toObject(false, response);
|
||||
return JSON.stringify(response.toObject(false));
|
||||
}
|
||||
function phaseOf(
|
||||
download: DownloadProgress
|
||||
): DownloadProgressStart | DownloadProgressUpdate | DownloadProgressEnd {
|
||||
let start: undefined | DownloadProgressStart = undefined;
|
||||
let update: undefined | DownloadProgressUpdate = undefined;
|
||||
let end: undefined | DownloadProgressEnd = undefined;
|
||||
if (download.hasStart()) {
|
||||
start = download.getStart();
|
||||
} else if (download.hasUpdate()) {
|
||||
update = download.getUpdate();
|
||||
} else if (download.hasEnd()) {
|
||||
end = download.getEnd();
|
||||
} else {
|
||||
throw new Error(
|
||||
`Download progress does not have a 'start', 'update', and 'end'. ${JSON.stringify(
|
||||
download.toObject(false)
|
||||
)}`
|
||||
);
|
||||
}
|
||||
if (!object) {
|
||||
console.warn('Unhandled gRPC response', response);
|
||||
return undefined;
|
||||
if (start) {
|
||||
return start;
|
||||
} else if (update) {
|
||||
return update;
|
||||
} else if (end) {
|
||||
return end;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Download progress does not have a 'start', 'update', and 'end'. ${JSON.stringify(
|
||||
download.toObject(false)
|
||||
)}`
|
||||
);
|
||||
}
|
||||
return JSON.stringify(object);
|
||||
}
|
||||
}
|
||||
|
||||
@ -306,33 +320,39 @@ export class IndexesUpdateProgressHandler {
|
||||
private done = 0;
|
||||
private readonly total: number;
|
||||
readonly progressId: string;
|
||||
readonly results: DownloadResult[];
|
||||
|
||||
constructor(
|
||||
private types: IndexType[],
|
||||
additionalUrlsCount: number,
|
||||
private readonly onProgress: (progressMessage: ProgressMessage) => void,
|
||||
private readonly onError?: ({
|
||||
progressId,
|
||||
message,
|
||||
}: {
|
||||
progressId: string;
|
||||
message: string;
|
||||
}) => void,
|
||||
private readonly onStart?: (progressId: string) => void,
|
||||
private readonly onEnd?: (progressId: string) => void
|
||||
private readonly options: {
|
||||
onProgress: (progressMessage: ProgressMessage) => void;
|
||||
onError?: (params: IndexUpdateDidFailParams) => void;
|
||||
onStart?: (params: IndexUpdateWillStartParams) => void;
|
||||
onComplete?: (params: IndexUpdateDidCompleteParams) => void;
|
||||
}
|
||||
) {
|
||||
this.progressId = v4();
|
||||
this.total = IndexesUpdateProgressHandler.total(additionalUrlsCount);
|
||||
this.results = [];
|
||||
this.total = IndexesUpdateProgressHandler.total(types, additionalUrlsCount);
|
||||
// Note: at this point, the IDE2 backend might not have any connected clients, so this notification is not delivered to anywhere
|
||||
// Hence, clients must handle gracefully when no `willUpdate` is received before any `didProgress`.
|
||||
this.onStart?.(this.progressId);
|
||||
// Hence, clients must handle gracefully when no `willStart` event is received before any `didProgress`.
|
||||
this.options.onStart?.({ progressId: this.progressId, types });
|
||||
}
|
||||
|
||||
reportEnd(): void {
|
||||
this.onEnd?.(this.progressId);
|
||||
const updatedAt = new Date().toISOString();
|
||||
this.options.onComplete?.({
|
||||
progressId: this.progressId,
|
||||
summary: this.types.reduce((summary, type) => {
|
||||
summary[type] = updatedAt;
|
||||
return summary;
|
||||
}, {} as IndexUpdateSummary),
|
||||
});
|
||||
}
|
||||
|
||||
reportProgress(message: string): void {
|
||||
this.onProgress({
|
||||
this.options.onProgress({
|
||||
message,
|
||||
progressId: this.progressId,
|
||||
work: { total: this.total, done: ++this.done },
|
||||
@ -340,15 +360,44 @@ export class IndexesUpdateProgressHandler {
|
||||
}
|
||||
|
||||
reportError(message: string): void {
|
||||
this.onError?.({ progressId: this.progressId, message });
|
||||
this.options.onError?.({
|
||||
progressId: this.progressId,
|
||||
message,
|
||||
types: this.types,
|
||||
});
|
||||
}
|
||||
|
||||
private static total(additionalUrlsCount: number): number {
|
||||
// +1 for the `package_index.tar.bz2` when updating the platform index.
|
||||
const totalPlatformIndexCount = additionalUrlsCount + 1;
|
||||
// The `library_index.json.gz` and `library_index.json.sig` when running the library index update.
|
||||
const totalLibraryIndexCount = 2;
|
||||
reportResult(result: DownloadResult): void {
|
||||
this.results.push(result);
|
||||
}
|
||||
|
||||
private static total(
|
||||
types: IndexType[],
|
||||
additionalUrlsCount: number
|
||||
): number {
|
||||
let total = 0;
|
||||
if (types.includes('library')) {
|
||||
// The `library_index.json.gz` and `library_index.json.sig` when running the library index update.
|
||||
total += 2;
|
||||
}
|
||||
if (types.includes('platform')) {
|
||||
// +1 for the `package_index.tar.bz2` when updating the platform index.
|
||||
total += additionalUrlsCount + 1;
|
||||
}
|
||||
// +1 for the `initInstance` call after the index update (`reportEnd`)
|
||||
return totalPlatformIndexCount + totalLibraryIndexCount + 1;
|
||||
return total + 1;
|
||||
}
|
||||
}
|
||||
|
||||
export interface DownloadResult {
|
||||
readonly url: string;
|
||||
readonly success: boolean;
|
||||
readonly message?: string;
|
||||
}
|
||||
export namespace DownloadResult {
|
||||
export function isError(
|
||||
arg: DownloadResult
|
||||
): arg is DownloadResult & { message: string } {
|
||||
return !!arg.message && !arg.success;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,9 @@ import type {
|
||||
Config,
|
||||
Sketch,
|
||||
ProgressMessage,
|
||||
IndexUpdateWillStartParams,
|
||||
IndexUpdateDidCompleteParams,
|
||||
IndexUpdateDidFailParams,
|
||||
} from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
@ -16,8 +19,8 @@ export class NotificationServiceServerImpl
|
||||
{
|
||||
private readonly clients: NotificationServiceClient[] = [];
|
||||
|
||||
notifyIndexWillUpdate(progressId: string): void {
|
||||
this.clients.forEach((client) => client.notifyIndexWillUpdate(progressId));
|
||||
notifyIndexUpdateWillStart(params: IndexUpdateWillStartParams): void {
|
||||
this.clients.forEach((client) => client.notifyIndexUpdateWillStart(params));
|
||||
}
|
||||
|
||||
notifyIndexUpdateDidProgress(progressMessage: ProgressMessage): void {
|
||||
@ -26,20 +29,14 @@ export class NotificationServiceServerImpl
|
||||
);
|
||||
}
|
||||
|
||||
notifyIndexDidUpdate(progressId: string): void {
|
||||
this.clients.forEach((client) => client.notifyIndexDidUpdate(progressId));
|
||||
notifyIndexUpdateDidComplete(params: IndexUpdateDidCompleteParams): void {
|
||||
this.clients.forEach((client) =>
|
||||
client.notifyIndexUpdateDidComplete(params)
|
||||
);
|
||||
}
|
||||
|
||||
notifyIndexUpdateDidFail({
|
||||
progressId,
|
||||
message,
|
||||
}: {
|
||||
progressId: string;
|
||||
message: string;
|
||||
}): void {
|
||||
this.clients.forEach((client) =>
|
||||
client.notifyIndexUpdateDidFail({ progressId, message })
|
||||
);
|
||||
notifyIndexUpdateDidFail(params: IndexUpdateDidFailParams): void {
|
||||
this.clients.forEach((client) => client.notifyIndexUpdateDidFail(params));
|
||||
}
|
||||
|
||||
notifyDaemonDidStart(port: string): void {
|
||||
|
@ -408,6 +408,11 @@
|
||||
"dismissSurvey": "Don't show again",
|
||||
"surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better."
|
||||
},
|
||||
"updateIndexes": {
|
||||
"updateIndexes": "Update Indexes",
|
||||
"updateLibraryIndex": "Update Library Index",
|
||||
"updatePackageIndex": "Update Package Index"
|
||||
},
|
||||
"upload": {
|
||||
"error": "{0} error: {1}"
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user