feat: use Arduino CLI 0.36.0-rc.1 APIs

Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
Akos Kitta
2024-01-17 17:16:00 +01:00
committed by Akos Kitta
parent 48e7bf6b5d
commit 8e09971078
43 changed files with 5314 additions and 3052 deletions

View File

@@ -3,7 +3,6 @@ import { nls } from '@theia/core/lib/common/nls';
import { notEmpty } from '@theia/core/lib/common/objects';
import { inject, injectable } from '@theia/core/shared/inversify';
import {
Board,
BoardDetails,
BoardSearch,
BoardUserField,
@@ -32,11 +31,9 @@ import {
BoardListAllResponse,
BoardSearchRequest,
} from './cli-protocol/cc/arduino/cli/commands/v1/board_pb';
import { Platform } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb';
import { PlatformSummary } from './cli-protocol/cc/arduino/cli/commands/v1/common_pb';
import {
PlatformInstallRequest,
PlatformListRequest,
PlatformListResponse,
PlatformSearchRequest,
PlatformSearchResponse,
PlatformUninstallRequest,
@@ -247,24 +244,22 @@ export class BoardsServiceImpl
async getInstalledPlatforms(): Promise<BoardsPackage[]> {
const { instance, client } = await this.coreClient;
return new Promise<BoardsPackage[]>((resolve, reject) => {
client.platformList(
new PlatformListRequest().setInstance(instance),
(err, response) => {
if (err) {
reject(err);
return;
}
resolve(
response
.getInstalledPlatformsList()
.map((platform, _, installedPlatforms) =>
toBoardsPackage(platform, installedPlatforms)
)
);
}
);
});
const resp = await new Promise<PlatformSearchResponse>(
(resolve, reject) => {
client.platformSearch(
new PlatformSearchRequest()
.setInstance(instance)
.setManuallyInstalled(true), // include core manually installed to the sketchbook
(err, resp) => (err ? reject(err) : resolve(resp))
);
}
);
const searchOutput = resp.getSearchOutputList();
return searchOutput
.map((message) => message.toObject(false))
.filter((summary) => summary.installedVersion) // only installed ones
.map(createBoardsPackage)
.filter(notEmpty);
}
private async handleListBoards(
@@ -287,12 +282,28 @@ export class BoardsServiceImpl
for (const board of resp.getBoardsList()) {
const platform = board.getPlatform();
if (platform) {
const platformId = platform.getId();
const metadata = platform.getMetadata();
if (!metadata) {
console.warn(
`Platform metadata is missing for platform: ${JSON.stringify(
platform.toObject(false)
)}. Skipping`
);
continue;
}
const platformId = metadata.getId();
const release = platform.getRelease();
if (!release) {
console.warn(
`Platform release is missing for platform: ${platformId}. Skipping`
);
continue;
}
const fqbn = board.getFqbn() || undefined; // prefer undefined over empty string
const parsedPlatformId = createPlatformIdentifier(platformId);
if (!parsedPlatformId) {
console.warn(
`Could not create platform identifier from platform ID input: ${platform.getId()}. Skipping`
`Could not create platform identifier from platform ID input: ${platformId}. Skipping`
);
continue;
}
@@ -319,8 +330,8 @@ export class BoardsServiceImpl
name: board.getName(),
fqbn: board.getFqbn(),
packageId: parsedPlatformId,
packageName: platform.getName(),
manuallyInstalled: platform.getManuallyInstalled(),
packageName: release.getName(),
manuallyInstalled: metadata.getManuallyInstalled(),
});
}
}
@@ -375,89 +386,25 @@ export class BoardsServiceImpl
const coreClient = await this.coreClient;
const { client, instance } = coreClient;
const installedPlatformsReq = new PlatformListRequest();
installedPlatformsReq.setInstance(instance);
const installedPlatformsResp = await new Promise<PlatformListResponse>(
(resolve, reject) => {
client.platformList(installedPlatformsReq, (err, resp) => {
!!err ? reject(err) : resolve(resp);
});
}
);
const installedPlatforms =
installedPlatformsResp.getInstalledPlatformsList();
const req = new PlatformSearchRequest();
req.setSearchArgs(options.query || '');
req.setAllVersions(true);
req.setInstance(instance);
// `core search` returns with all platform versions when the command is executed via gRPC or with `--format json`
// The `--all` flag is applicable only when filtering for the human-readable (`--format text`) output of the CLI
const resp = await new Promise<PlatformSearchResponse>(
(resolve, reject) => {
client.platformSearch(req, (err, resp) => {
!!err ? reject(err) : resolve(resp);
});
client.platformSearch(
new PlatformSearchRequest()
.setInstance(instance)
.setSearchArgs(options.query ?? ''),
(err, resp) => (err ? reject(err) : resolve(resp))
);
}
);
const packages = new Map<string, BoardsPackage>();
// We must group the cores by ID, and sort platforms by, first the installed version, then version alphabetical order.
// Otherwise we lose the FQBN information.
const groupedById: Map<string, Platform[]> = new Map();
for (const platform of resp.getSearchOutputList()) {
const id = platform.getId();
const idGroup = groupedById.get(id);
if (idGroup) {
idGroup.push(platform);
} else {
groupedById.set(id, [platform]);
}
}
const installedAwareVersionComparator = (
left: Platform,
right: Platform
) => {
// XXX: we cannot rely on `platform.getInstalled()`, it is always an empty string.
const leftInstalled = !!installedPlatforms.find(
(ip) =>
ip.getId() === left.getId() && ip.getInstalled() === left.getLatest()
);
const rightInstalled = !!installedPlatforms.find(
(ip) =>
ip.getId() === right.getId() &&
ip.getInstalled() === right.getLatest()
);
if (leftInstalled && !rightInstalled) {
return -1;
}
if (!leftInstalled && rightInstalled) {
return 1;
}
const invertedVersionComparator =
Installable.Version.COMPARATOR(left.getLatest(), right.getLatest()) *
-1;
// Higher version comes first.
return invertedVersionComparator;
};
for (const value of groupedById.values()) {
value.sort(installedAwareVersionComparator);
}
for (const value of groupedById.values()) {
for (const platform of value) {
const id = platform.getId();
const pkg = packages.get(id);
if (pkg) {
pkg.availableVersions.push(platform.getLatest());
pkg.availableVersions.sort(Installable.Version.COMPARATOR).reverse();
} else {
packages.set(id, toBoardsPackage(platform, installedPlatforms));
}
}
}
const filter = this.typePredicate(options);
const boardsPackages = [...packages.values()].filter(filter);
const typeFilter = this.typePredicate(options);
const searchOutput = resp.getSearchOutputList();
const boardsPackages = searchOutput
.map((message) => message.toObject(false))
.map(createBoardsPackage)
.filter(notEmpty)
.filter(typeFilter);
return sortComponents(boardsPackages, boardsPackageSortGroup);
}
@@ -624,36 +571,48 @@ function boardsPackageSortGroup(boardsPackage: BoardsPackage): SortGroup {
return types.join('-') as SortGroup;
}
function toBoardsPackage(
platform: Platform,
installedPlatforms: Platform[]
): BoardsPackage {
let installedVersion: string | undefined;
const matchingPlatform = installedPlatforms.find(
(ip) => ip.getId() === platform.getId()
);
if (!!matchingPlatform) {
installedVersion = matchingPlatform.getInstalled();
function createBoardsPackage(
summary: PlatformSummary.AsObject
): BoardsPackage | undefined {
if (!isPlatformSummaryWithMetadata(summary)) {
return undefined;
}
const versionReleaseMap = new Map(summary.releasesMap);
const actualRelease =
versionReleaseMap.get(summary.installedVersion) ??
versionReleaseMap.get(summary.latestVersion);
if (!actualRelease) {
return undefined;
}
const { name, typeList, boardsList, deprecated, compatible } = actualRelease;
if (!compatible) {
return undefined; // never show incompatible platforms
}
const { id, website, maintainer } = summary.metadata;
const availableVersions = Array.from(versionReleaseMap.keys())
.sort(Installable.Version.COMPARATOR)
.reverse();
return {
id: platform.getId(),
name: platform.getName(),
author: platform.getMaintainer(),
availableVersions: [platform.getLatest()],
description: platform
.getBoardsList()
.map((b) => b.getName())
.join(', '),
types: platform.getTypeList(),
deprecated: platform.getDeprecated(),
id,
name,
summary: nls.localize(
'arduino/component/boardsIncluded',
'Boards included in this package:'
),
installedVersion,
boards: platform
.getBoardsList()
.map((b) => <Board>{ name: b.getName(), fqbn: b.getFqbn() }),
moreInfoLink: platform.getWebsite(),
description: boardsList.map(({ name }) => name).join(', '),
boards: boardsList,
types: typeList,
moreInfoLink: website,
author: maintainer,
deprecated,
availableVersions,
};
}
type PlatformSummaryWithMetadata = PlatformSummary.AsObject &
Required<Pick<PlatformSummary.AsObject, 'metadata'>>;
function isPlatformSummaryWithMetadata(
summary: PlatformSummary.AsObject
): summary is PlatformSummaryWithMetadata {
return Boolean(summary.metadata);
}