From afdb0213a0ea291d22cba5b3be2247cf8e143d6c Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 23 Apr 2019 09:47:35 +0300 Subject: [PATCH 1/2] fix: prepare xcconfig files for all conigurations Currently CLI merges and prepares xcconfig files only for the current build configuration, i.e. debug or release. However, the `pod install` command works with both configurations. This leads to problem when some property is set in the project's (plugin's) build.xcconfig file as CLI will prepare the native iOS project only for one configuration. When `pod install` is executed, if the Pods project uses the property set in the build.xcconfig file, it will fail with error, as the value for debug and release will be different (i.e. it will be set only for one of them). Pods project does not support this behavior, so the build operation fails. So, ensure CLI merges all xcconfig files for both debug and release configurations. This way, the Pods project will be in sync, so it should continue its execution. This is important when using Cocoapods 1.6.0+ where some changes are applied for Swift support, which can be workarounded by setting SWIFT_VERSION in project's build.xcconfig file. --- lib/declarations.d.ts | 7 ++-- lib/services/cocoapods-service.ts | 12 ++++--- lib/services/ios-project-service.ts | 53 ++++++++++++++++----------- lib/services/xcconfig-service.ts | 12 +++---- test/ios-project-service.ts | 56 +++++++++++++++-------------- 5 files changed, 77 insertions(+), 63 deletions(-) diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index e3e75e604b..7972c678dc 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -890,12 +890,11 @@ interface IXcprojInfo { interface IXcconfigService { /** - * Returns the path to the xcconfig file + * Returns the paths to the xcconfig files for build configuration (debug/release) * @param projectRoot The path to root folder of native project (platforms/ios) - * @param opts - * @returns {string} + * @returns {IStringDictionary} */ - getPluginsXcconfigFilePath(projectRoot: string, opts: IRelease): string; + getPluginsXcconfigFilePaths(projectRoot: string): IStringDictionary; /** * Returns the value of a property from a xcconfig file. diff --git a/lib/services/cocoapods-service.ts b/lib/services/cocoapods-service.ts index b25a7daa13..da08ec1252 100644 --- a/lib/services/cocoapods-service.ts +++ b/lib/services/cocoapods-service.ts @@ -55,14 +55,16 @@ export class CocoaPodsService implements ICocoaPodsService { return podInstallResult; } - public async mergePodXcconfigFile(projectData: IProjectData, platformData: IPlatformData, opts: IRelease) { + public async mergePodXcconfigFile(projectData: IProjectData, platformData: IPlatformData): Promise { const podFilesRootDirName = path.join("Pods", "Target Support Files", `Pods-${projectData.projectName}`); const podFolder = path.join(platformData.projectRoot, podFilesRootDirName); if (this.$fs.exists(podFolder)) { - const podXcconfigFilePath = opts && opts.release ? path.join(podFolder, `Pods-${projectData.projectName}.release.xcconfig`) - : path.join(podFolder, `Pods-${projectData.projectName}.debug.xcconfig`); - const pluginsXcconfigFilePath = this.$xcconfigService.getPluginsXcconfigFilePath(platformData.projectRoot, opts); - await this.$xcconfigService.mergeFiles(podXcconfigFilePath, pluginsXcconfigFilePath); + const pluginsXcconfigFilePaths = this.$xcconfigService.getPluginsXcconfigFilePaths(platformData.projectRoot); + for (const configuration in pluginsXcconfigFilePaths) { + const pluginsXcconfigFilePath = pluginsXcconfigFilePaths[configuration]; + const podXcconfigFilePath = path.join(podFolder, `Pods-${projectData.projectName}.${configuration}.xcconfig`); + await this.$xcconfigService.mergeFiles(podXcconfigFilePath, pluginsXcconfigFilePath); + } } } diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index 85960e4ec2..820677b4d6 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -799,7 +799,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f public async processConfigurationFilesFromAppResources(projectData: IProjectData, opts: IRelease): Promise { await this.mergeInfoPlists(projectData, opts); await this.$iOSEntitlementsService.merge(projectData); - await this.mergeProjectXcconfigFiles(projectData, opts); + await this.mergeProjectXcconfigFiles(projectData); for (const pluginData of await this.getAllInstalledPlugins(projectData)) { await this.$pluginVariablesService.interpolatePluginVariables(pluginData, this.getPlatformData(projectData).configurationFilePath, projectData.projectDir); } @@ -1216,10 +1216,13 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f this.$fs.writeFile(path.join(headersFolderPath, "module.modulemap"), modulemap); } - private async mergeProjectXcconfigFiles(projectData: IProjectData, opts: IRelease): Promise { + private async mergeProjectXcconfigFiles(projectData: IProjectData): Promise { const platformData = this.getPlatformData(projectData); - const pluginsXcconfigFilePath = this.$xcconfigService.getPluginsXcconfigFilePath(platformData.projectRoot, opts); - this.$fs.deleteFile(pluginsXcconfigFilePath); + const pluginsXcconfigFilePaths = _.values(this.$xcconfigService.getPluginsXcconfigFilePaths(platformData.projectRoot)); + + for (const pluginsXcconfigFilePath of pluginsXcconfigFilePaths) { + this.$fs.deleteFile(pluginsXcconfigFilePath); + } const pluginsService = this.$injector.resolve("pluginsService"); const allPlugins: IPluginData[] = await pluginsService.getAllInstalledPlugins(projectData); @@ -1227,32 +1230,40 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f const pluginPlatformsFolderPath = plugin.pluginPlatformsFolderPath(IOSProjectService.IOS_PLATFORM_NAME); const pluginXcconfigFilePath = path.join(pluginPlatformsFolderPath, BUILD_XCCONFIG_FILE_NAME); if (this.$fs.exists(pluginXcconfigFilePath)) { - await this.$xcconfigService.mergeFiles(pluginXcconfigFilePath, pluginsXcconfigFilePath); + for (const pluginsXcconfigFilePath of pluginsXcconfigFilePaths) { + await this.$xcconfigService.mergeFiles(pluginXcconfigFilePath, pluginsXcconfigFilePath); + } } } const appResourcesXcconfigPath = path.join(projectData.appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, BUILD_XCCONFIG_FILE_NAME); if (this.$fs.exists(appResourcesXcconfigPath)) { - await this.$xcconfigService.mergeFiles(appResourcesXcconfigPath, pluginsXcconfigFilePath); + for (const pluginsXcconfigFilePath of pluginsXcconfigFilePaths) { + await this.$xcconfigService.mergeFiles(appResourcesXcconfigPath, pluginsXcconfigFilePath); + } } - if (!this.$fs.exists(pluginsXcconfigFilePath)) { - // We need the pluginsXcconfig file to exist in platforms dir as it is required in the native template: - // https://github.com/NativeScript/ios-runtime/blob/9c2b7b5f70b9bee8452b7a24aa6b646214c7d2be/build/project-template/__PROJECT_NAME__/build-debug.xcconfig#L3 - // From Xcode 10 in case the file is missing, this include fails and the build itself fails (was a warning in previous Xcode versions). - this.$fs.writeFile(pluginsXcconfigFilePath, ""); + for (const pluginsXcconfigFilePath of pluginsXcconfigFilePaths) { + if (!this.$fs.exists(pluginsXcconfigFilePath)) { + // We need the pluginsXcconfig file to exist in platforms dir as it is required in the native template: + // https://github.com/NativeScript/ios-runtime/blob/9c2b7b5f70b9bee8452b7a24aa6b646214c7d2be/build/project-template/__PROJECT_NAME__/build-debug.xcconfig#L3 + // From Xcode 10 in case the file is missing, this include fails and the build itself fails (was a warning in previous Xcode versions). + this.$fs.writeFile(pluginsXcconfigFilePath, ""); + } } - // Set Entitlements Property to point to default file if not set explicitly by the user. - const entitlementsPropertyValue = this.$xcconfigService.readPropertyValue(pluginsXcconfigFilePath, constants.CODE_SIGN_ENTITLEMENTS); - if (entitlementsPropertyValue === null && this.$fs.exists(this.$iOSEntitlementsService.getPlatformsEntitlementsPath(projectData))) { - temp.track(); - const tempEntitlementsDir = temp.mkdirSync("entitlements"); - const tempEntitlementsFilePath = path.join(tempEntitlementsDir, "set-entitlements.xcconfig"); - const entitlementsRelativePath = this.$iOSEntitlementsService.getPlatformsEntitlementsRelativePath(projectData); - this.$fs.writeFile(tempEntitlementsFilePath, `CODE_SIGN_ENTITLEMENTS = ${entitlementsRelativePath}${EOL}`); - - await this.$xcconfigService.mergeFiles(tempEntitlementsFilePath, pluginsXcconfigFilePath); + for (const pluginsXcconfigFilePath of pluginsXcconfigFilePaths) { + // Set Entitlements Property to point to default file if not set explicitly by the user. + const entitlementsPropertyValue = this.$xcconfigService.readPropertyValue(pluginsXcconfigFilePath, constants.CODE_SIGN_ENTITLEMENTS); + if (entitlementsPropertyValue === null && this.$fs.exists(this.$iOSEntitlementsService.getPlatformsEntitlementsPath(projectData))) { + temp.track(); + const tempEntitlementsDir = temp.mkdirSync("entitlements"); + const tempEntitlementsFilePath = path.join(tempEntitlementsDir, "set-entitlements.xcconfig"); + const entitlementsRelativePath = this.$iOSEntitlementsService.getPlatformsEntitlementsRelativePath(projectData); + this.$fs.writeFile(tempEntitlementsFilePath, `CODE_SIGN_ENTITLEMENTS = ${entitlementsRelativePath}${EOL}`); + + await this.$xcconfigService.mergeFiles(tempEntitlementsFilePath, pluginsXcconfigFilePath); + } } } diff --git a/lib/services/xcconfig-service.ts b/lib/services/xcconfig-service.ts index 59a33353ec..896778536f 100644 --- a/lib/services/xcconfig-service.ts +++ b/lib/services/xcconfig-service.ts @@ -1,4 +1,5 @@ import * as path from "path"; +import { Configurations } from "../common/constants"; export class XcconfigService implements IXcconfigService { constructor( @@ -6,12 +7,11 @@ export class XcconfigService implements IXcconfigService { private $fs: IFileSystem, private $xcprojService: IXcprojService) { } - public getPluginsXcconfigFilePath(projectRoot: string, opts: IRelease): string { - if (opts && opts.release) { - return this.getPluginsReleaseXcconfigFilePath(projectRoot); - } - - return this.getPluginsDebugXcconfigFilePath(projectRoot); + public getPluginsXcconfigFilePaths(projectRoot: string): IStringDictionary { + return { + [Configurations.Debug.toLowerCase()]: this.getPluginsDebugXcconfigFilePath(projectRoot), + [Configurations.Release.toLowerCase()]: this.getPluginsReleaseXcconfigFilePath(projectRoot) + }; } private getPluginsDebugXcconfigFilePath(projectRoot: string): string { diff --git a/test/ios-project-service.ts b/test/ios-project-service.ts index 74468e6e6b..dc6fbc249a 100644 --- a/test/ios-project-service.ts +++ b/test/ios-project-service.ts @@ -1178,17 +1178,19 @@ describe("Merge Project XCConfig files", () => { // run merge for all release: debug|release for (const release in [true, false]) { - await (iOSProjectService).mergeProjectXcconfigFiles(projectData, { release }); + await (iOSProjectService).mergeProjectXcconfigFiles(projectData); - const destinationFilePath = xcconfigService.getPluginsXcconfigFilePath(projectRoot, { release: !!release }); + const destinationFilePaths = xcconfigService.getPluginsXcconfigFilePaths(projectRoot); - assert.isTrue(fs.exists(destinationFilePath), 'Target build xcconfig is missing for release: ' + release); - const expected = { - 'ASSETCATALOG_COMPILER_APPICON_NAME': 'AppIcon', - 'ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME': 'LaunchImage', - 'CODE_SIGN_IDENTITY': 'iPhone Distribution' - }; - assertPropertyValues(expected, destinationFilePath, testInjector); + _.each(destinationFilePaths, destinationFilePath => { + assert.isTrue(fs.exists(destinationFilePath), 'Target build xcconfig is missing for release: ' + release); + const expected = { + 'ASSETCATALOG_COMPILER_APPICON_NAME': 'AppIcon', + 'ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME': 'LaunchImage', + 'CODE_SIGN_IDENTITY': 'iPhone Distribution' + }; + assertPropertyValues(expected, destinationFilePath, testInjector); + }); } }); @@ -1206,13 +1208,15 @@ describe("Merge Project XCConfig files", () => { await (iOSProjectService).mergeProjectXcconfigFiles(projectData, { release }); - const destinationFilePath = xcconfigService.getPluginsXcconfigFilePath(projectRoot, { release: !!release }); + const destinationFilePaths = xcconfigService.getPluginsXcconfigFilePaths(projectRoot); - assert.isTrue(fs.exists(destinationFilePath), 'Target build xcconfig is missing for release: ' + release); - const expected = { - 'CODE_SIGN_ENTITLEMENTS': iOSEntitlementsService.getPlatformsEntitlementsRelativePath(projectData) - }; - assertPropertyValues(expected, destinationFilePath, testInjector); + _.each(destinationFilePaths, destinationFilePath => { + assert.isTrue(fs.exists(destinationFilePath), 'Target build xcconfig is missing for release: ' + release); + const expected = { + 'CODE_SIGN_ENTITLEMENTS': iOSEntitlementsService.getPlatformsEntitlementsRelativePath(projectData) + }; + assertPropertyValues(expected, destinationFilePath, testInjector); + }); } }); @@ -1222,13 +1226,12 @@ describe("Merge Project XCConfig files", () => { const xcconfigEntitlements = appResourceXCConfigContent + `${EOL}CODE_SIGN_ENTITLEMENTS = ${expectedEntitlementsFile}`; fs.writeFile(appResourcesXcconfigPath, xcconfigEntitlements); - // run merge for all release: debug|release - for (const release in [true, false]) { - await (iOSProjectService).mergeProjectXcconfigFiles(projectData, { release }); + await (iOSProjectService).mergeProjectXcconfigFiles(projectData); - const destinationFilePath = xcconfigService.getPluginsXcconfigFilePath(projectRoot, { release: !!release }); + const destinationFilePaths = xcconfigService.getPluginsXcconfigFilePaths(projectRoot); - assert.isTrue(fs.exists(destinationFilePath), 'Target build xcconfig is missing for release: ' + release); + _.each(destinationFilePaths, destinationFilePath => { + assert.isTrue(fs.exists(destinationFilePath), `Target build xcconfig ${destinationFilePath} is missing.`); const expected = { 'ASSETCATALOG_COMPILER_APPICON_NAME': 'AppIcon', 'ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME': 'LaunchImage', @@ -1236,20 +1239,19 @@ describe("Merge Project XCConfig files", () => { 'CODE_SIGN_ENTITLEMENTS': expectedEntitlementsFile }; assertPropertyValues(expected, destinationFilePath, testInjector); - } + }); }); it("creates empty plugins-.xcconfig in case there are no build.xcconfig in App_Resources and in plugins", async () => { - // run merge for all release: debug|release - for (const release in [true, false]) { - await (iOSProjectService).mergeProjectXcconfigFiles(projectData, { release }); + await (iOSProjectService).mergeProjectXcconfigFiles(projectData); - const destinationFilePath = xcconfigService.getPluginsXcconfigFilePath(projectRoot, { release: !!release }); + const destinationFilePaths = xcconfigService.getPluginsXcconfigFilePaths(projectRoot); - assert.isTrue(fs.exists(destinationFilePath), 'Target build xcconfig is missing for release: ' + release); + _.each(destinationFilePaths, destinationFilePath => { + assert.isTrue(fs.exists(destinationFilePath), `Target build xcconfig ${destinationFilePath} is missing.` ); const content = fs.readFile(destinationFilePath).toString(); assert.equal(content, ""); - } + }); }); }); From a2d109896b5f0459f2edd1c3eb76c651caa9d03b Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 23 Apr 2019 12:29:09 +0300 Subject: [PATCH 2/2] chore: set version to 5.3.4 --- npm-shrinkwrap.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 7d4916d98d..a79a750442 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "nativescript", - "version": "5.3.3", + "version": "5.3.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 05ddfb92a6..cf27bebdd3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nativescript", "preferGlobal": true, - "version": "5.3.3", + "version": "5.3.4", "author": "Telerik ", "description": "Command-line interface for building NativeScript projects", "bin": {