/** * Copyright (c) 2021 OpenLens Authors * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ import { ExtensionInstallationStateStore } from "../extension-install.store"; import { downloadFile, downloadJson, ExtendableDisposer } from "../../../../common/utils"; import { Notifications } from "../../notifications"; import { ConfirmDialog } from "../../confirm-dialog"; import React from "react"; import path from "path"; import { SemVer } from "semver"; import URLParse from "url-parse"; import type { InstallRequest } from "../attempt-install/install-request"; import lodash from "lodash"; export interface ExtensionInfo { name: string; version?: string; requireConfirmation?: boolean; } export interface Dependencies { attemptInstall: (request: InstallRequest, d: ExtendableDisposer) => Promise } export const attemptInstallByInfo = ({ attemptInstall }: Dependencies) => async ({ name, version, requireConfirmation = false, }: ExtensionInfo) => { const disposer = ExtensionInstallationStateStore.startPreInstall(); const registryUrl = new URLParse("https://registry.npmjs.com") .set("pathname", name) .toString(); const { promise } = downloadJson({ url: registryUrl }); const json = await promise.catch(console.error); if ( !json || json.error || typeof json.versions !== "object" || !json.versions ) { const message = json?.error ? `: ${json.error}` : ""; Notifications.error( `Failed to get registry information for that extension${message}`, ); return disposer(); } if (version) { if (!json.versions[version]) { if (json["dist-tags"][version]) { version = json["dist-tags"][version]; } else { Notifications.error(

The {name} extension does not have a version or tag{" "} {version}.

, ); return disposer(); } } } else { const versions = Object.keys(json.versions) .map( version => new SemVer(version, { loose: true, includePrerelease: true }), ) // ignore pre-releases for auto picking the version .filter(version => version.prerelease.length === 0); version = lodash.reduce(versions, (prev, curr) => prev.compareMain(curr) === -1 ? curr : prev, ).format(); } if (requireConfirmation) { const proceed = await ConfirmDialog.confirm({ message: (

Are you sure you want to install{" "} {name}@{version} ?

), labelCancel: "Cancel", labelOk: "Install", }); if (!proceed) { return disposer(); } } const url = json.versions[version].dist.tarball; const fileName = path.basename(url); const { promise: dataP } = downloadFile({ url, timeout: 10 * 60 * 1000 }); return attemptInstall({ fileName, dataP }, disposer); };