From 8f9283c1459fcd611b5a364309116f7ad94aa8f5 Mon Sep 17 00:00:00 2001 From: Toma Popov Date: Thu, 20 Aug 2015 20:39:58 +0300 Subject: [PATCH] Use npm to fetch tns-core-modules package. --- lib/bootstrap.ts | 1 + lib/constants.ts | 1 + lib/declarations.ts | 2 ++ lib/definitions/project.d.ts | 1 + lib/node-package-manager.ts | 7 ++++++- lib/options.ts | 3 ++- lib/services/platform-service.ts | 12 +++++++++--- lib/services/project-service.ts | 15 ++++++++++++--- lib/tools/broccoli/node-modules-dest-copy.ts | 6 ++++++ test/project-service.ts | 12 +++++++++++- 10 files changed, 51 insertions(+), 9 deletions(-) diff --git a/lib/bootstrap.ts b/lib/bootstrap.ts index c1ef2ad92e..78e3976244 100644 --- a/lib/bootstrap.ts +++ b/lib/bootstrap.ts @@ -11,6 +11,7 @@ $injector.require("androidProjectService", "./services/android-project-service") $injector.require("iOSProjectService", "./services/ios-project-service"); $injector.require("projectTemplatesService", "./services/project-templates-service"); +$injector.require("tnsModulesService", "./services/tns-modules-service"); $injector.require("platformsData", "./platforms-data"); $injector.require("platformService", "./services/platform-service"); diff --git a/lib/constants.ts b/lib/constants.ts index 7d86bfbc49..032432dc54 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -5,6 +5,7 @@ export var APP_RESOURCES_FOLDER_NAME = "App_Resources"; export var PROJECT_FRAMEWORK_FOLDER_NAME = "framework"; export var NATIVESCRIPT_KEY_NAME = "nativescript"; export var NODE_MODULES_FOLDER_NAME = "node_modules"; +export var TNS_CORE_MODULES_NAME = "tns-core-modules"; export var PACKAGE_JSON_FILE_NAME = "package.json"; export var NODE_MODULE_CACHE_PATH_KEY_NAME = "node-modules-cache-path"; export var DEFAULT_APP_IDENTIFIER_PREFIX = "org.nativescript"; diff --git a/lib/declarations.ts b/lib/declarations.ts index b5756a38dc..27007e1b81 100644 --- a/lib/declarations.ts +++ b/lib/declarations.ts @@ -6,6 +6,7 @@ interface INodePackageManager { cache(packageName: string, version: string, cache?: any): IFuture; cacheUnpack(packageName: string, version: string, unpackTarget?: string): IFuture; view(packageName: string, propertyName: string): IFuture; + executeNpmCommand(npmCommandName: string, currentWorkingDirectory: string): IFuture; } interface INpmInstallationManager { @@ -78,6 +79,7 @@ interface IOptions extends ICommonOptions { keyStoreAliasPassword: string; sdk: string; ignoreScripts: boolean; + tnsModulesVersion: string; } interface IProjectFilesManager { diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index 3f4aad3a53..2cc18ee79c 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -1,3 +1,4 @@ + interface IProjectService { createProject(projectName: string): IFuture; } diff --git a/lib/node-package-manager.ts b/lib/node-package-manager.ts index 8ed32e9ff8..452f779cb0 100644 --- a/lib/node-package-manager.ts +++ b/lib/node-package-manager.ts @@ -5,7 +5,8 @@ import Future = require("fibers/future"); import npm = require("npm"); export class NodePackageManager implements INodePackageManager { - constructor(private $logger: ILogger, + constructor(private $childProcess: IChildProcess, + private $logger: ILogger, private $errors: IErrors, private $fs: IFileSystem, private $lockfile: ILockFile, @@ -53,6 +54,10 @@ export class NodePackageManager implements INodePackageManager { public view(packageName: string, propertyName: string): IFuture { return this.loadAndExecute("view", [[packageName, propertyName], [false]]); } + + public executeNpmCommand(npmCommandName: string, currentWorkingDirectory: string): IFuture { + return this.$childProcess.exec(npmCommandName, { cwd: currentWorkingDirectory }); + } private loadAndExecute(commandName: string, args: any[], opts?: { config?: any, subCommandName?: string }): IFuture { return (() => { diff --git a/lib/options.ts b/lib/options.ts index c707ca6711..987eb2ea26 100644 --- a/lib/options.ts +++ b/lib/options.ts @@ -27,7 +27,8 @@ export class Options extends commonOptionsLibPath.OptionsBase { keyStoreAlias: { type: OptionType.String }, keyStoreAliasPassword: { type: OptionType.String }, sdk: { type: OptionType.String }, - ignoreScripts: {type: OptionType.Boolean } + ignoreScripts: {type: OptionType.Boolean }, + tnsModulesVersion: { type: OptionType.String } }, path.join($hostInfo.isWindows ? process.env.LocalAppData : path.join(osenv.home(), ".local/share"), ".nativescript-cli"), $errors, $staticConfig); diff --git a/lib/services/platform-service.ts b/lib/services/platform-service.ts index b8dc838cf0..237d8e2de9 100644 --- a/lib/services/platform-service.ts +++ b/lib/services/platform-service.ts @@ -175,9 +175,15 @@ export class PlatformService implements IPlatformService { platformData.platformProjectService.prepareProject().wait(); // Process node_modules folder - this.$pluginsService.ensureAllDependenciesAreInstalled().wait(); - let tnsModulesDestinationPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME, PlatformService.TNS_MODULES_FOLDER_NAME); - this.$broccoliBuilder.prepareNodeModules(tnsModulesDestinationPath, this.$projectData.projectDir, platform, lastModifiedTime).wait(); + try { + this.$pluginsService.ensureAllDependenciesAreInstalled().wait(); + let tnsModulesDestinationPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME, PlatformService.TNS_MODULES_FOLDER_NAME); + this.$broccoliBuilder.prepareNodeModules(tnsModulesDestinationPath, this.$projectData.projectDir, platform, lastModifiedTime).wait(); + } catch(error) { + this.$logger.debug(error); + this.$errors.fail(`Processing node_modules failed. Error:${error}`); + shell.rm("-rf", appResourcesDirectoryPath); + } // Process platform specific files let directoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME); diff --git a/lib/services/project-service.ts b/lib/services/project-service.ts index 16aa0aeda0..a8f86d6abf 100644 --- a/lib/services/project-service.ts +++ b/lib/services/project-service.ts @@ -10,7 +10,8 @@ import util = require("util"); export class ProjectService implements IProjectService { - constructor(private $errors: IErrors, + constructor(private $npm: INodePackageManager, + private $errors: IErrors, private $fs: IFileSystem, private $logger: ILogger, private $projectDataService: IProjectDataService, @@ -83,13 +84,12 @@ export class ProjectService implements IProjectService { throw err; } - this.$logger.out("Project %s was successfully created", projectName); }).future()(); } - private createProjectCore(projectDir: string, appSourcePath: string, projectId: string): IFuture { + private createProjectCore(projectDir: string, appSourcePath: string, projectId: string): IFuture { return (() => { this.$fs.ensureDirectoryExists(projectDir).wait(); @@ -101,6 +101,7 @@ export class ProjectService implements IProjectService { } else { shell.cp('-R', path.join(appSourcePath, "*"), appDestinationPath); } + this.createBasicProjectStructure(projectDir, projectId).wait(); }).future()(); } @@ -111,6 +112,14 @@ export class ProjectService implements IProjectService { this.$projectDataService.initialize(projectDir); this.$projectDataService.setValue("id", projectId).wait(); + + let tnsModulesVersion = this.$options.tnsModulesVersion; + let packageName = constants.TNS_CORE_MODULES_NAME; + if (tnsModulesVersion) { + packageName = `${packageName}@${tnsModulesVersion}`; + } + + this.$npm.executeNpmCommand(`npm install ${packageName} --save --save-exact`, projectDir).wait(); }).future()(); } diff --git a/lib/tools/broccoli/node-modules-dest-copy.ts b/lib/tools/broccoli/node-modules-dest-copy.ts index 7fd2ea8634..3d38e603b7 100644 --- a/lib/tools/broccoli/node-modules-dest-copy.ts +++ b/lib/tools/broccoli/node-modules-dest-copy.ts @@ -75,6 +75,12 @@ export class DestCopy implements IBroccoliPlugin { if(isPlugin) { this.$pluginsService.prepare(dependency).wait(); } + + if (dependency.name === constants.TNS_CORE_MODULES_NAME) { + let tnsCoreModulesResourcePath = path.join(this.outputRoot, constants.TNS_CORE_MODULES_NAME); + shelljs.cp("-Rf", path.join(tnsCoreModulesResourcePath, "*"), this.outputRoot); + this.$fs.deleteDirectory(tnsCoreModulesResourcePath).wait(); + } }); } diff --git a/test/project-service.ts b/test/project-service.ts index b65891956c..9dcc145bd3 100644 --- a/test/project-service.ts +++ b/test/project-service.ts @@ -3,6 +3,8 @@ import yok = require('../lib/common/yok'); import stubs = require('./stubs'); +import * as constants from "./../lib/constants"; +import * as ChildProcessLib from "../lib/common/child-process"; import ProjectServiceLib = require("../lib/services/project-service"); import ProjectDataServiceLib = require("../lib/services/project-data-service"); @@ -69,11 +71,14 @@ class ProjectIntegrationTest { var appDirectoryPath = path.join(projectDir, "app"); var platformsDirectoryPath = path.join(projectDir, "platforms"); let tnsProjectFilePath = path.join(projectDir, "package.json"); + let tnsModulesPath = path.join(projectDir, constants.NODE_MODULES_FOLDER_NAME, constants.TNS_CORE_MODULES_NAME); + var options = this.testInjector.resolve("options"); assert.isTrue(fs.exists(appDirectoryPath).wait()); assert.isTrue(fs.exists(platformsDirectoryPath).wait()); assert.isTrue(fs.exists(tnsProjectFilePath).wait()); + assert.isTrue(fs.exists(tnsModulesPath).wait()); assert.isFalse(fs.isEmptyDir(appDirectoryPath).wait()); assert.isTrue(fs.isEmptyDir(platformsDirectoryPath).wait()); @@ -82,6 +87,9 @@ class ProjectIntegrationTest { var expectedAppId = appId; assert.equal(actualAppId, expectedAppId); + let tnsCoreModulesRecord = fs.readJson(tnsProjectFilePath).wait()["dependencies"][constants.TNS_CORE_MODULES_NAME]; + assert.isTrue(tnsCoreModulesRecord !== null); + var actualFiles = fs.enumerateFilesInDirectorySync(options.copyFrom); var expectedFiles = fs.enumerateFilesInDirectorySync(appDirectoryPath); @@ -99,7 +107,7 @@ class ProjectIntegrationTest { private createTestInjector(): void { this.testInjector = new yok.Yok(); - + this.testInjector.register("childProcess", ChildProcessLib.ChildProcess); this.testInjector.register("errors", stubs.ErrorsStub); this.testInjector.register('logger', stubs.LoggerStub); this.testInjector.register("projectService", ProjectServiceLib.ProjectService); @@ -171,6 +179,8 @@ function createTestInjector() { testInjector.register("httpClient", HttpClientLib.HttpClient); testInjector.register("config", {}); testInjector.register("lockfile", stubs.LockFile); + + testInjector.register("childProcess", ChildProcessLib.ChildProcess); testInjector.register('projectData', ProjectDataLib.ProjectData); testInjector.register("options", optionsLib.Options);