mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-10-07 18:38:32 +00:00

Closes #177 Closes #1188 Co-authored-by: Francesco Spissu <f.spissu@arduino.cc> Co-authored-by: Per Tillisch <p.tillisch@arduino.cc> Co-authored-by: Akos Kitta <a.kitta@arduino.cc> Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
222 lines
6.7 KiB
TypeScript
222 lines
6.7 KiB
TypeScript
import type { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
|
|
import { nls } from '@theia/core/lib/common/nls';
|
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
import { InstallManually, Later } from '../../common/nls';
|
|
import {
|
|
ArduinoComponent,
|
|
BoardsPackage,
|
|
BoardsService,
|
|
LibraryPackage,
|
|
LibraryService,
|
|
ResponseServiceClient,
|
|
Searchable,
|
|
} from '../../common/protocol';
|
|
import { Installable } from '../../common/protocol/installable';
|
|
import { ExecuteWithProgress } from '../../common/protocol/progressible';
|
|
import { BoardsListWidgetFrontendContribution } from '../boards/boards-widget-frontend-contribution';
|
|
import { LibraryListWidgetFrontendContribution } from '../library/library-widget-frontend-contribution';
|
|
import { WindowServiceExt } from '../theia/core/window-service-ext';
|
|
import type { ListWidget } from '../widgets/component-list/list-widget';
|
|
import { Command, CommandRegistry, Contribution } from './contribution';
|
|
|
|
const NoUpdates = nls.localize(
|
|
'arduino/checkForUpdates/noUpdates',
|
|
'There are no recent updates available.'
|
|
);
|
|
const PromptUpdateBoards = nls.localize(
|
|
'arduino/checkForUpdates/promptUpdateBoards',
|
|
'Updates are available for some of your boards.'
|
|
);
|
|
const PromptUpdateLibraries = nls.localize(
|
|
'arduino/checkForUpdates/promptUpdateLibraries',
|
|
'Updates are available for some of your libraries.'
|
|
);
|
|
const UpdatingBoards = nls.localize(
|
|
'arduino/checkForUpdates/updatingBoards',
|
|
'Updating boards...'
|
|
);
|
|
const UpdatingLibraries = nls.localize(
|
|
'arduino/checkForUpdates/updatingLibraries',
|
|
'Updating libraries...'
|
|
);
|
|
const InstallAll = nls.localize(
|
|
'arduino/checkForUpdates/installAll',
|
|
'Install All'
|
|
);
|
|
|
|
interface Task<T extends ArduinoComponent> {
|
|
readonly run: () => Promise<void>;
|
|
readonly item: T;
|
|
}
|
|
|
|
const Updatable = { type: 'Updatable' } as const;
|
|
|
|
@injectable()
|
|
export class CheckForUpdates extends Contribution {
|
|
@inject(WindowServiceExt)
|
|
private readonly windowService: WindowServiceExt;
|
|
@inject(ResponseServiceClient)
|
|
private readonly responseService: ResponseServiceClient;
|
|
@inject(BoardsService)
|
|
private readonly boardsService: BoardsService;
|
|
@inject(LibraryService)
|
|
private readonly libraryService: LibraryService;
|
|
@inject(BoardsListWidgetFrontendContribution)
|
|
private readonly boardsContribution: BoardsListWidgetFrontendContribution;
|
|
@inject(LibraryListWidgetFrontendContribution)
|
|
private readonly librariesContribution: LibraryListWidgetFrontendContribution;
|
|
|
|
override registerCommands(register: CommandRegistry): void {
|
|
register.registerCommand(CheckForUpdates.Commands.CHECK_FOR_UPDATES, {
|
|
execute: () => this.checkForUpdates(false),
|
|
});
|
|
}
|
|
|
|
override async onReady(): Promise<void> {
|
|
const checkForUpdates = this.preferences['arduino.checkForUpdates'];
|
|
if (checkForUpdates) {
|
|
this.windowService.isFirstWindow().then((firstWindow) => {
|
|
if (firstWindow) {
|
|
this.checkForUpdates();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private async checkForUpdates(silent = true) {
|
|
const [boardsPackages, libraryPackages] = await Promise.all([
|
|
this.boardsService.search(Updatable),
|
|
this.libraryService.search(Updatable),
|
|
]);
|
|
this.promptUpdateBoards(boardsPackages);
|
|
this.promptUpdateLibraries(libraryPackages);
|
|
if (!libraryPackages.length && !boardsPackages.length && !silent) {
|
|
this.messageService.info(NoUpdates);
|
|
}
|
|
}
|
|
|
|
private promptUpdateBoards(items: BoardsPackage[]): void {
|
|
this.prompt({
|
|
items,
|
|
installable: this.boardsService,
|
|
viewContribution: this.boardsContribution,
|
|
viewSearchOptions: { query: '', ...Updatable },
|
|
promptMessage: PromptUpdateBoards,
|
|
updatingMessage: UpdatingBoards,
|
|
});
|
|
}
|
|
|
|
private promptUpdateLibraries(items: LibraryPackage[]): void {
|
|
this.prompt({
|
|
items,
|
|
installable: this.libraryService,
|
|
viewContribution: this.librariesContribution,
|
|
viewSearchOptions: { query: '', topic: 'All', ...Updatable },
|
|
promptMessage: PromptUpdateLibraries,
|
|
updatingMessage: UpdatingLibraries,
|
|
});
|
|
}
|
|
|
|
private prompt<
|
|
T extends ArduinoComponent,
|
|
S extends Searchable.Options
|
|
>(options: {
|
|
items: T[];
|
|
installable: Installable<T>;
|
|
viewContribution: AbstractViewContribution<ListWidget<T, S>>;
|
|
viewSearchOptions: S;
|
|
promptMessage: string;
|
|
updatingMessage: string;
|
|
}): void {
|
|
const {
|
|
items,
|
|
installable,
|
|
viewContribution,
|
|
promptMessage: message,
|
|
viewSearchOptions,
|
|
updatingMessage,
|
|
} = options;
|
|
|
|
if (!items.length) {
|
|
return;
|
|
}
|
|
this.messageService
|
|
.info(message, Later, InstallManually, InstallAll)
|
|
.then((answer) => {
|
|
if (answer === InstallAll) {
|
|
const tasks = items.map((item) =>
|
|
this.createInstallTask(item, installable)
|
|
);
|
|
this.executeTasks(updatingMessage, tasks);
|
|
} else if (answer === InstallManually) {
|
|
viewContribution
|
|
.openView({ reveal: true })
|
|
.then((widget) => widget.refresh(viewSearchOptions));
|
|
}
|
|
});
|
|
}
|
|
|
|
private async executeTasks(
|
|
message: string,
|
|
tasks: Task<ArduinoComponent>[]
|
|
): Promise<void> {
|
|
if (tasks.length) {
|
|
return ExecuteWithProgress.withProgress(
|
|
message,
|
|
this.messageService,
|
|
async (progress) => {
|
|
try {
|
|
const total = tasks.length;
|
|
let count = 0;
|
|
for (const { run, item } of tasks) {
|
|
try {
|
|
await run(); // runs update sequentially. // TODO: is parallel update desired?
|
|
} catch (err) {
|
|
console.error(err);
|
|
this.messageService.error(
|
|
`Failed to update ${item.name}. ${err}`
|
|
);
|
|
} finally {
|
|
progress.report({ work: { total, done: ++count } });
|
|
}
|
|
}
|
|
} finally {
|
|
progress.cancel();
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
private createInstallTask<T extends ArduinoComponent>(
|
|
item: T,
|
|
installable: Installable<T>
|
|
): Task<T> {
|
|
const latestVersion = item.availableVersions[0];
|
|
return {
|
|
item,
|
|
run: () =>
|
|
Installable.installWithProgress({
|
|
installable,
|
|
item,
|
|
version: latestVersion,
|
|
messageService: this.messageService,
|
|
responseService: this.responseService,
|
|
keepOutput: true,
|
|
}),
|
|
};
|
|
}
|
|
}
|
|
export namespace CheckForUpdates {
|
|
export namespace Commands {
|
|
export const CHECK_FOR_UPDATES: Command = Command.toLocalizedCommand(
|
|
{
|
|
id: 'arduino-check-for-updates',
|
|
label: 'Check for Arduino Updates',
|
|
category: 'Arduino',
|
|
},
|
|
'arduino/checkForUpdates/checkForUpdates'
|
|
);
|
|
}
|
|
}
|