Skip to content

Use tns_modules from npm #805

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
1 change: 1 addition & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
2 changes: 2 additions & 0 deletions lib/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ interface INodePackageManager {
cache(packageName: string, version: string, cache?: any): IFuture<IDependencyData>;
cacheUnpack(packageName: string, version: string, unpackTarget?: string): IFuture<void>;
view(packageName: string, propertyName: string): IFuture<any>;
executeNpmCommand(npmCommandName: string, currentWorkingDirectory: string): IFuture<any>;
}

interface INpmInstallationManager {
Expand Down Expand Up @@ -78,6 +79,7 @@ interface IOptions extends ICommonOptions {
keyStoreAliasPassword: string;
sdk: string;
ignoreScripts: boolean;
tnsModulesVersion: string;
}

interface IProjectFilesManager {
Expand Down
1 change: 1 addition & 0 deletions lib/definitions/project.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

interface IProjectService {
createProject(projectName: string): IFuture<void>;
}
Expand Down
7 changes: 6 additions & 1 deletion lib/node-package-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -53,6 +54,10 @@ export class NodePackageManager implements INodePackageManager {
public view(packageName: string, propertyName: string): IFuture<any> {
return this.loadAndExecute("view", [[packageName, propertyName], [false]]);
}

public executeNpmCommand(npmCommandName: string, currentWorkingDirectory: string): IFuture<any> {
return this.$childProcess.exec(npmCommandName, { cwd: currentWorkingDirectory });
}

private loadAndExecute(commandName: string, args: any[], opts?: { config?: any, subCommandName?: string }): IFuture<any> {
return (() => {
Expand Down
3 changes: 2 additions & 1 deletion lib/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
12 changes: 9 additions & 3 deletions lib/services/platform-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
15 changes: 12 additions & 3 deletions lib/services/project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -83,13 +84,12 @@ export class ProjectService implements IProjectService {
throw err;
}


this.$logger.out("Project %s was successfully created", projectName);

}).future<void>()();
}

private createProjectCore(projectDir: string, appSourcePath: string, projectId: string): IFuture<void> {
private createProjectCore(projectDir: string, appSourcePath: string, projectId: string): IFuture<void> {
return (() => {
this.$fs.ensureDirectoryExists(projectDir).wait();

Expand All @@ -101,6 +101,7 @@ export class ProjectService implements IProjectService {
} else {
shell.cp('-R', path.join(appSourcePath, "*"), appDestinationPath);
}

this.createBasicProjectStructure(projectDir, projectId).wait();
}).future<void>()();
}
Expand All @@ -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<void>()();
}

Expand Down
6 changes: 6 additions & 0 deletions lib/tools/broccoli/node-modules-dest-copy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when shelljs.cp throws (i.e. I/O error)? Should we deleteDirectory in this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, we have to handle this case properly. Take a look at the next commit where the whole function prepareNodeModules is put in a try-catch block. Deleting the app folder in the catch will guarantee the process being triggered on next prepare <platform> command.

}
});
}

Expand Down
12 changes: 11 additions & 1 deletion test/project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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());
Expand All @@ -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);

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down