diff --git a/Gruntfile.js b/Gruntfile.js index 2426df2e34..7dc046d1f4 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -185,5 +185,6 @@ module.exports = function(grunt) { ]); grunt.registerTask("lint", ["tslint:build"]); grunt.registerTask("all", ["clean", "test", "lint"]); + grunt.registerTask("rebuild", ["clean", "ts:devlib"]); grunt.registerTask("default", "ts:devlib"); }; diff --git a/lib/common b/lib/common index 3feb39e136..62f64d02db 160000 --- a/lib/common +++ b/lib/common @@ -1 +1 @@ -Subproject commit 3feb39e13643951a7ecb64e19cb895fce1024c4c +Subproject commit 62f64d02db5363f8d464222559ed73aad9b8861d diff --git a/lib/declarations.ts b/lib/declarations.ts index 7616b92968..eb50d1666f 100644 --- a/lib/declarations.ts +++ b/lib/declarations.ts @@ -83,6 +83,7 @@ interface IOptions extends ICommonOptions { port: Number; copyTo: string; baseConfig: string; + platformTemplate: string; } interface IInitService { diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index 99f6bd3719..5b2a72aabc 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -55,7 +55,7 @@ interface IBuildConfig { interface IPlatformProjectService { platformData: IPlatformData; validate(): IFuture; - createProject(frameworkDir: string, frameworkVersion: string): IFuture; + createProject(frameworkDir: string, frameworkVersion: string, pathToTemplate?: string): IFuture; interpolateData(): IFuture; interpolateConfigurationFile(configurationFilePath?: string): IFuture; afterCreateProject(projectRoot: string): IFuture; diff --git a/lib/nativescript-cli.ts b/lib/nativescript-cli.ts index a06792c38f..3e7d989aee 100644 --- a/lib/nativescript-cli.ts +++ b/lib/nativescript-cli.ts @@ -9,6 +9,7 @@ import * as fiber from "fibers"; import Future = require("fibers/future"); import * as shelljs from "shelljs"; shelljs.config.silent = true; +shelljs.config.fatal = true; import {installUncaughtExceptionListener} from "./common/errors"; installUncaughtExceptionListener(process.exit); diff --git a/lib/options.ts b/lib/options.ts index 17a58c567c..67be850eed 100644 --- a/lib/options.ts +++ b/lib/options.ts @@ -33,7 +33,8 @@ export class Options extends commonOptionsLibPath.OptionsBase { compileSdk: {type: OptionType.Number }, port: { type: OptionType.Number }, copyTo: { type: OptionType.String }, - baseConfig: { type: OptionType.String } + baseConfig: { type: OptionType.String }, + platformTemplate: { type: OptionType.String } }, path.join($hostInfo.isWindows ? process.env.AppData : path.join(osenv.home(), ".local/share"), ".nativescript-cli"), $errors, $staticConfig); diff --git a/lib/services/android-project-service.ts b/lib/services/android-project-service.ts index 777db27d25..ab09865d98 100644 --- a/lib/services/android-project-service.ts +++ b/lib/services/android-project-service.ts @@ -92,7 +92,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject }).future()(); } - public createProject(frameworkDir: string, frameworkVersion: string): IFuture { + public createProject(frameworkDir: string, frameworkVersion: string, pathToTemplate?: string): IFuture { return (() => { if(semver.lt(frameworkVersion, AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE)) { this.$errors.failWithoutHelp(`The NativeScript CLI requires Android runtime ${AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE} or later to work properly.`); @@ -111,7 +111,13 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject } // These files and directories should not be symlinked as CLI is modifying them and we'll change the original values as well. - this.copy(this.platformData.projectRoot, frameworkDir, "src", "-R"); + if(pathToTemplate) { + let mainPath = path.join(this.platformData.projectRoot, "src", "main"); + this.$fs.createDirectory(mainPath).wait(); + shell.cp("-R", path.join(path.resolve(pathToTemplate), "*"), mainPath); + } else { + this.copy(this.platformData.projectRoot, frameworkDir, "src", "-R"); + } this.copy(this.platformData.projectRoot, frameworkDir, "build.gradle settings.gradle gradle.properties", "-f"); if (this.useGradleWrapper(frameworkDir)) { diff --git a/lib/services/ios-project-service.ts b/lib/services/ios-project-service.ts index e0b186bb36..2132afc1a7 100644 --- a/lib/services/ios-project-service.ts +++ b/lib/services/ios-project-service.ts @@ -104,10 +104,16 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ }).future()(); } - public createProject(frameworkDir: string, frameworkVersion: string): IFuture { + public createProject(frameworkDir: string, frameworkVersion: string, pathToTemplate?: string): IFuture { return (() => { this.$fs.ensureDirectoryExists(path.join(this.platformData.projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER)).wait(); - if(this.$options.symlink) { + if(pathToTemplate) { + // Copy everything except the template from the runtime + this.$fs.readDirectory(frameworkDir).wait() + .filter(dirName => dirName.indexOf(IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER) === -1) + .forEach(dirName => shell.cp("-R", path.join(frameworkDir, dirName), this.platformData.projectRoot)); + shell.cp("-rf", path.join(pathToTemplate, "*"), this.platformData.projectRoot); + } else if(this.$options.symlink) { let xcodeProjectName = util.format("%s.xcodeproj", IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER); shell.cp("-R", path.join(frameworkDir, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER, "*"), path.join(this.platformData.projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER)); @@ -118,7 +124,6 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ _.each(frameworkFiles, (file: string) => { this.$fs.symlink(path.join(frameworkDir, file), path.join(this.platformData.projectRoot, file)).wait(); }); - } else { shell.cp("-R", path.join(frameworkDir, "*"), this.platformData.projectRoot); } @@ -393,6 +398,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ public processConfigurationFilesFromAppResources(): IFuture { return (() => { this.mergeInfoPlists().wait(); + this.mergeProjectXcconfigFiles().wait(); _(this.getAllInstalledPlugins().wait()) .map(pluginData => this.$pluginVariablesService.interpolatePluginVariables(pluginData, this.platformData.configurationFilePath).wait()) .value(); @@ -565,8 +571,6 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ this.executePodInstall().wait(); } - - this.regeneratePluginsXcconfigFile().wait(); }).future()(); } @@ -778,7 +782,7 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ }).future()(); } - private regeneratePluginsXcconfigFile(): IFuture { + private mergeProjectXcconfigFiles(): IFuture { return (() => { this.$fs.deleteFile(this.pluginsDebugXcconfigFilePath).wait(); this.$fs.deleteFile(this.pluginsReleaseXcconfigFilePath).wait(); @@ -793,6 +797,12 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ } } + let appResourcesXcconfigPath = path.join(this.$projectData.projectDir, constants.APP_FOLDER_NAME, constants.APP_RESOURCES_FOLDER_NAME, this.platformData.normalizedPlatformName, "build.xcconfig"); + if (this.$fs.exists(appResourcesXcconfigPath).wait()) { + this.mergeXcconfigFiles(appResourcesXcconfigPath, this.pluginsDebugXcconfigFilePath).wait(); + this.mergeXcconfigFiles(appResourcesXcconfigPath, this.pluginsReleaseXcconfigFilePath).wait(); + } + let podFolder = path.join(this.platformData.projectRoot, "Pods/Target Support Files/Pods/"); if (this.$fs.exists(podFolder).wait()) { this.mergeXcconfigFiles(path.join(this.platformData.projectRoot, "Pods/Target Support Files/Pods/Pods.debug.xcconfig"), this.pluginsDebugXcconfigFilePath).wait(); diff --git a/lib/services/livesync/android-livesync-service.ts b/lib/services/livesync/android-livesync-service.ts index 27ca710432..0d3d6e3baf 100644 --- a/lib/services/livesync/android-livesync-service.ts +++ b/lib/services/livesync/android-livesync-service.ts @@ -35,7 +35,18 @@ class AndroidLiveSyncService extends liveSyncServiceBaseLib.LiveSyncServiceBase< public beforeLiveSyncAction(deviceAppData: Mobile.IDeviceAppData): IFuture { return (() => { - let deviceRootPath = this.getDeviceRootPath(deviceAppData.appIdentifier); + let deviceRootPath = this.getDeviceRootPath(deviceAppData.appIdentifier), + deviceRootDir = path.dirname(deviceRootPath), + deviceRootBasename = path.basename(deviceRootPath), + listResult = this.device.adb.executeShellCommand(["ls", "-l", deviceRootDir]).wait(), + regex = new RegExp(`^-.*${deviceRootBasename}$`, "m"), + matchingFile = (listResult || "").match(regex); + + // Check if there is already a file with deviceRootBasename. If so, delete it as it breaks LiveSyncing. + if(matchingFile && matchingFile[0] && _.startsWith(matchingFile[0], '-')){ + this.device.adb.executeShellCommand(["rm", "-f", deviceRootPath]).wait(); + } + this.device.adb.executeShellCommand(["rm", "-rf", this.$mobileHelper.buildDevicePath(deviceRootPath, "fullsync"), this.$mobileHelper.buildDevicePath(deviceRootPath, "sync"), this.$mobileHelper.buildDevicePath(deviceRootPath, "removedsync")]).wait(); diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index abdbcdafcc..cabc825726 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -8,6 +8,8 @@ import * as helpers from "../common/helpers"; import * as semver from "semver"; import * as minimatch from "minimatch"; import Future = require("fibers/future"); +import * as temp from "temp"; +temp.track(); let clui = require("clui"); export class PlatformService implements IPlatformService { @@ -29,7 +31,8 @@ export class PlatformService implements IPlatformService { private $projectFilesManager: IProjectFilesManager, private $mobileHelper: Mobile.IMobileHelper, private $hostInfo: IHostInfo, - private $xmlValidator: IXmlValidator) { } + private $xmlValidator: IXmlValidator, + private $npm: INodePackageManager) { } public addPlatforms(platforms: string[]): IFuture { return (() => { @@ -114,7 +117,13 @@ export class PlatformService implements IPlatformService { } let sourceFrameworkDir = isFrameworkPathDirectory && this.$options.symlink ? path.join(this.$options.frameworkPath, "framework") : frameworkDir; - platformData.platformProjectService.createProject(path.resolve(sourceFrameworkDir), installedVersion).wait(); + this.$projectDataService.initialize(this.$projectData.projectDir); + let customTemplateOptions = this.getPathToPlatformTemplate(this.$options.platformTemplate, platformData.frameworkPackageName).wait(); + let pathToTemplate: string; + if(customTemplateOptions) { + pathToTemplate = customTemplateOptions.pathToTemplate; + } + platformData.platformProjectService.createProject(path.resolve(sourceFrameworkDir), installedVersion, pathToTemplate).wait(); if(isFrameworkPathDirectory || isFrameworkPathNotSymlinkedFile) { // Need to remove unneeded node_modules folder @@ -132,12 +141,39 @@ export class PlatformService implements IPlatformService { this.$fs.copyFile(newConfigFile, platformData.configurationFilePath).wait(); } - this.$projectDataService.initialize(this.$projectData.projectDir); - this.$projectDataService.setValue(platformData.frameworkPackageName, {version: installedVersion}).wait(); + let frameworkPackageNameData: any = {version: installedVersion}; + if(customTemplateOptions) { + frameworkPackageNameData.template = customTemplateOptions.selectedTemplate; + } + this.$projectDataService.setValue(platformData.frameworkPackageName, frameworkPackageNameData).wait(); }).future()(); } + private getPathToPlatformTemplate(selectedTemplate: string, frameworkPackageName: string): IFuture { + return (() => { + if(!selectedTemplate) { + // read data from package.json's nativescript key + // check the nativescript.tns-.template value + let nativescriptPlatformData = this.$projectDataService.getValue(frameworkPackageName).wait(); + selectedTemplate = nativescriptPlatformData && nativescriptPlatformData.template; + } + + if(selectedTemplate) { + let tempDir = temp.mkdirSync("platform-template"); + try { + let pathToTemplate = this.$npm.install(selectedTemplate, tempDir, {"ignore-scripts": true, "production": true}).wait()[0][1]; + return { selectedTemplate, pathToTemplate }; + } catch(err) { + this.$logger.trace("Error while trying to install specified template: ", err); + this.$errors.failWithoutHelp(`Unable to install platform template ${selectedTemplate}. Make sure the specified value is valid.`); + } + } + + return null; + }).future()(); + } + public getInstalledPlatforms(): IFuture { return(() => { if(!this.$fs.exists(this.$projectData.platformsDir).wait()) { diff --git a/package.json b/package.json index b88da43b6e..603d773f70 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nativescript", "preferGlobal": true, - "version": "1.6.1", + "version": "1.7.0", "author": "Telerik ", "description": "Command-line interface for building NativeScript projects", "bin": { @@ -65,7 +65,6 @@ "properties-parser": "0.2.3", "ref": "https://github.com/icenium/ref/tarball/v1.1.3.1", "ref-struct": "https://github.com/telerik/ref-struct/tarball/v1.0.2.1", - "rimraf": "2.4.2", "semver": "5.0.1", "shelljs": "0.5.3", "tabtab": "https://github.com/Icenium/node-tabtab/tarball/master", @@ -73,7 +72,7 @@ "through2": "2.0.0", "utf-8-validate": "https://github.com/telerik/utf-8-validate/tarball/v1.0.1.1", "vinyl-filter-since": "2.0.2", - "winreg": "0.0.12", + "winreg": "0.0.17", "ws": "0.7.1", "xcode": "https://github.com/NativeScript/node-xcode/archive/1.4.0.tar.gz", "xmldom": "0.1.21", diff --git a/setup/native-script.ps1 b/setup/native-script.ps1 index 7fdf740a49..1c31b5b8cf 100644 --- a/setup/native-script.ps1 +++ b/setup/native-script.ps1 @@ -20,9 +20,6 @@ write-host "To ensure consistent environment, this script will re-install all Na write-host -BackgroundColor Black -ForegroundColor Yellow "Installing Google Chrome (required to debug NativeScript apps)" cinst googlechrome --force --yes -write-host -BackgroundColor Black -ForegroundColor Yellow "Installing node.js" -cinst nodejs.install -version 4.3.0 --force --yes - write-host -BackgroundColor Black -ForegroundColor Yellow "Installing Java Development Kit" cinst jdk8 --force --yes @@ -47,16 +44,6 @@ if (!$env:JAVA_HOME) { $env:JAVA_HOME = $javaHome; } -# install NativeScript CLI -write-host -BackgroundColor Black -ForegroundColor Yellow "Installing NativeScript CLI" - -$oldPathUser = [Environment]::GetEnvironmentVariable("PATH", "User") -$pathMachine = [Environment]::GetEnvironmentVariable("PATH", "Machine") -$myPath = [Environment]::GetEnvironmentVariable("PATH") -[Environment]::SetEnvironmentVariable("PATH", "$myPath;$oldPathUser;$pathMachine;$env:ProgramFiles\nodejs") - -npm install -g nativescript - write-host -BackgroundColor Black -ForegroundColor Yellow "This script has modified your environment. You need to log off and log back on for the changes to take effect." Write-Host "Press any key to continue..." [void][System.Console]::ReadKey($true) diff --git a/setup/native-script.rb b/setup/native-script.rb index 963d54d25c..e8c2079412 100644 --- a/setup/native-script.rb +++ b/setup/native-script.rb @@ -51,10 +51,4 @@ puts "Configuring your system for Android development... This might take some time, please, be patient." system "echo yes | /usr/local/opt/android-sdk/tools/android update sdk --filter tools,platform-tools,android-23,build-tools-23.0.2,extra-android-m2repository --all --no-ui" -puts "Installing Node.js 4" -system('brew install homebrew/versions/node4-lts') - -puts "Installing NativeScript CLI..." -system "/usr/local/bin/npm install -g nativescript" - puts "The ANDROID_HOME and JAVA_HOME environment variables have been added to your .profile. Restart the terminal to use them." diff --git a/test/platform-commands.ts b/test/platform-commands.ts index 8871fff37c..98fd5e0bdc 100644 --- a/test/platform-commands.ts +++ b/test/platform-commands.ts @@ -137,6 +137,7 @@ function createTestInjector() { testInjector.register("mobilePlatformsCapabilities", MobilePlatformsCapabilities); testInjector.register("devicePlatformsConstants", DevicePlatformsConstants); testInjector.register("xmlValidator", XmlValidator); + testInjector.register("npm", {}); return testInjector; } diff --git a/test/platform-service.ts b/test/platform-service.ts index 65f721d059..4ed9a18a8b 100644 --- a/test/platform-service.ts +++ b/test/platform-service.ts @@ -71,6 +71,7 @@ function createTestInjector() { testInjector.register("mobilePlatformsCapabilities", MobilePlatformsCapabilities); testInjector.register("devicePlatformsConstants", DevicePlatformsConstants); testInjector.register("xmlValidator", XmlValidator); + testInjector.register("npm", {}); return testInjector; }