Skip to content

Fix creating multiple projects in a single process #2573

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
Feb 28, 2017
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
3 changes: 1 addition & 2 deletions lib/commands/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ export class InstallCommand implements ICommand {

await this.$pluginsService.ensureAllDependenciesAreInstalled();

this.$projectDataService.initialize(this.$projectData.projectDir);
for (let platform of this.$platformsData.platformsNames) {
let platformData = this.$platformsData.getPlatformData(platform);
let frameworkPackageData = this.$projectDataService.getValue(platformData.frameworkPackageName);
const frameworkPackageData = this.$projectDataService.getNSValue(this.$projectData.projectDir, platformData.frameworkPackageName);
if (frameworkPackageData && frameworkPackageData.version) {
try {
await this.$platformService.addPlatforms([`${platform}@${frameworkPackageData.version}`]);
Expand Down
5 changes: 2 additions & 3 deletions lib/commands/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,12 @@ export class UpdateCommand implements ICommand {
let availablePlatforms = this.$platformService.getAvailablePlatforms();
let packagePlatforms: string[] = [];

this.$projectDataService.initialize(this.$projectData.projectDir);
for (let platform of availablePlatforms) {
let platformData = this.$platformsData.getPlatformData(platform);
let platformVersion = this.$projectDataService.getValue(platformData.frameworkPackageName);
const platformVersion = this.$projectDataService.getNSValue(this.$projectData.projectDir, platformData.frameworkPackageName);
if (platformVersion) {
packagePlatforms.push(platform);
this.$projectDataService.removeProperty(platformData.frameworkPackageName);
this.$projectDataService.removeNSProperty(this.$projectData.projectDir, platformData.frameworkPackageName);
}
}

Expand Down
14 changes: 8 additions & 6 deletions lib/definitions/project.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,36 +60,38 @@ interface IProjectData {
}

interface IProjectDataService {
initialize(projectDir: string): void;

/**
* Returns a value from `nativescript` key in project's package.json.
* @param {string} projectDir The project directory - the place where the root package.json is located.
* @param {string} propertyName The name of the property to be checked in `nativescript` key.
* @returns {any} The value of the property.
*/
getValue(propertyName: string): any;
getNSValue(projectDir: string, propertyName: string): any;

/**
* Sets a value in the `nativescript` key in a project's package.json.
* @param {string} projectDir The project directory - the place where the root package.json is located.
* @param {string} key Key to be added to `nativescript` key in project's package.json.
* @param {any} value Value of the key to be added to `nativescript` key in project's package.json.
* @returns {void}
*/
setValue(key: string, value: any): void;
setNSValue(projectDir: string, key: string, value: any): void;

/**
* Removes a property from `nativescript` key in project's package.json.
* @param {string} projectDir The project directory - the place where the root package.json is located.
* @param {string} propertyName The name of the property to be removed from `nativescript` key.
* @returns {void}
*/
removeProperty(propertyName: string): void;
removeNSProperty(projectDir: string, propertyName: string): void;

/**
* Removes dependency from package.json
* @param {string} projectDir The project directory - the place where the root package.json is located.
* @param {string} dependencyName Name of the dependency that has to be removed.
* @returns {void}
*/
removeDependency(dependencyName: string): void;
removeDependency(projectDir: string, dependencyName: string): void;
}

/**
Expand Down
3 changes: 1 addition & 2 deletions lib/services/android-project-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,7 @@ export class AndroidProjectService extends projectServiceBaseLib.PlatformProject
private canUseGradle(frameworkVersion?: string): boolean {
if (!this._canUseGradle) {
if (!frameworkVersion) {
this.$projectDataService.initialize(this.$projectData.projectDir);
let frameworkInfoInProjectFile = this.$projectDataService.getValue(this.platformData.frameworkPackageName);
const frameworkInfoInProjectFile = this.$projectDataService.getNSValue(this.$projectData.projectDir, this.platformData.frameworkPackageName);
frameworkVersion = frameworkInfoInProjectFile && frameworkInfoInProjectFile.version;
}

Expand Down
3 changes: 1 addition & 2 deletions lib/services/livesync/livesync-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ class LiveSyncService implements ILiveSyncService {
private $processService: IProcessService) { }

private async ensureAndroidFrameworkVersion(platformData: IPlatformData): Promise<void> { // TODO: this can be moved inside command or canExecute function
this.$projectDataService.initialize(this.$projectData.projectDir);
let frameworkVersion = this.$projectDataService.getValue(platformData.frameworkPackageName).version;
const frameworkVersion = this.$projectDataService.getNSValue(this.$projectData.projectDir, platformData.frameworkPackageName).version;

if (platformData.normalizedPlatformName.toLowerCase() === this.$devicePlatformsConstants.Android.toLowerCase()) {
if (semver.lt(frameworkVersion, "1.2.1")) {
Expand Down
4 changes: 1 addition & 3 deletions lib/services/platform-project-service-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ export class PlatformProjectServiceBase implements IPlatformProjectServiceBase {
}

protected getFrameworkVersion(runtimePackageName: string): string {
this.$projectDataService.initialize(this.$projectData.projectDir);
let frameworkVersion = this.$projectDataService.getValue(runtimePackageName).version;
return frameworkVersion;
return this.$projectDataService.getNSValue(this.$projectData.projectDir, runtimePackageName).version;
}
}
13 changes: 5 additions & 8 deletions lib/services/platform-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export class PlatformService implements IPlatformService {
let installedVersion = coreModuleData.version;
let coreModuleName = coreModuleData.name;

this.$projectDataService.initialize(this.$projectData.projectDir);
let customTemplateOptions = await this.getPathToPlatformTemplate(this.$options.platformTemplate, platformData.frameworkPackageName);
let pathToTemplate = customTemplateOptions && customTemplateOptions.pathToTemplate;
await platformData.platformProjectService.createProject(path.resolve(frameworkDir), installedVersion, pathToTemplate);
Expand All @@ -130,7 +129,8 @@ export class PlatformService implements IPlatformService {
if (customTemplateOptions) {
frameworkPackageNameData.template = customTemplateOptions.selectedTemplate;
}
this.$projectDataService.setValue(platformData.frameworkPackageName, frameworkPackageNameData);

this.$projectDataService.setNSValue(this.$projectData.projectDir, platformData.frameworkPackageName, frameworkPackageNameData);

return coreModuleName;

Expand All @@ -140,7 +140,7 @@ export class PlatformService implements IPlatformService {
if (!selectedTemplate) {
// read data from package.json's nativescript key
// check the nativescript.tns-<platform>.template value
let nativescriptPlatformData = this.$projectDataService.getValue(frameworkPackageName);
const nativescriptPlatformData = this.$projectDataService.getNSValue(this.$projectData.projectDir, frameworkPackageName);
selectedTemplate = nativescriptPlatformData && nativescriptPlatformData.template;
}

Expand Down Expand Up @@ -582,8 +582,6 @@ export class PlatformService implements IPlatformService {
}

public async removePlatforms(platforms: string[]): Promise<void> {
this.$projectDataService.initialize(this.$projectData.projectDir);

for (let platform of platforms) {
this.validatePlatformInstalled(platform);
let platformData = this.$platformsData.getPlatformData(platform);
Expand All @@ -592,7 +590,7 @@ export class PlatformService implements IPlatformService {

let platformDir = path.join(this.$projectData.platformsDir, platform);
this.$fs.deleteDirectory(platformDir);
this.$projectDataService.removeProperty(platformData.frameworkPackageName);
this.$projectDataService.removeNSProperty(this.$projectData.projectDir, platformData.frameworkPackageName);

this.$logger.out(`Platform ${platform} successfully removed.`);
}
Expand Down Expand Up @@ -724,8 +722,7 @@ export class PlatformService implements IPlatformService {
private async updatePlatform(platform: string, version: string): Promise<void> {
let platformData = this.$platformsData.getPlatformData(platform);

this.$projectDataService.initialize(this.$projectData.projectDir);
let data = this.$projectDataService.getValue(platformData.frameworkPackageName);
let data = this.$projectDataService.getNSValue(this.$projectData.projectDir, platformData.frameworkPackageName);
let currentVersion = data && data.version ? data.version : "0.2.0";

let newVersion = version === constants.PackageVersion.NEXT ?
Expand Down
9 changes: 3 additions & 6 deletions lib/services/plugin-variables-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,12 @@ export class PluginVariablesService implements IPluginVariablesService {
});

if (!_.isEmpty(values)) {
this.$projectDataService.initialize(this.$projectData.projectDir);
this.$projectDataService.setValue(this.getPluginVariablePropertyName(pluginData.name), values);
this.$projectDataService.setNSValue(this.$projectData.projectDir, this.getPluginVariablePropertyName(pluginData.name), values);
}
}

public removePluginVariablesFromProjectFile(pluginName: string): void {
this.$projectDataService.initialize(this.$projectData.projectDir);
this.$projectDataService.removeProperty(this.getPluginVariablePropertyName(pluginName));
this.$projectDataService.removeNSProperty(this.$projectData.projectDir, this.getPluginVariablePropertyName(pluginName));
}

public async interpolatePluginVariables(pluginData: IPluginData, pluginConfigurationFilePath: string): Promise<void> {
Expand Down Expand Up @@ -97,8 +95,7 @@ export class PluginVariablesService implements IPluginVariablesService {

variableData.name = pluginVariableName;

this.$projectDataService.initialize(this.$projectData.projectDir);
let pluginVariableValues = this.$projectDataService.getValue(this.getPluginVariablePropertyName(pluginData.name));
const pluginVariableValues = this.$projectDataService.getNSValue(this.$projectData.projectDir, this.getPluginVariablePropertyName(pluginData.name));
variableData.value = pluginVariableValues ? pluginVariableValues[pluginVariableName] : undefined;

return variableData;
Expand Down
6 changes: 2 additions & 4 deletions lib/services/plugins-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ export class PluginsService implements IPluginsService {
await this.$pluginVariablesService.savePluginVariablesInProjectFile(pluginData);
} catch (err) {
// Revert package.json
this.$projectDataService.initialize(this.$projectData.projectDir);
this.$projectDataService.removeProperty(this.$pluginVariablesService.getPluginVariablePropertyName(pluginData.name));
this.$projectDataService.removeNSProperty(this.$projectData.projectDir, this.$pluginVariablesService.getPluginVariablePropertyName(pluginData.name));
await this.$npm.uninstall(plugin, PluginsService.NPM_CONFIG, this.$projectData.projectDir);

throw err;
Expand Down Expand Up @@ -275,8 +274,7 @@ export class PluginsService implements IPluginsService {

private getInstalledFrameworkVersion(platform: string): string {
let platformData = this.$platformsData.getPlatformData(platform);
this.$projectDataService.initialize(this.$projectData.projectDir);
let frameworkData = this.$projectDataService.getValue(platformData.frameworkPackageName);
const frameworkData = this.$projectDataService.getNSValue(this.$projectData.projectDir, platformData.frameworkPackageName);
return frameworkData.version;
}

Expand Down
128 changes: 81 additions & 47 deletions lib/services/project-data-service.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,109 @@
import * as path from "path";
import * as assert from "assert";

interface IProjectFileData {
projectData: any;
projectFilePath: string;
}

export class ProjectDataService implements IProjectDataService {
private static DEPENDENCIES_KEY_NAME = "dependencies";

private projectFilePath: string;
private projectData: IDictionary<any>;
private projectFileIndent: string;

constructor(private $fs: IFileSystem,
private $staticConfig: IStaticConfig) {
private $staticConfig: IStaticConfig,
private $logger: ILogger) {
}

public initialize(projectDir: string): void {
if (!this.projectFilePath) {
this.projectFilePath = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
}
public getNSValue(projectDir: string, propertyName: string): any {
return this.getValue(projectDir, this.getNativeScriptPropertyName(propertyName));
}

public getValue(propertyName: string): any {
this.loadProjectFile();
return this.projectData ? this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE][propertyName] : null;
public setNSValue(projectDir: string, key: string, value: any): void {
this.setValue(projectDir, this.getNativeScriptPropertyName(key), value);
}

public setValue(key: string, value: any): void {
this.loadProjectFile();
if (!this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE]) {
this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE] = Object.create(null);
}
this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE][key] = value;
this.$fs.writeJson(this.projectFilePath, this.projectData, this.projectFileIndent);
public removeNSProperty(projectDir: string, propertyName: string): void {
this.removeProperty(projectDir, this.getNativeScriptPropertyName(propertyName));
}

public removeProperty(propertyName: string): void {
this.loadProjectFile();
delete this.projectData[this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE][propertyName];
this.$fs.writeJson(this.projectFilePath, this.projectData, this.projectFileIndent);
public removeDependency(projectDir: string, dependencyName: string): void {
const projectFileInfo = this.getProjectFileData(projectDir);
delete projectFileInfo.projectData[ProjectDataService.DEPENDENCIES_KEY_NAME][dependencyName];
this.$fs.writeJson(projectFileInfo.projectFilePath, projectFileInfo.projectData);
}

private getValue(projectDir: string, propertyName: string): any {
const projectData = this.getProjectFileData(projectDir).projectData;

if (projectData) {
try {
return this.getPropertyValueFromJson(projectData, propertyName);
} catch (err) {
this.$logger.trace(`Error while trying to get property ${propertyName} from ${projectDir}. Error is:`, err);
}
}

return null;
}

public removeDependency(dependencyName: string): void {
this.loadProjectFile();
delete this.projectData[ProjectDataService.DEPENDENCIES_KEY_NAME][dependencyName];
this.$fs.writeJson(this.projectFilePath, this.projectData, this.projectFileIndent);
private getNativeScriptPropertyName(propertyName: string) {
return `${this.$staticConfig.CLIENT_NAME_KEY_IN_PROJECT_FILE}.${propertyName}`;
}

private loadProjectFile(): void {
assert.ok(this.projectFilePath, "Initialize method of projectDataService is not called.");
private getPropertyValueFromJson(jsonData: any, dottedPropertyName: string): any {
const props = dottedPropertyName.split(".");
let result = jsonData[props.shift()];

if (!this.$fs.exists(this.projectFilePath)) {
this.$fs.writeJson(this.projectFilePath, {
"description": "NativeScript Application",
"license": "SEE LICENSE IN <your-license-filename>",
"readme": "NativeScript Application",
"repository": "<fill-your-repository-here>"
});
for (let prop of props) {
result = result[prop];
}

// Detect indent and use it later to write JSON.
let projectFileContent = this.$fs.readText(this.projectFilePath);
return result;
}

private setValue(projectDir: string, key: string, value: any): void {
const projectFileInfo = this.getProjectFileData(projectDir);

const props = key.split(".");
let data: any = projectFileInfo.projectData;
let currentData = data;

this.projectFileIndent = projectFileContent ? this.detectIndent(projectFileContent) : "\t";
_.each(props, (prop, index: number) => {
if (index === (props.length - 1)) {
currentData[prop] = value;
} else {
currentData[prop] = currentData[prop] || Object.create(null);
}

this.projectData = projectFileContent ? JSON.parse(projectFileContent) : Object.create(null);
currentData = currentData[prop];
});

this.$fs.writeJson(projectFileInfo.projectFilePath, data);
}

private detectIndent(content: string): any {
const leadingSpace = content.match(/(^[ ]+)\S/m);
if (leadingSpace) {
return leadingSpace[1].length;
}
return "\t";
private removeProperty(projectDir: string, propertyName: string): void {
const projectFileInfo = this.getProjectFileData(projectDir);
let data: any = projectFileInfo.projectData;
let currentData = data;
const props = propertyName.split(".");
const propertyToDelete = props.splice(props.length - 1, 1)[0];

_.each(props, (prop) => {
currentData = currentData[prop];
});

delete currentData[propertyToDelete];
this.$fs.writeJson(projectFileInfo.projectFilePath, data);
}

private getProjectFileData(projectDir: string): IProjectFileData {
const projectFilePath = path.join(projectDir, this.$staticConfig.PROJECT_FILE_NAME);
const projectFileContent = this.$fs.readText(projectFilePath);
const projectData = projectFileContent ? JSON.parse(projectFileContent) : Object.create(null);

return {
projectData,
projectFilePath
};
}
}
$injector.register("projectDataService", ProjectDataService);
Loading