Skip to content

fix: clean the installed extensions and inspector cache on intentional CLI uninstall #4257

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion lib/common/commands/preuninstall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,41 @@ export class PreUninstallCommand implements ICommand {

public allowedParameters: ICommandParameter[] = [];

constructor(private $fs: IFileSystem,
constructor(private $extensibilityService: IExtensibilityService,
private $fs: IFileSystem,
private $packageInstallationManager: IPackageInstallationManager,
private $settingsService: ISettingsService) { }

public async execute(args: string[]): Promise<void> {
if (this.isIntentionalUninstall()) {
this.handleIntentionalUninstall();
}

this.$fs.deleteFile(path.join(this.$settingsService.getProfileDir(), "KillSwitches", "cli"));
}

private isIntentionalUninstall(): boolean {
let isIntentionalUninstall = false;
if (process.env && process.env.npm_config_argv) {
try {
const npmConfigArgv = JSON.parse(process.env.npm_config_argv);
const uninstallAliases = ["uninstall", "remove", "rm", "r", "un", "unlink"];
if (_.intersection(npmConfigArgv.original, uninstallAliases).length > 0) {
isIntentionalUninstall = true;
}
} catch (error) {
// ignore
}

}

return isIntentionalUninstall;
}

private handleIntentionalUninstall(): void {
this.$extensibilityService.removeAllExtensions();
this.$packageInstallationManager.clearInspectorCache();
}
}

$injector.registerCommand("dev-preuninstall", PreUninstallCommand);
9 changes: 8 additions & 1 deletion lib/common/declarations.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,12 +289,19 @@ interface IFileSystem {
deleteFile(path: string): void;

/**
* Deletes whole directory. Implementation uses shelljs.
* Deletes whole directory.
* @param {string} directory Path to directory that has to be deleted.
* @returns {void}
*/
deleteDirectory(directory: string): void;

/**
* Deletes whole directory without throwing exceptions.
* @param {string} directory Path to directory that has to be deleted.
* @returns {void}
*/
deleteDirectorySafe(directory: string): void;

/**
* Returns the size of specified file.
* @param {string} path Path to file.
Expand Down
6 changes: 6 additions & 0 deletions lib/common/definitions/extensibility.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ interface IExtensibilityService {
*/
uninstallExtension(extensionName: string): Promise<void>;

/**
* Removes all installed extensions.
* @returns {void}
*/
removeAllExtensions(): void;

/**
* Loads all extensions, so their methods and commands can be used from CLI.
* For each of the extensions, a new Promise is returned. It will be rejected in case the extension cannot be loaded. However other promises will not be reflected by this failure.
Expand Down
8 changes: 8 additions & 0 deletions lib/common/file-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,14 @@ export class FileSystem implements IFileSystem {
}
}

public deleteDirectorySafe(directory: string): void {
try {
this.deleteDirectory(directory);
} catch (e) {
return;
}
}

public getFileSize(path: string): number {
const stat = this.getFsStats(path);
return stat.size;
Expand Down
1 change: 1 addition & 0 deletions lib/declarations.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ interface IPackageInstallationManager {
getLatestCompatibleVersion(packageName: string, referenceVersion?: string): Promise<string>;
getLatestCompatibleVersionSafe(packageName: string, referenceVersion?: string): Promise<string>;
getInspectorFromCache(inspectorNpmPackageName: string, projectDir: string): Promise<string>;
clearInspectorCache(): void;
}

/**
Expand Down
10 changes: 9 additions & 1 deletion lib/package-installation-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export class PackageInstallationManager implements IPackageInstallationManager {
return inspectorPath;
}

const cachePath = path.join(this.$settingsService.getProfileDir(), constants.INSPECTOR_CACHE_DIRNAME);
const cachePath = this.getInspectorCachePath();
this.prepareCacheDir(cachePath);
const pathToPackageInCache = path.join(cachePath, constants.NODE_MODULES_FOLDER_NAME, inspectorNpmPackageName);
const iOSFrameworkNSValue = this.$projectDataService.getNSValue(projectDir, constants.TNS_IOS_RUNTIME_NAME);
Expand All @@ -95,6 +95,14 @@ export class PackageInstallationManager implements IPackageInstallationManager {
return pathToPackageInCache;
}

public clearInspectorCache(): void {
this.$fs.deleteDirectorySafe(this.getInspectorCachePath());
}

private getInspectorCachePath(): string {
return path.join(this.$settingsService.getProfileDir(), constants.INSPECTOR_CACHE_DIRNAME);
}

private prepareCacheDir(cacheDirName: string): void {
this.$fs.ensureDirectoryExists(cacheDirName);

Expand Down
5 changes: 5 additions & 0 deletions lib/services/extensibility-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ export class ExtensibilityService implements IExtensibilityService {
this.$logger.trace(`Finished uninstallation of extension '${extensionName}'.`);
}

public removeAllExtensions(): void {
this.$fs.deleteDirectorySafe(this.pathToExtensions);
this.$logger.info(`Removed all NativeScript CLI extensions.`);
}

public getInstalledExtensionsData(): IExtensionData[] {
const installedExtensions = this.getInstalledExtensions();
return _.keys(installedExtensions).map(installedExtension => this.getInstalledExtensionData(installedExtension));
Expand Down
10 changes: 8 additions & 2 deletions test/stubs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export class ProcessServiceStub implements IProcessService {
}

export class FileSystemStub implements IFileSystem {
deleteDirectorySafe(directory: string): void {
return this.deleteDirectory(directory);
}
async zipFiles(zipFile: string, files: string[], zipPathCallback: (path: string) => string): Promise<void> {
return undefined;
}
Expand All @@ -73,8 +76,8 @@ export class FileSystemStub implements IFileSystem {
return undefined;
}

async deleteDirectory(directory: string): Promise<void> {
return Promise.resolve();
deleteDirectory(directory: string): void {
return undefined;
}

getFileSize(path: string): number {
Expand Down Expand Up @@ -227,6 +230,9 @@ export class ErrorsStub implements IErrors {
}

export class PackageInstallationManagerStub implements IPackageInstallationManager {
clearInspectorCache(): void {
return undefined;
}
async install(packageName: string, pathToSave?: string, options?: INpmInstallOptions): Promise<string> {
return Promise.resolve("");
}
Expand Down