Include bundled extensions in package.json (#6715)

* bundle extensions to asar

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

* make build fix

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>

Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
Jari Kolehmainen authored and GitHub committed 2022-12-13 13:24:46 +02:00
1 parent 146cae0b1c
commit 012944d562
12 files changed
+55 -108

No files matched your search

@@ -18,6 +18,7 @@ export default getGlobalOverride(applicationInformationInjectable, () => ({
sentryDsn: "",
contentSecurityPolicy: "script-src 'unsafe-eval' 'self'; frame-src http://*.localhost:*/; img-src * data:",
welcomeRoute: "/welcome",
extensions: [],
},
copyright: "some-copyright-information",
description: "some-descriptive-text",
@@ -10,7 +10,6 @@ import extensionsStoreInjectable from "../extensions-store/extensions-store.inje
import extensionInstallationStateStoreInjectable from "../extension-installation-state-store/extension-installation-state-store.injectable";
import installExtensionInjectable from "../extension-installer/install-extension/install-extension.injectable";
import extensionPackageRootDirectoryInjectable from "../extension-installer/extension-package-root-directory/extension-package-root-directory.injectable";
import installExtensionsInjectable from "../extension-installer/install-extensions/install-extensions.injectable";
import readJsonFileInjectable from "../../common/fs/read-json-file.injectable";
import loggerInjectable from "../../common/logger.injectable";
import pathExistsInjectable from "../../common/fs/path-exists.injectable";
@@ -28,6 +27,7 @@ import getRelativePathInjectable from "../../common/path/get-relative-path.injec
import joinPathsInjectable from "../../common/path/join-paths.injectable";
import removePathInjectable from "../../common/fs/remove-path.injectable";
import homeDirectoryPathInjectable from "../../common/os/home-directory-path.injectable";
import applicationInformationInjectable from "../../common/vars/application-information.injectable";
import lensResourcesDirInjectable from "../../common/vars/lens-resources-dir.injectable";
const extensionDiscoveryInjectable = getInjectable({
@@ -39,7 +39,6 @@ const extensionDiscoveryInjectable = getInjectable({
extensionInstallationStateStore: di.inject(extensionInstallationStateStoreInjectable),
isCompatibleExtension: di.inject(isCompatibleExtensionInjectable),
installExtension: di.inject(installExtensionInjectable),
installExtensions: di.inject(installExtensionsInjectable),
extensionPackageRootDirectory: di.inject(extensionPackageRootDirectoryInjectable),
resourcesDirectory: di.inject(lensResourcesDirInjectable),
readJsonFile: di.inject(readJsonFileInjectable),
@@ -59,6 +58,7 @@ const extensionDiscoveryInjectable = getInjectable({
getRelativePath: di.inject(getRelativePathInjectable),
joinPaths: di.inject(joinPathsInjectable),
homeDirectoryPath: di.inject(homeDirectoryPathInjectable),
applicationInformation: di.inject(applicationInformationInjectable),
}),
});
@@ -12,7 +12,6 @@ import type { ExtensionsStore } from "../extensions-store/extensions-store";
import type { ExtensionLoader } from "../extension-loader";
import type { LensExtensionId, LensExtensionManifest } from "../lens-extension";
import type { ExtensionInstallationStateStore } from "../extension-installation-state-store/extension-installation-state-store";
import type { PackageJson } from "type-fest";
import { extensionDiscoveryStateChannel } from "../../common/ipc/extension-handling";
import { requestInitialExtensionDiscovery } from "../../renderer/ipc";
import type { ReadJson } from "../../common/fs/read-json-file.injectable";
@@ -20,7 +19,6 @@ import type { Logger } from "../../common/logger";
import type { PathExists } from "../../common/fs/path-exists.injectable";
import type { Watch } from "../../common/fs/watch/watch.injectable";
import type { Stats } from "fs";
import { constants } from "fs";
import type { LStat } from "../../common/fs/lstat.injectable";
import type { ReadDirectory } from "../../common/fs/read-directory.injectable";
import type { EnsureDirectory } from "../../common/fs/ensure-dir.injectable";
@@ -32,6 +30,7 @@ import type { GetDirnameOfPath } from "../../common/path/get-dirname.injectable"
import type { GetRelativePath } from "../../common/path/get-relative-path.injectable";
import type { RemovePath } from "../../common/fs/remove-path.injectable";
import type TypedEventEmitter from "typed-emitter";
import type { ApplicationInformation } from "../../common/vars/application-information.injectable";
interface Dependencies {
readonly extensionLoader: ExtensionLoader;
@@ -43,9 +42,9 @@ interface Dependencies {
readonly isProduction: boolean;
readonly fileSystemSeparator: string;
readonly homeDirectoryPath: string;
readonly applicationInformation: ApplicationInformation;
isCompatibleExtension: (manifest: LensExtensionManifest) => boolean;
installExtension: (name: string) => Promise<void>;
installExtensions: (packageJsonPath: string, packagesJson: PackageJson) => Promise<void>;
readJsonFile: ReadJson;
pathExists: PathExists;
removePath: RemovePath;
@@ -137,14 +136,6 @@ export class ExtensionDiscovery {
return this.dependencies.joinPaths(this.dependencies.extensionPackageRootDirectory, manifestFilename);
}
get inTreeTargetPath(): string {
return this.dependencies.joinPaths(this.dependencies.extensionPackageRootDirectory, "extensions");
}
get inTreeFolderPath(): string {
return this.dependencies.joinPaths(this.dependencies.resourcesDirectory, "extensions");
}
get nodeModulesPath(): string {
return this.dependencies.joinPaths(this.dependencies.extensionPackageRootDirectory, "node_modules");
}
@@ -329,26 +320,6 @@ export class ExtensionDiscovery {
);
await this.dependencies.removePath(this.dependencies.joinPaths(this.dependencies.extensionPackageRootDirectory, "package-lock.json"));
const canWriteToInTreeFolder = await this.dependencies.accessPath(this.inTreeFolderPath, constants.W_OK);
if (canWriteToInTreeFolder) {
// Set bundled folder path to static/extensions
this.bundledFolderPath = this.inTreeFolderPath;
} else {
// Remove e.g. /Users/<username>/Library/Application Support/LensDev/extensions
await this.dependencies.removePath(this.inTreeTargetPath);
// Create folder e.g. /Users/<username>/Library/Application Support/LensDev/extensions
await this.dependencies.ensureDirectory(this.inTreeTargetPath);
// Copy static/extensions to e.g. /Users/<username>/Library/Application Support/LensDev/extensions
await this.dependencies.copy(this.inTreeFolderPath, this.inTreeTargetPath);
// Set bundled folder path to e.g. /Users/<username>/Library/Application Support/LensDev/extensions
this.bundledFolderPath = this.inTreeTargetPath;
}
await this.dependencies.ensureDirectory(this.nodeModulesPath);
await this.dependencies.ensureDirectory(this.localFolderPath);
@@ -382,7 +353,7 @@ export class ExtensionDiscovery {
protected async getByManifest(manifestPath: string, { isBundled = false } = {}): Promise<InstalledExtension | null> {
try {
const manifest = await this.dependencies.readJsonFile(manifestPath) as unknown as LensExtensionManifest;
const id = this.getInstalledManifestPath(manifest.name);
const id = isBundled ? manifestPath : this.getInstalledManifestPath(manifest.name);
const isEnabled = this.dependencies.extensionsStore.isEnabled({ id, isBundled });
const extensionDir = this.dependencies.getDirnameOfPath(manifestPath);
const npmPackage = this.dependencies.joinPaths(extensionDir, `${manifest.name}-${manifest.version}.tgz`);
@@ -417,39 +388,24 @@ export class ExtensionDiscovery {
const userExtensions = await this.loadFromFolder(this.localFolderPath, bundledExtensions.map((extension) => extension.manifest.name));
const extensions = bundledExtensions.concat(userExtensions);
await this.installBundledPackages(this.packageJsonPath, extensions);
return this.extensions = new Map(extensions.map(extension => [extension.id, extension]));
}
/**
* Write package.json to file system and install dependencies.
*/
installBundledPackages(packageJsonPath: string, extensions: InstalledExtension[]): Promise<void> {
const dependencies = Object.fromEntries(
extensions.filter(extension => extension.isBundled).map(extension => [extension.manifest.name, extension.absolutePath]),
);
const optionalDependencies = Object.fromEntries(
extensions.filter(extension => !extension.isBundled).map(extension => [extension.manifest.name, extension.absolutePath]),
);
return this.dependencies.installExtensions(packageJsonPath, { dependencies, optionalDependencies });
}
async loadBundledExtensions(): Promise<InstalledExtension[]> {
const extensions: InstalledExtension[] = [];
const folderPath = this.bundledFolderPath;
const paths = await this.dependencies.readDirectory(folderPath);
const extensionNames = this.dependencies.applicationInformation.config.extensions || [];
for (const fileName of paths) {
const absPath = this.dependencies.joinPaths(folderPath, fileName);
for (const dirName of extensionNames) {
const absPath = this.dependencies.joinPaths(__dirname, "..", "..", "node_modules", dirName);
const extension = await this.loadExtensionFromFolder(absPath, { isBundled: true });
if (extension) {
extensions.push(extension);
if (!extension) {
throw new Error(`Couldn't load bundled extension: ${dirName}`);
}
extensions.push(extension);
}
this.dependencies.logger.debug(`${logModule}: ${extensions.length} extensions loaded`, { folderPath, extensions });
this.dependencies.logger.debug(`${logModule}: ${extensions.length} extensions loaded`, { extensions });
return extensions;
}
@@ -5,10 +5,7 @@
import AwaitLock from "await-lock";
import child_process from "child_process";
import fs from "fs-extra";
import path from "path";
import logger from "../../main/logger";
import type { PackageJson } from "type-fest";
const logModule = "[EXTENSION-INSTALLER]";
@@ -38,27 +35,6 @@ export class ExtensionInstaller {
return __non_webpack_require__.resolve("npm");
}
/**
* Write package.json to the file system and execute npm install for it.
*/
installPackages = async (packageJsonPath: string, packagesJson: PackageJson): Promise<void> => {
// Mutual exclusion to install packages in sequence
await this.installLock.acquireAsync();
try {
// Write the package.json which will be installed in .installDependencies()
await fs.writeFile(path.join(packageJsonPath), JSON.stringify(packagesJson, null, 2), {
mode: 0o600,
});
logger.info(`${logModule} installing dependencies at ${this.dependencies.extensionPackageRootDirectory}`);
await this.npm(...baseNpmInstallArgs);
logger.info(`${logModule} dependencies installed at ${this.dependencies.extensionPackageRootDirectory}`);
} finally {
this.installLock.release();
}
};
/**
* Install single package using npm
*/
@@ -1,13 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import extensionInstallerInjectable from "../extension-installer.injectable";
const installExtensionsInjectable = getInjectable({
id: "install-extensions",
instantiate: (di) => di.inject(extensionInstallerInjectable).installPackages,
});
export default installExtensionsInjectable;