1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Remove broken symlink from node_modules on uninstall (#1695)

Signed-off-by: Panu Horsmalahti <phorsmalahti@mirantis.com>
This commit is contained in:
Panu Horsmalahti 2020-12-08 21:04:01 +02:00 committed by GitHub
parent 172b2a9c9f
commit ec0a90343e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 8 deletions

View File

@ -206,7 +206,7 @@ export class ExtensionDiscovery {
// The path to the manifest file is the lens extension id // The path to the manifest file is the lens extension id
// Note that we need to use the symlinked path // Note that we need to use the symlinked path
const lensExtensionId = path.join(this.nodeModulesPath, extensionName, "package.json"); const lensExtensionId = path.join(this.nodeModulesPath, extensionName, manifestFilename);
logger.info(`${logModule} removed extension ${extensionName}`); logger.info(`${logModule} removed extension ${extensionName}`);
this.events.emit("remove", lensExtensionId as LensExtensionId); this.events.emit("remove", lensExtensionId as LensExtensionId);
@ -217,12 +217,17 @@ export class ExtensionDiscovery {
}; };
/** /**
* Uninstalls extension by path. * Uninstalls extension.
* The application will detect the folder unlink and remove the extension from the UI automatically. * The application will detect the folder unlink and remove the extension from the UI automatically.
* @param absolutePath Path to the non-symlinked folder of the extension * @param extension Extension to unistall.
*/ */
async uninstallExtension(absolutePath: string) { async uninstallExtension({ absolutePath, manifest }: InstalledExtension) {
logger.info(`${logModule} Uninstalling ${absolutePath}`); logger.info(`${logModule} Uninstalling ${manifest.name}`);
// remove the symlink under node_modules.
// If we don't remove the symlink, the uninstall would leave a non-working symlink,
// which wouldn't be fixed if the extension was reinstalled, causing the extension not to work.
await fs.remove(this.getInstalledPath(manifest.name));
const exists = await fs.pathExists(absolutePath); const exists = await fs.pathExists(absolutePath);
@ -269,6 +274,22 @@ export class ExtensionDiscovery {
return extensions; return extensions;
} }
/**
* Returns the symlinked path to the extension folder,
* e.g. "/Users/<username>/Library/Application Support/Lens/node_modules/@publisher/extension"
*/
protected getInstalledPath(name: string) {
return path.join(this.nodeModulesPath, name);
}
/**
* Returns the symlinked path to the package.json,
* e.g. "/Users/<username>/Library/Application Support/Lens/node_modules/@publisher/extension/package.json"
*/
protected getInstalledManifestPath(name: string) {
return path.join(this.getInstalledPath(name), manifestFilename);
}
protected async getByManifest(manifestPath: string, { isBundled = false }: { protected async getByManifest(manifestPath: string, { isBundled = false }: {
isBundled?: boolean; isBundled?: boolean;
} = {}): Promise<InstalledExtension | null> { } = {}): Promise<InstalledExtension | null> {
@ -279,7 +300,7 @@ export class ExtensionDiscovery {
fs.accessSync(manifestPath, fs.constants.F_OK); fs.accessSync(manifestPath, fs.constants.F_OK);
manifestJson = __non_webpack_require__(manifestPath); manifestJson = __non_webpack_require__(manifestPath);
const installedManifestPath = path.join(this.nodeModulesPath, manifestJson.name, "package.json"); const installedManifestPath = this.getInstalledManifestPath(manifestJson.name);
this.packagesJson.dependencies[manifestJson.name] = path.dirname(manifestPath); this.packagesJson.dependencies[manifestJson.name] = path.dirname(manifestPath);
const isEnabled = isBundled || extensionsStore.isEnabled(installedManifestPath); const isEnabled = isBundled || extensionsStore.isEnabled(installedManifestPath);

View File

@ -68,7 +68,7 @@ describe("Extensions", () => {
// Approve confirm dialog // Approve confirm dialog
fireEvent.click(screen.getByText("Yes")); fireEvent.click(screen.getByText("Yes"));
expect(extensionDiscovery.uninstallExtension).toHaveBeenCalledWith("/absolute/path"); expect(extensionDiscovery.uninstallExtension).toHaveBeenCalled();
expect(screen.getByText("Disable").closest("button")).toBeDisabled(); expect(screen.getByText("Disable").closest("button")).toBeDisabled();
expect(screen.getByText("Uninstall").closest("button")).toBeDisabled(); expect(screen.getByText("Uninstall").closest("button")).toBeDisabled();
}); });

View File

@ -413,7 +413,7 @@ export class Extensions extends React.Component {
displayName displayName
}); });
await extensionDiscovery.uninstallExtension(extension.absolutePath); await extensionDiscovery.uninstallExtension(extension);
} catch (error) { } catch (error) {
Notifications.error( Notifications.error(
<p>Uninstalling extension <b>{displayName}</b> has failed: <em>{error?.message ?? ""}</em></p> <p>Uninstalling extension <b>{displayName}</b> has failed: <em>{error?.message ?? ""}</em></p>