From d8e02ca2c4cf4cf779138e3dd44a48e70920c7d7 Mon Sep 17 00:00:00 2001 From: rosen-vladimirov Date: Tue, 20 Mar 2018 16:20:58 +0200 Subject: [PATCH] feat: Expose paths to project configuration files in projectData Expose new properties in `projectData` with paths to specific configuration files. This allows all tools that require CLI to get these paths and will not require changes in them when the structure of project is modified. Introduce additional constants and use them in the code --- lib/constants.ts | 3 +++ lib/definitions/project.d.ts | 6 +++++ lib/project-data.ts | 23 ++++++++++++++++++- lib/services/android-project-service.ts | 8 +++---- .../android-resources-migration-service.ts | 2 +- lib/services/ios-project-service.ts | 17 +++++++------- lib/services/itmstransporter-service.ts | 4 ++-- lib/services/project-changes-service.ts | 6 ++--- test/ios-project-service.ts | 3 ++- test/platform-service.ts | 3 ++- test/plugin-variables-service.ts | 5 ++++ test/project-data.ts | 7 ++++++ test/services/android-plugin-build-service.ts | 5 ++-- test/stubs.ts | 6 +++++ 14 files changed, 74 insertions(+), 24 deletions(-) diff --git a/lib/constants.ts b/lib/constants.ts index c8f5e556b6..1ff3ad5f49 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -24,7 +24,10 @@ export const SRC_DIR = "src"; export const MAIN_DIR = "main"; export const ASSETS_DIR = "assets"; export const MANIFEST_FILE_NAME = "AndroidManifest.xml"; +export const APP_GRADLE_FILE_NAME = "app.gradle"; +export const INFO_PLIST_FILE_NAME = "Info.plist"; export const INCLUDE_GRADLE_NAME = "include.gradle"; +export const BUILD_XCCONFIG_FILE_NAME = "build.xcconfig"; export const BUILD_DIR = "build"; export const OUTPUTS_DIR = "outputs"; export const APK_DIR = "apk"; diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index 8c8710fa94..224f4122bf 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -69,6 +69,12 @@ interface IProjectData extends IProjectDir { appResourcesDirectoryPath: string; projectType: string; nsConfig: INsConfig; + androidManifestPath: string; + appGradlePath: string; + gradleFilesDirectoryPath: string; + infoPlistPath: string; + buildXcconfigPath: string; + /** * Initializes project data with the given project directory. If none supplied defaults to --path option or cwd. * @param {string} projectDir Project root directory. diff --git a/lib/project-data.ts b/lib/project-data.ts index f5bc33b325..90cda0cdac 100644 --- a/lib/project-data.ts +++ b/lib/project-data.ts @@ -43,13 +43,20 @@ export class ProjectData implements IProjectData { public dependencies: any; public devDependencies: IStringDictionary; public projectType: string; + public androidManifestPath: string; + public infoPlistPath: string; + public appGradlePath: string; + public gradleFilesDirectoryPath: string; + public buildXcconfigPath: string; constructor(private $fs: IFileSystem, private $errors: IErrors, private $projectHelper: IProjectHelper, private $staticConfig: IStaticConfig, private $options: IOptions, - private $logger: ILogger) { } + private $logger: ILogger, + private $androidResourcesMigrationService: IAndroidResourcesMigrationService, + private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants) { } public initializeProjectData(projectDir?: string): void { projectDir = projectDir || this.$projectHelper.projectDir; @@ -108,6 +115,11 @@ export class ProjectData implements IProjectData { this.nsConfig = nsConfig; this.appDirectoryPath = this.getAppDirectoryPath(); this.appResourcesDirectoryPath = this.getAppResourcesDirectoryPath(); + this.androidManifestPath = this.getPathToAndroidManifest(this.appResourcesDirectoryPath); + this.gradleFilesDirectoryPath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.Android); + this.appGradlePath = path.join(this.gradleFilesDirectoryPath, constants.APP_GRADLE_FILE_NAME); + this.infoPlistPath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.INFO_PLIST_FILE_NAME); + this.buildXcconfigPath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.BUILD_XCCONFIG_FILE_NAME); return; } @@ -115,6 +127,15 @@ export class ProjectData implements IProjectData { this.errorInvalidProject(projectDir); } + private getPathToAndroidManifest(appResourcesDir: string): string { + const androidDirPath = path.join(appResourcesDir, this.$devicePlatformsConstants.Android); + const androidManifestDir = this.$androidResourcesMigrationService.hasMigrated(appResourcesDir) ? + path.join(androidDirPath, constants.SRC_DIR, constants.MAIN_DIR) : + androidDirPath; + + return path.join(androidManifestDir, constants.MANIFEST_FILE_NAME); + } + private errorInvalidProject(projectDir: string): void { const currentDir = path.resolve("."); this.$logger.trace(`Unable to find project. projectDir: ${projectDir}, options.path: ${this.$options.path}, ${currentDir}`); diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index 2558a2d8bb..50505a5daf 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -256,11 +256,9 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject const gradleSettingsFilePath = path.join(this.getPlatformData(projectData).projectRoot, "settings.gradle"); shell.sed('-i', /__PROJECT_NAME__/, this.getProjectNameFromId(projectData), gradleSettingsFilePath); - // will replace applicationId in app/App_Resources/Android/app.gradle if it has not been edited by the user - const userAppGradleFilePath = path.join(projectData.appResourcesDirectoryPath, this.$devicePlatformsConstants.Android, "app.gradle"); - try { - shell.sed('-i', /__PACKAGE__/, projectData.projectId, userAppGradleFilePath); + // will replace applicationId in app/App_Resources/Android/app.gradle if it has not been edited by the user + shell.sed('-i', /__PACKAGE__/, projectData.projectId, projectData.appGradlePath); } catch (e) { this.$logger.warn(`\n${e}.\nCheck if you're using an outdated template and update it.`); } @@ -520,7 +518,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject } // Copy include.gradle file - const includeGradleFilePath = path.join(pluginPlatformsFolderPath, "include.gradle"); + const includeGradleFilePath = path.join(pluginPlatformsFolderPath, constants.INCLUDE_GRADLE_NAME); if (this.$fs.exists(includeGradleFilePath)) { shell.cp("-f", includeGradleFilePath, pluginConfigurationDirectoryPath); } diff --git a/lib/services/android-resources-migration-service.ts b/lib/services/android-resources-migration-service.ts index 75e6959673..612fe07558 100644 --- a/lib/services/android-resources-migration-service.ts +++ b/lib/services/android-resources-migration-service.ts @@ -37,7 +37,7 @@ export class AndroidResourcesMigrationService implements IAndroidResourcesMigrat const getDirectories = (files: string[]) => files.filter(isDirectory); const getFiles = (files: string[]) => files.filter((file: string) => !isDirectory(file)); - this.$fs.copyFile(path.join(originalAppResources, "app.gradle"), path.join(appResourcesDestination, "app.gradle")); + this.$fs.copyFile(path.join(originalAppResources, constants.APP_GRADLE_FILE_NAME), path.join(appResourcesDestination, constants.APP_GRADLE_FILE_NAME)); const appResourcesFiles = getAllFiles(originalAppResources); const resourceDirectories = getDirectories(appResourcesFiles); diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index ee5d65a1de..365aa08448 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -16,6 +16,7 @@ import { XCConfigService } from "./xcconfig-service"; import * as simplePlist from "simple-plist"; import * as mobileprovision from "ios-mobileprovision-finder"; import { SpawnOptions } from "child_process"; +import { BUILD_XCCONFIG_FILE_NAME } from "../constants"; export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase implements IPlatformProjectService { private static XCODE_PROJECT_EXT_NAME = ".xcodeproj"; @@ -89,8 +90,8 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ frameworkDirectoriesExtensions: [".framework"], frameworkDirectoriesNames: ["Metadata", "metadataGenerator", "NativeScript", "internal"], targetedOS: ['darwin'], - configurationFileName: "Info.plist", - configurationFilePath: path.join(projectRoot, projectData.projectName, projectData.projectName + "-Info.plist"), + configurationFileName: constants.INFO_PLIST_FILE_NAME, + configurationFilePath: path.join(projectRoot, projectData.projectName, projectData.projectName + `-${constants.INFO_PLIST_FILE_NAME}`), relativeToFrameworkConfigurationFilePath: path.join("__PROJECT_NAME__", "__PROJECT_NAME__-Info.plist"), fastLivesyncFileExtensions: [".tiff", ".tif", ".jpg", "jpeg", "gif", ".png", ".bmp", ".BMPf", ".ico", ".cur", ".xbm"] // https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/ }; @@ -338,7 +339,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ // Starting from tns-ios 1.4 the xcconfig file is referenced in the project template const frameworkVersion = this.getFrameworkVersion(this.getPlatformData(projectData).frameworkPackageName, projectData.projectDir); if (semver.lt(frameworkVersion, "1.4.0")) { - basicArgs.push("-xcconfig", path.join(projectRoot, projectData.projectName, "build.xcconfig")); + basicArgs.push("-xcconfig", path.join(projectRoot, projectData.projectName, BUILD_XCCONFIG_FILE_NAME)); } // if (this.$logger.getLevel() === "INFO") { @@ -1039,7 +1040,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f } private validateFramework(libraryPath: string): void { - const infoPlistPath = path.join(libraryPath, "Info.plist"); + const infoPlistPath = path.join(libraryPath, constants.INFO_PLIST_FILE_NAME); if (!this.$fs.exists(infoPlistPath)) { this.$errors.failWithoutHelp("The bundle at %s does not contain an Info.plist file.", libraryPath); } @@ -1227,13 +1228,13 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f const allPlugins: IPluginData[] = await (this.$injector.resolve("pluginsService")).getAllInstalledPlugins(projectData); for (const plugin of allPlugins) { const pluginPlatformsFolderPath = plugin.pluginPlatformsFolderPath(IOSProjectService.IOS_PLATFORM_NAME); - const pluginXcconfigFilePath = path.join(pluginPlatformsFolderPath, "build.xcconfig"); + const pluginXcconfigFilePath = path.join(pluginPlatformsFolderPath, BUILD_XCCONFIG_FILE_NAME); if (this.$fs.exists(pluginXcconfigFilePath)) { await this.mergeXcconfigFiles(pluginXcconfigFilePath, pluginsXcconfigFilePath); } } - const appResourcesXcconfigPath = path.join(projectData.appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, "build.xcconfig"); + const appResourcesXcconfigPath = path.join(projectData.appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, BUILD_XCCONFIG_FILE_NAME); if (this.$fs.exists(appResourcesXcconfigPath)) { await this.mergeXcconfigFiles(appResourcesXcconfigPath, pluginsXcconfigFilePath); } @@ -1289,7 +1290,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f private getBuildXCConfigFilePath(projectData: IProjectData): string { const buildXCConfig = path.join(projectData.appResourcesDirectoryPath, - this.getPlatformData(projectData).normalizedPlatformName, "build.xcconfig"); + this.getPlatformData(projectData).normalizedPlatformName, BUILD_XCCONFIG_FILE_NAME); return buildXCConfig; } @@ -1350,7 +1351,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f const choicePersist = await this.$prompter.promptForChoice("Do you want to make teamId: " + teamId + " a persistent choice for your app?", choicesPersist); switch (choicesPersist.indexOf(choicePersist)) { case 0: - const xcconfigFile = path.join(projectData.appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, "build.xcconfig"); + const xcconfigFile = path.join(projectData.appResourcesDirectoryPath, this.getPlatformData(projectData).normalizedPlatformName, BUILD_XCCONFIG_FILE_NAME); this.$fs.appendFile(xcconfigFile, "\nDEVELOPMENT_TEAM = " + teamId + "\n"); break; case 1: diff --git a/lib/services/itmstransporter-service.ts b/lib/services/itmstransporter-service.ts index 83dbbf3698..e60b23da2c 100644 --- a/lib/services/itmstransporter-service.ts +++ b/lib/services/itmstransporter-service.ts @@ -1,7 +1,7 @@ import * as path from "path"; import * as temp from "temp"; import { EOL } from "os"; -import { ITMSConstants } from "../constants"; +import { ITMSConstants, INFO_PLIST_FILE_NAME } from "../constants"; import { ItunesConnectApplicationTypes } from "../constants"; import { quoteString, versionCompare } from "../common/helpers"; @@ -135,7 +135,7 @@ export class ITMSTransporterService implements IITMSTransporterService { } const appFile = path.join(payloadDir, allApps[0]); - const plistObject = await this.$bplistParser.parseFile(path.join(appFile, "Info.plist")); + const plistObject = await this.$bplistParser.parseFile(path.join(appFile, INFO_PLIST_FILE_NAME)); const bundleId = plistObject && plistObject[0] && plistObject[0].CFBundleIdentifier; if (!bundleId) { this.$errors.failWithoutHelp(`Unable to determine bundle identifier from ${ipaFileFullPath}.`); diff --git a/lib/services/project-changes-service.ts b/lib/services/project-changes-service.ts index 334ba8cad8..6af8e7e5c0 100644 --- a/lib/services/project-changes-service.ts +++ b/lib/services/project-changes-service.ts @@ -1,5 +1,5 @@ import * as path from "path"; -import { NODE_MODULES_FOLDER_NAME, NativePlatformStatus, PACKAGE_JSON_FILE_NAME } from "../constants"; +import { NODE_MODULES_FOLDER_NAME, NativePlatformStatus, PACKAGE_JSON_FILE_NAME, APP_GRADLE_FILE_NAME, BUILD_XCCONFIG_FILE_NAME } from "../constants"; import { getHash } from "../common/helpers"; const prepareInfoFileName = ".nsprepareinfo"; @@ -77,12 +77,12 @@ export class ProjectChangesService implements IProjectChangesService { if (platform === this.$devicePlatformsConstants.iOS.toLowerCase()) { this._changesInfo.configChanged = this.filesChanged([path.join(platformResourcesDir, platformData.configurationFileName), path.join(platformResourcesDir, "LaunchScreen.storyboard"), - path.join(platformResourcesDir, "build.xcconfig") + path.join(platformResourcesDir, BUILD_XCCONFIG_FILE_NAME) ]); } else { this._changesInfo.configChanged = this.filesChanged([ path.join(platformResourcesDir, platformData.configurationFileName), - path.join(platformResourcesDir, "app.gradle") + path.join(platformResourcesDir, APP_GRADLE_FILE_NAME) ]); } } diff --git a/test/ios-project-service.ts b/test/ios-project-service.ts index 3e383a35fb..8e9a09626c 100644 --- a/test/ios-project-service.ts +++ b/test/ios-project-service.ts @@ -33,6 +33,7 @@ import { NodePackageManager } from "../lib/node-package-manager"; import { assert } from "chai"; import { IOSProvisionService } from "../lib/services/ios-provision-service"; import { SettingsService } from "../lib/common/test/unit-tests/stubs"; +import { BUILD_XCCONFIG_FILE_NAME } from "../lib/constants"; import { ProjectDataStub } from "./stubs"; import temp = require("temp"); @@ -800,7 +801,7 @@ describe("Merge Project XCConfig files", () => { iOSEntitlementsService = testInjector.resolve("iOSEntitlementsService"); - appResourcesXcconfigPath = path.join(projectData.appResourcesDirectoryPath, "iOS", "build.xcconfig"); + appResourcesXcconfigPath = path.join(projectData.appResourcesDirectoryPath, "iOS", BUILD_XCCONFIG_FILE_NAME); appResourceXCConfigContent = `CODE_SIGN_IDENTITY = iPhone Distribution // To build for device with XCode 8 you need to specify your development team. More info: https://developer.apple.com/library/prerelease/content/releasenotes/DeveloperTools/RN-Xcode/Introduction.html // DEVELOPMENT_TEAM = YOUR_TEAM_ID; diff --git a/test/platform-service.ts b/test/platform-service.ts index 8faa479779..f765d84d69 100644 --- a/test/platform-service.ts +++ b/test/platform-service.ts @@ -22,6 +22,7 @@ import * as ChildProcessLib from "../lib/common/child-process"; import ProjectChangesLib = require("../lib/services/project-changes-service"); import { Messages } from "../lib/common/messages/messages"; import { SettingsService } from "../lib/common/test/unit-tests/stubs"; +import { INFO_PLIST_FILE_NAME, MANIFEST_FILE_NAME } from "../lib/constants"; require("should"); const temp = require("temp"); @@ -425,7 +426,7 @@ describe('Platform Service Tests', () => { appDestinationDirectoryPath: testDirData.appDestFolderPath, appResourcesDestinationDirectoryPath: testDirData.appResourcesFolderPath, normalizedPlatformName: platformToTest, - configurationFileName: platformToTest === "ios" ? "Info.plist" : "AndroidManifest.xml", + configurationFileName: platformToTest === "ios" ? INFO_PLIST_FILE_NAME : MANIFEST_FILE_NAME, projectRoot: testDirData.tempFolder, platformProjectService: { prepareProject: (): any => null, diff --git a/test/plugin-variables-service.ts b/test/plugin-variables-service.ts index 6e51f32899..c99f24cb11 100644 --- a/test/plugin-variables-service.ts +++ b/test/plugin-variables-service.ts @@ -12,6 +12,7 @@ import { StaticConfig } from "../lib/config"; import { MessagesService } from "../lib/common/services/messages-service"; import { Yok } from '../lib/common/yok'; import { SettingsService } from "../lib/common/test/unit-tests/stubs"; +import { DevicePlatformsConstants } from "../lib/common/mobile/device-platforms-constants"; import * as stubs from './stubs'; import * as path from "path"; import * as temp from "temp"; @@ -39,6 +40,10 @@ function createTestInjector(): IInjector { }); testInjector.register("staticConfig", StaticConfig); testInjector.register("settingsService", SettingsService); + testInjector.register("devicePlatformsConstants", DevicePlatformsConstants); + testInjector.register("androidResourcesMigrationService", { + hasMigrated: () => true + }); return testInjector; } diff --git a/test/project-data.ts b/test/project-data.ts index 67f1a2775b..5a465b6611 100644 --- a/test/project-data.ts +++ b/test/project-data.ts @@ -1,5 +1,6 @@ import { ProjectData } from "../lib/project-data"; import { Yok } from "../lib/common/yok"; +import { DevicePlatformsConstants } from "../lib/common/mobile/device-platforms-constants"; import { assert } from "chai"; import * as stubs from "./stubs"; import * as path from "path"; @@ -30,6 +31,12 @@ describe("projectData", () => { testInjector.register("options", {}); + testInjector.register("devicePlatformsConstants", DevicePlatformsConstants); + + testInjector.register("androidResourcesMigrationService", { + hasMigrated: () => true + }); + testInjector.register("projectData", ProjectData); return testInjector; diff --git a/test/services/android-plugin-build-service.ts b/test/services/android-plugin-build-service.ts index 51b58372a6..da3c77049f 100644 --- a/test/services/android-plugin-build-service.ts +++ b/test/services/android-plugin-build-service.ts @@ -7,6 +7,7 @@ import { HostInfo } from "../../lib/common/host-info"; import { Logger } from "../../lib/common/logger"; import * as ErrorsLib from "../../lib/common/errors"; import temp = require("temp"); +import { INCLUDE_GRADLE_NAME } from "../../lib/constants"; temp.track(); describe('androiPluginBuildService', () => { @@ -65,7 +66,7 @@ dependencies { compile "com.android.support:design:$supportVersion" }`; - fs.writeFile(path.join(pluginFolder, "include.gradle"), validIncludeGradleContent); + fs.writeFile(path.join(pluginFolder, INCLUDE_GRADLE_NAME), validIncludeGradleContent); } function setUpPluginNativeFolder(manifestFile: boolean, resFolder: boolean, assetsFolder: boolean) { @@ -196,7 +197,7 @@ dependencies { tempPluginDirPath: pluginFolder }; - const includeGradleName = "include.gradle"; + const includeGradleName = INCLUDE_GRADLE_NAME; await androidBuildPluginService.migrateIncludeGradle(config); const includeGradleContent = fs.readText(path.join(pluginFolder, includeGradleName).toString()); const productFlavorsAreRemoved = includeGradleContent.indexOf("productFlavors") === -1; diff --git a/test/stubs.ts b/test/stubs.ts index c355a92939..8fb02569e6 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -258,6 +258,12 @@ export class ProjectDataStub implements IProjectData { devDependencies: IStringDictionary; projectType: string; appResourcesDirectoryPath: string; + public androidManifestPath: string; + public infoPlistPath: string; + public appGradlePath: string; + public gradleFilesDirectoryPath: string; + public buildXcconfigPath: string; + public initializeProjectData(projectDir?: string): void { this.projectDir = this.projectDir || projectDir; }