UNPKG

@sussudio/platform

Version:

Internal APIs for VS Code's service injection the base services.

174 lines (173 loc) 7.03 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { compareIgnoreCase } from '@sussudio/base/common/strings.mjs'; import { getTargetPlatform } from './extensionManagement.mjs'; import { ExtensionIdentifier } from '../../extensions/common/extensions.mjs'; import { isLinux, platform } from '@sussudio/base/common/platform.mjs'; import { URI } from '@sussudio/base/common/uri.mjs'; import { getErrorMessage } from '@sussudio/base/common/errors.mjs'; import { arch } from '@sussudio/base/common/process.mjs'; import { TrustedTelemetryValue } from '../../telemetry/common/telemetryUtils.mjs'; export function areSameExtensions(a, b) { if (a.uuid && b.uuid) { return a.uuid === b.uuid; } if (a.id === b.id) { return true; } return compareIgnoreCase(a.id, b.id) === 0; } const ExtensionKeyRegex = /^([^.]+\..+)-(\d+\.\d+\.\d+)(-(.+))?$/; export class ExtensionKey { version; targetPlatform; static create(extension) { const version = extension.manifest ? extension.manifest.version : extension.version; const targetPlatform = extension.manifest ? extension.targetPlatform : extension.properties.targetPlatform; return new ExtensionKey(extension.identifier, version, targetPlatform); } static parse(key) { const matches = ExtensionKeyRegex.exec(key); return matches && matches[1] && matches[2] ? new ExtensionKey({ id: matches[1] }, matches[2], matches[4] || undefined) : null; } id; constructor(identifier, version, targetPlatform = 'undefined' /* TargetPlatform.UNDEFINED */) { this.version = version; this.targetPlatform = targetPlatform; this.id = identifier.id; } toString() { return `${this.id}-${this.version}${ this.targetPlatform !== 'undefined' /* TargetPlatform.UNDEFINED */ ? `-${this.targetPlatform}` : '' }`; } equals(o) { if (!(o instanceof ExtensionKey)) { return false; } return areSameExtensions(this, o) && this.version === o.version && this.targetPlatform === o.targetPlatform; } } const EXTENSION_IDENTIFIER_WITH_VERSION_REGEX = /^([^.]+\..+)@((prerelease)|(\d+\.\d+\.\d+(-.*)?))$/; export function getIdAndVersion(id) { const matches = EXTENSION_IDENTIFIER_WITH_VERSION_REGEX.exec(id); if (matches && matches[1]) { return [adoptToGalleryExtensionId(matches[1]), matches[2]]; } return [adoptToGalleryExtensionId(id), undefined]; } export function getExtensionId(publisher, name) { return `${publisher}.${name}`; } export function adoptToGalleryExtensionId(id) { return id.toLocaleLowerCase(); } export function getGalleryExtensionId(publisher, name) { return adoptToGalleryExtensionId(getExtensionId(publisher, name)); } export function groupByExtension(extensions, getExtensionIdentifier) { const byExtension = []; const findGroup = (extension) => { for (const group of byExtension) { if (group.some((e) => areSameExtensions(getExtensionIdentifier(e), getExtensionIdentifier(extension)))) { return group; } } return null; }; for (const extension of extensions) { const group = findGroup(extension); if (group) { group.push(extension); } else { byExtension.push([extension]); } } return byExtension; } export function getLocalExtensionTelemetryData(extension) { return { id: extension.identifier.id, name: extension.manifest.name, galleryId: null, publisherId: extension.publisherId, publisherName: extension.manifest.publisher, publisherDisplayName: extension.publisherDisplayName, dependencies: extension.manifest.extensionDependencies && extension.manifest.extensionDependencies.length > 0, }; } /* __GDPR__FRAGMENT__ "GalleryExtensionTelemetryData" : { "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "name": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "galleryId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "publisherId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "publisherName": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "publisherDisplayName": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "isPreReleaseVersion": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "dependencies": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "isSigned": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "${include}": [ "${GalleryExtensionTelemetryData2}" ] } */ export function getGalleryExtensionTelemetryData(extension) { return { id: new TrustedTelemetryValue(extension.identifier.id), name: new TrustedTelemetryValue(extension.name), galleryId: extension.identifier.uuid, publisherId: extension.publisherId, publisherName: extension.publisher, publisherDisplayName: extension.publisherDisplayName, isPreReleaseVersion: extension.properties.isPreReleaseVersion, dependencies: !!(extension.properties.dependencies && extension.properties.dependencies.length > 0), isSigned: extension.isSigned, ...extension.telemetryData, }; } export const BetterMergeId = new ExtensionIdentifier('pprice.better-merge'); export function getExtensionDependencies(installedExtensions, extension) { const dependencies = []; const extensions = extension.manifest.extensionDependencies?.slice(0) ?? []; while (extensions.length) { const id = extensions.shift(); if (id && dependencies.every((e) => !areSameExtensions(e.identifier, { id }))) { const ext = installedExtensions.filter((e) => areSameExtensions(e.identifier, { id })); if (ext.length === 1) { dependencies.push(ext[0]); extensions.push(...(ext[0].manifest.extensionDependencies?.slice(0) ?? [])); } } } return dependencies; } export async function isAlpineLinux(fileService, logService) { if (!isLinux) { return false; } let content; try { const fileContent = await fileService.readFile(URI.file('/etc/os-release')); content = fileContent.value.toString(); } catch (error) { try { const fileContent = await fileService.readFile(URI.file('/usr/lib/os-release')); content = fileContent.value.toString(); } catch (error) { /* Ignore */ logService.debug(`Error while getting the os-release file.`, getErrorMessage(error)); } } return !!content && (content.match(/^ID=([^\u001b\r\n]*)/m) || [])[1] === 'alpine'; } export async function computeTargetPlatform(fileService, logService) { const alpineLinux = await isAlpineLinux(fileService, logService); const targetPlatform = getTargetPlatform(alpineLinux ? 'alpine' : platform, arch); logService.debug('ComputeTargetPlatform:', targetPlatform); return targetPlatform; }