diff --git a/lib/definitions/platform.d.ts b/lib/definitions/platform.d.ts index 624802f7d4..f9af11ac6c 100644 --- a/lib/definitions/platform.d.ts +++ b/lib/definitions/platform.d.ts @@ -24,7 +24,7 @@ interface IPlatformService { * @param {string[]} platforms Platforms to be removed. * @returns {void} */ - removePlatforms(platforms: string[]): void; + removePlatforms(platforms: string[]): Promise; updatePlatforms(platforms: string[]): Promise; diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index dbda895226..f178dd9eb3 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -208,6 +208,13 @@ interface IPlatformProjectService { * @returns {void} */ ensureConfigurationFileInAppResources(): void; + + /** + * Stops all running processes that might hold a lock on the filesystem. + * Android: Gradle daemon processes are terminated. + * @returns {void} + */ + stopServices(): Promise; } interface IAndroidProjectPropertiesManager { diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index 3806a463b9..209518af5c 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -395,6 +395,16 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject } } + public async stopServices(): Promise { + let projectRoot = this.platformData.projectRoot; + let gradleBin = path.join(projectRoot, "gradlew"); + if (this.$hostInfo.isWindows) { + gradleBin += ".bat"; + } + + return this.$childProcess.spawnFromEvent(gradleBin, ["--stop", "--quiet"], "close", { stdio: "inherit", cwd: projectRoot }); + } + private async cleanProject(projectRoot: string, options: string[]): Promise { options.unshift("clean"); diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index f1aa961239..db2fb9e794 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -632,6 +632,10 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f return null; } + public async stopServices(): Promise { + return Promise.resolve({stderr: "", stdout: "", exitCode: 0}); + } + private async mergeInfoPlists(): Promise { let projectDir = this.$projectData.projectDir; let infoPlistPath = this.$options.baseConfig || path.join(projectDir, constants.APP_FOLDER_NAME, constants.APP_RESOURCES_FOLDER_NAME, this.platformData.normalizedPlatformName, this.platformData.configurationFileName); diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index 6cf23bbe45..6255df1430 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -570,19 +570,21 @@ export class PlatformService implements IPlatformService { this.$logger.info(`Copied file '${packageFile}' to '${targetPath}'.`); } - public removePlatforms(platforms: string[]): void { + public async removePlatforms(platforms: string[]): Promise { this.$projectDataService.initialize(this.$projectData.projectDir); - _.each(platforms, platform => { + for (let platform of platforms) { this.validatePlatformInstalled(platform); let platformData = this.$platformsData.getPlatformData(platform); + await this.$platformsData.getPlatformData(platform).platformProjectService.stopServices(); + let platformDir = path.join(this.$projectData.platformsDir, platform); this.$fs.deleteDirectory(platformDir); this.$projectDataService.removeProperty(platformData.frameworkPackageName); this.$logger.out(`Platform ${platform} successfully removed.`); - }); + } } public async updatePlatforms(platforms: string[]): Promise { @@ -744,7 +746,7 @@ export class PlatformService implements IPlatformService { private async updatePlatformCore(platformData: IPlatformData, currentVersion: string, newVersion: string, canUpdate: boolean): Promise { let packageName = platformData.normalizedPlatformName.toLowerCase(); - this.removePlatforms([packageName]); + await this.removePlatforms([packageName]); packageName = newVersion ? `${packageName}@${newVersion}` : packageName; await this.addPlatform(packageName); this.$logger.out("Successfully updated to version ", newVersion); diff --git a/test/platform-commands.ts b/test/platform-commands.ts index a868c17321..429168da5e 100644 --- a/test/platform-commands.ts +++ b/test/platform-commands.ts @@ -408,7 +408,7 @@ describe('Platform Service Tests', () => { testInjector.registerCommand("platform|clean", CleanCommand); let cleanCommand = testInjector.resolveCommand("platform|clean"); - platformService.removePlatforms = (platforms: string[]) => { + platformService.removePlatforms = async (platforms: string[]) => { platformActions.push({ action: "removePlatforms", platforms }); }; diff --git a/test/platform-service.ts b/test/platform-service.ts index e9da8636dd..b287b21b44 100644 --- a/test/platform-service.ts +++ b/test/platform-service.ts @@ -168,10 +168,25 @@ describe('Platform Service Tests', () => { }); describe("remove platform unit tests", () => { - it("should fail when platforms are not added", () => { + it("should fail when platforms are not added", async () => { + const ExpectedErrorsCaught = 2; + let errorsCaught = 0; + testInjector.resolve("fs").exists = () => false; - (() => platformService.removePlatforms(["android"])).should.throw(); - (() => platformService.removePlatforms(["ios"])).should.throw(); + + try { + await platformService.removePlatforms(["android"]); + } catch (e) { + errorsCaught++; + } + + try { + await platformService.removePlatforms(["ios"]); + } catch (e) { + errorsCaught++; + } + + assert.isTrue(errorsCaught === ExpectedErrorsCaught); }); it("shouldn't fail when platforms are added", async () => { testInjector.resolve("fs").exists = () => false; diff --git a/test/stubs.ts b/test/stubs.ts index 7f576a6a5e..9a7fd1a850 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -342,6 +342,9 @@ export class PlatformProjectServiceStub implements IPlatformProjectService { ensureConfigurationFileInAppResources(): void { return null; } + async stopServices(): Promise { + return Promise.resolve({stderr: "", stdout: "", exitCode: 0}); + } } export class ProjectDataService implements IProjectDataService { @@ -589,7 +592,7 @@ export class PlatformServiceStub implements IPlatformService { return []; } - public removePlatforms(platforms: string[]): void { + public async removePlatforms(platforms: string[]): Promise { }