Skip to content

Commit db04d3b

Browse files
nadyaADimitar Kerezov
authored and
Dimitar Kerezov
committed
Separate native and JS prepare code
Create interfaces to separate the prepare functionality in js and native parts. Ensure better isolation and encapsulation of project preparation process.
1 parent 0f861bb commit db04d3b

6 files changed

+230
-158
lines changed

lib/bootstrap.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ $injector.require("tnsModulesService", "./services/tns-modules-service");
2222

2323
$injector.require("platformsData", "./platforms-data");
2424
$injector.require("platformService", "./services/platform-service");
25+
$injector.require("preparePlatformJSService", "./services/prepare-platform-js-service");
26+
$injector.require("preparePlatformNativeService", "./services/prepare-platform-native-service");
2527

2628
$injector.require("debugDataService", "./services/debug-data-service");
2729
$injector.requirePublicClass("debugService", "./services/debug-service");

lib/definitions/platform.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,3 +290,16 @@ interface IBuildInfo {
290290
prepareTime: string;
291291
buildTime: string;
292292
}
293+
294+
interface IPreparePlatformService extends NodeJS.EventEmitter {
295+
addPlatform(platformData: IPlatformData, frameworkDir: string, installedVersion: string, projectData: IProjectData, config: IPlatformOptions, platformTemplate?: string, ): Promise<void>;
296+
preparePlatform(platform: string, platformData: IPlatformData, appFilesUpdaterOptions: IAppFilesUpdaterOptions, projectData: IProjectData, platformSpecificData: IPlatformSpecificData, changesInfo?: IProjectChangesInfo, filesToSync?: Array<String>, projectFilesConfig?: IProjectFilesConfig): Promise<void>;
297+
}
298+
299+
interface IPreparePlatformJSService extends IPreparePlatformService {
300+
301+
}
302+
303+
interface IPreparePlatformNativeService extends IPreparePlatformService {
304+
305+
}

lib/services/platform-service.ts

Lines changed: 9 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,20 @@ export class PlatformService extends EventEmitter implements IPlatformService {
2323
private _trackedProjectFilePath: string = null;
2424

2525
constructor(private $devicesService: Mobile.IDevicesService,
26+
private $preparePlatformNativeService: IPreparePlatformNativeService,
27+
private $preparePlatformJSService: IPreparePlatformJSService,
2628
private $errors: IErrors,
2729
private $fs: IFileSystem,
2830
private $logger: ILogger,
2931
private $npmInstallationManager: INpmInstallationManager,
3032
private $platformsData: IPlatformsData,
3133
private $projectDataService: IProjectDataService,
3234
private $hooksService: IHooksService,
33-
private $nodeModulesBuilder: INodeModulesBuilder,
3435
private $pluginsService: IPluginsService,
3536
private $projectFilesManager: IProjectFilesManager,
3637
private $mobileHelper: Mobile.IMobileHelper,
3738
private $hostInfo: IHostInfo,
3839
private $devicePathProvider: IDevicePathProvider,
39-
private $xmlValidator: IXmlValidator,
4040
private $npm: INodePackageManager,
4141
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
4242
private $projectChangesService: IProjectChangesService,
@@ -141,60 +141,17 @@ export class PlatformService extends EventEmitter implements IPlatformService {
141141
private async addPlatformCore(platformData: IPlatformData, frameworkDir: string, platformTemplate: string, projectData: IProjectData, config: IPlatformOptions, nativePrepare?: INativePrepare): Promise<string> {
142142
const coreModuleData = this.$fs.readJson(path.join(frameworkDir, "..", "package.json"));
143143
const installedVersion = coreModuleData.version;
144-
const customTemplateOptions = await this.getPathToPlatformTemplate(platformTemplate, platformData.frameworkPackageName, projectData.projectDir);
145-
config.pathToTemplate = customTemplateOptions && customTemplateOptions.pathToTemplate;
144+
145+
await this.$preparePlatformJSService.addPlatform(platformData, frameworkDir, installedVersion, projectData, config, platformTemplate);
146146

147147
if (!nativePrepare || !nativePrepare.skipNativePrepare) {
148148
const platformDir = path.join(projectData.platformsDir, platformData.normalizedPlatformName.toLowerCase());
149149
this.$fs.deleteDirectory(platformDir);
150-
await this.addPlatformCoreNative(platformData, frameworkDir, installedVersion, projectData, config);
151-
}
152-
153-
const frameworkPackageNameData: any = { version: installedVersion };
154-
if (customTemplateOptions) {
155-
frameworkPackageNameData.template = customTemplateOptions.selectedTemplate;
150+
await this.$preparePlatformNativeService.addPlatform(platformData, frameworkDir, installedVersion, projectData, config);
156151
}
157152

158-
this.$projectDataService.setNSValue(projectData.projectDir, platformData.frameworkPackageName, frameworkPackageNameData);
159-
160153
const coreModuleName = coreModuleData.name;
161154
return coreModuleName;
162-
163-
}
164-
165-
private async addPlatformCoreNative(platformData: IPlatformData, frameworkDir: string, installedVersion: string, projectData: IProjectData, config: IPlatformOptions): Promise<void> {
166-
await platformData.platformProjectService.createProject(path.resolve(frameworkDir), installedVersion, projectData, config);
167-
platformData.platformProjectService.ensureConfigurationFileInAppResources(projectData);
168-
await platformData.platformProjectService.interpolateData(projectData, config);
169-
platformData.platformProjectService.afterCreateProject(platformData.projectRoot, projectData);
170-
}
171-
172-
private async getPathToPlatformTemplate(selectedTemplate: string, frameworkPackageName: string, projectDir: string): Promise<{ selectedTemplate: string, pathToTemplate: string }> {
173-
if (!selectedTemplate) {
174-
// read data from package.json's nativescript key
175-
// check the nativescript.tns-<platform>.template value
176-
const nativescriptPlatformData = this.$projectDataService.getNSValue(projectDir, frameworkPackageName);
177-
selectedTemplate = nativescriptPlatformData && nativescriptPlatformData.template;
178-
}
179-
180-
if (selectedTemplate) {
181-
const tempDir = temp.mkdirSync("platform-template");
182-
this.$fs.writeJson(path.join(tempDir, constants.PACKAGE_JSON_FILE_NAME), {});
183-
try {
184-
const npmInstallResult = await this.$npm.install(selectedTemplate, tempDir, {
185-
disableNpmInstall: false,
186-
frameworkPath: null,
187-
ignoreScripts: false
188-
});
189-
const pathToTemplate = path.join(tempDir, constants.NODE_MODULES_FOLDER_NAME, npmInstallResult.name);
190-
return { selectedTemplate, pathToTemplate };
191-
} catch (err) {
192-
this.$logger.trace("Error while trying to install specified template: ", err);
193-
this.$errors.failWithoutHelp(`Unable to install platform template ${selectedTemplate}. Make sure the specified value is valid.`);
194-
}
195-
}
196-
197-
return null;
198155
}
199156

200157
public getInstalledPlatforms(projectData: IProjectData): string[] {
@@ -216,8 +173,10 @@ export class PlatformService extends EventEmitter implements IPlatformService {
216173
public getPreparedPlatforms(projectData: IProjectData): string[] {
217174
return _.filter(this.$platformsData.platformsNames, p => { return this.isPlatformPrepared(p, projectData); });
218175
}
176+
219177
public async preparePlatform(platform: string, appFilesUpdaterOptions: IAppFilesUpdaterOptions, platformTemplate: string, projectData: IProjectData, config: IPlatformOptions, filesToSync?: Array<String>, nativePrepare?: INativePrepare): Promise<boolean> {
220178
const platformData = this.$platformsData.getPlatformData(platform, projectData);
179+
221180
const changesInfo = await this.initialPrepare(platform, platformData, appFilesUpdaterOptions, platformTemplate, projectData, config, nativePrepare);
222181
const requiresNativePrepare = (!nativePrepare || !nativePrepare.skipNativePrepare) && changesInfo.nativePlatformStatus === constants.NativePlatformStatus.requiresPrepare;
223182

@@ -249,25 +208,6 @@ export class PlatformService extends EventEmitter implements IPlatformService {
249208
}
250209
}
251210

252-
private async cleanProject(platform: string, appFilesUpdaterOptions: IAppFilesUpdaterOptions, platformData: IPlatformData, projectData: IProjectData): Promise<void> {
253-
// android build artifacts need to be cleaned up
254-
// when switching between debug, release and webpack builds
255-
if (platform.toLowerCase() !== "android") {
256-
return;
257-
}
258-
259-
const previousPrepareInfo = this.$projectChangesService.getPrepareInfo(platform, projectData);
260-
if (!previousPrepareInfo) {
261-
return;
262-
}
263-
264-
const { release: previousWasRelease, bundle: previousWasBundle } = previousPrepareInfo;
265-
const { release: currentIsRelease, bundle: currentIsBundle } = appFilesUpdaterOptions;
266-
if ((previousWasRelease !== currentIsRelease) || (previousWasBundle !== currentIsBundle)) {
267-
await platformData.platformProjectService.cleanProject(platformData.projectRoot, projectData);
268-
}
269-
}
270-
271211
private async initialPrepare(platform: string, platformData: IPlatformData, appFilesUpdaterOptions: IAppFilesUpdaterOptions, platformTemplate: string, projectData: IProjectData, config: IPlatformOptions, nativePrepare?: INativePrepare): Promise<IProjectChangesInfo> {
272212
this.validatePlatform(platform, projectData);
273213

@@ -298,10 +238,10 @@ export class PlatformService extends EventEmitter implements IPlatformService {
298238

299239
const platformData = this.$platformsData.getPlatformData(platform, projectData);
300240
const projectFilesConfig = helpers.getProjectFilesConfig({ isReleaseBuild: appFilesUpdaterOptions.release });
301-
await this.preparePlatformCoreJS(platform, platformData, appFilesUpdaterOptions, projectData, platformSpecificData, changesInfo, filesToSync, projectFilesConfig);
241+
await this.$preparePlatformJSService.preparePlatform(platform, platformData, appFilesUpdaterOptions, projectData, platformSpecificData, changesInfo, filesToSync, projectFilesConfig);
302242

303243
if (!nativePrepare || !nativePrepare.skipNativePrepare) {
304-
await this.preparePlatformCoreNative(platform, platformData, appFilesUpdaterOptions, projectData, platformSpecificData, changesInfo, projectFilesConfig);
244+
await this.$preparePlatformNativeService.preparePlatform(platform, platformData, appFilesUpdaterOptions, projectData, platformSpecificData, changesInfo, filesToSync, projectFilesConfig);
305245
}
306246

307247
const directoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
@@ -315,95 +255,6 @@ export class PlatformService extends EventEmitter implements IPlatformService {
315255
this.$logger.out(`Project successfully prepared (${platform})`);
316256
}
317257

318-
private async preparePlatformCoreJS(platform: string, platformData: IPlatformData, appFilesUpdaterOptions: IAppFilesUpdaterOptions, projectData: IProjectData, platformSpecificData: IPlatformSpecificData, changesInfo?: IProjectChangesInfo, filesToSync?: Array<String>, projectFilesConfig?: IProjectFilesConfig): Promise<void> {
319-
if (!changesInfo || changesInfo.appFilesChanged) {
320-
await this.copyAppFiles(platformData, appFilesUpdaterOptions, projectData);
321-
322-
// remove the App_Resources folder from the app/assets as here we're applying other files changes.
323-
const appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
324-
const appResourcesDirectoryPath = path.join(appDestinationDirectoryPath, constants.APP_RESOURCES_FOLDER_NAME);
325-
if (this.$fs.exists(appResourcesDirectoryPath)) {
326-
this.$fs.deleteDirectory(appResourcesDirectoryPath);
327-
}
328-
}
329-
330-
if (!changesInfo || changesInfo.modulesChanged) {
331-
await this.copyTnsModules(platform, platformData, projectData, projectFilesConfig);
332-
}
333-
}
334-
335-
public async preparePlatformCoreNative(platform: string, platformData: IPlatformData, appFilesUpdaterOptions: IAppFilesUpdaterOptions, projectData: IProjectData, platformSpecificData: IPlatformSpecificData, changesInfo?: IProjectChangesInfo, projectFilesConfig?: IProjectFilesConfig): Promise<void> {
336-
if (changesInfo.hasChanges) {
337-
await this.cleanProject(platform, appFilesUpdaterOptions, platformData, projectData);
338-
}
339-
340-
if (!changesInfo || changesInfo.changesRequirePrepare) {
341-
await this.copyAppFiles(platformData, appFilesUpdaterOptions, projectData);
342-
this.copyAppResources(platformData, projectData);
343-
await platformData.platformProjectService.prepareProject(projectData, platformSpecificData);
344-
}
345-
346-
if (!changesInfo || changesInfo.modulesChanged || appFilesUpdaterOptions.bundle) {
347-
await this.$pluginsService.validate(platformData, projectData);
348-
349-
const appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
350-
const lastModifiedTime = this.$fs.exists(appDestinationDirectoryPath) ? this.$fs.getFsStats(appDestinationDirectoryPath).mtime : null;
351-
352-
const tnsModulesDestinationPath = path.join(appDestinationDirectoryPath, constants.TNS_MODULES_FOLDER_NAME);
353-
// Process node_modules folder
354-
await this.$nodeModulesBuilder.prepareNodeModules(tnsModulesDestinationPath, platform, lastModifiedTime, projectData, projectFilesConfig);
355-
}
356-
357-
if (!changesInfo || changesInfo.configChanged || changesInfo.modulesChanged) {
358-
await platformData.platformProjectService.processConfigurationFilesFromAppResources(appFilesUpdaterOptions.release, projectData);
359-
}
360-
361-
platformData.platformProjectService.interpolateConfigurationFile(projectData, platformSpecificData);
362-
this.$projectChangesService.setNativePlatformStatus(platform, projectData,
363-
{ nativePlatformStatus: constants.NativePlatformStatus.alreadyPrepared });
364-
}
365-
366-
private async copyAppFiles(platformData: IPlatformData, appFilesUpdaterOptions: IAppFilesUpdaterOptions, projectData: IProjectData): Promise<void> {
367-
platformData.platformProjectService.ensureConfigurationFileInAppResources(projectData);
368-
const appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
369-
370-
// Copy app folder to native project
371-
this.$fs.ensureDirectoryExists(appDestinationDirectoryPath);
372-
const appSourceDirectoryPath = path.join(projectData.projectDir, constants.APP_FOLDER_NAME);
373-
374-
const appUpdater = new AppFilesUpdater(appSourceDirectoryPath, appDestinationDirectoryPath, appFilesUpdaterOptions, this.$fs);
375-
appUpdater.updateApp(sourceFiles => {
376-
this.$xmlValidator.validateXmlFiles(sourceFiles);
377-
});
378-
}
379-
380-
private copyAppResources(platformData: IPlatformData, projectData: IProjectData): void {
381-
const appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
382-
const appResourcesDirectoryPath = path.join(appDestinationDirectoryPath, constants.APP_RESOURCES_FOLDER_NAME);
383-
if (this.$fs.exists(appResourcesDirectoryPath)) {
384-
platformData.platformProjectService.prepareAppResources(appResourcesDirectoryPath, projectData);
385-
const appResourcesDestination = platformData.platformProjectService.getAppResourcesDestinationDirectoryPath(projectData);
386-
this.$fs.ensureDirectoryExists(appResourcesDestination);
387-
shell.cp("-Rf", path.join(appResourcesDirectoryPath, platformData.normalizedPlatformName, "*"), appResourcesDestination);
388-
this.$fs.deleteDirectory(appResourcesDirectoryPath);
389-
}
390-
}
391-
392-
private async copyTnsModules(platform: string, platformData: IPlatformData, projectData: IProjectData, projectFilesConfig?: IProjectFilesConfig): Promise<void> {
393-
const appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
394-
const lastModifiedTime = this.$fs.exists(appDestinationDirectoryPath) ? this.$fs.getFsStats(appDestinationDirectoryPath).mtime : null;
395-
396-
try {
397-
const tnsModulesDestinationPath = path.join(appDestinationDirectoryPath, constants.TNS_MODULES_FOLDER_NAME);
398-
// Process node_modules folder
399-
await this.$nodeModulesBuilder.prepareJSNodeModules(tnsModulesDestinationPath, platform, lastModifiedTime, projectData, projectFilesConfig);
400-
} catch (error) {
401-
this.$logger.debug(error);
402-
shell.rm("-rf", appDestinationDirectoryPath);
403-
this.$errors.failWithoutHelp(`Processing node_modules failed. ${error}`);
404-
}
405-
}
406-
407258
public async shouldBuild(platform: string, projectData: IProjectData, buildConfig: IBuildConfig, outputPath?: string): Promise<boolean> {
408259
if (this.$projectChangesService.currentChanges.changesRequireBuild) {
409260
return true;
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import * as constants from "../constants";
2+
import * as path from "path";
3+
import * as shell from "shelljs";
4+
import * as temp from "temp";
5+
import { PreparePlatformService } from "./prepare-platform-service";
6+
7+
temp.track();
8+
9+
export class PreparePlatformJSService extends PreparePlatformService implements IPreparePlatformNativeService {
10+
11+
constructor($fs: IFileSystem,
12+
$xmlValidator: IXmlValidator,
13+
private $errors: IErrors,
14+
private $logger: ILogger,
15+
private $projectDataService: IProjectDataService,
16+
private $nodeModulesBuilder: INodeModulesBuilder,
17+
private $npm: INodePackageManager) {
18+
super($fs, $xmlValidator);
19+
}
20+
21+
public async addPlatform(platformData: IPlatformData, frameworkDir: string, installedVersion: string, projectData: IProjectData, config: IPlatformOptions, platformTemplate: string, ): Promise<void> {
22+
const customTemplateOptions = await this.getPathToPlatformTemplate(platformTemplate, platformData.frameworkPackageName, projectData.projectDir);
23+
config.pathToTemplate = customTemplateOptions && customTemplateOptions.pathToTemplate;
24+
25+
const frameworkPackageNameData: any = { version: installedVersion };
26+
if (customTemplateOptions) {
27+
frameworkPackageNameData.template = customTemplateOptions.selectedTemplate;
28+
}
29+
30+
this.$projectDataService.setNSValue(projectData.projectDir, platformData.frameworkPackageName, frameworkPackageNameData);
31+
}
32+
33+
public async preparePlatform(platform: string, platformData: IPlatformData, appFilesUpdaterOptions: IAppFilesUpdaterOptions, projectData: IProjectData, platformSpecificData: IPlatformSpecificData, changesInfo?: IProjectChangesInfo, filesToSync?: Array<String>, projectFilesConfig?: IProjectFilesConfig): Promise<void> {
34+
if (!changesInfo || changesInfo.appFilesChanged) {
35+
await this.copyAppFiles(platformData, appFilesUpdaterOptions, projectData);
36+
37+
// remove the App_Resources folder from the app/assets as here we're applying other files changes.
38+
const appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
39+
const appResourcesDirectoryPath = path.join(appDestinationDirectoryPath, constants.APP_RESOURCES_FOLDER_NAME);
40+
if (this.$fs.exists(appResourcesDirectoryPath)) {
41+
this.$fs.deleteDirectory(appResourcesDirectoryPath);
42+
}
43+
}
44+
45+
if (!changesInfo || changesInfo.modulesChanged) {
46+
await this.copyTnsModules(platform, platformData, projectData, projectFilesConfig);
47+
}
48+
}
49+
50+
private async getPathToPlatformTemplate(selectedTemplate: string, frameworkPackageName: string, projectDir: string): Promise<{ selectedTemplate: string, pathToTemplate: string }> {
51+
if (!selectedTemplate) {
52+
// read data from package.json's nativescript key
53+
// check the nativescript.tns-<platform>.template value
54+
const nativescriptPlatformData = this.$projectDataService.getNSValue(projectDir, frameworkPackageName);
55+
selectedTemplate = nativescriptPlatformData && nativescriptPlatformData.template;
56+
}
57+
58+
if (selectedTemplate) {
59+
const tempDir = temp.mkdirSync("platform-template");
60+
this.$fs.writeJson(path.join(tempDir, constants.PACKAGE_JSON_FILE_NAME), {});
61+
try {
62+
const npmInstallResult = await this.$npm.install(selectedTemplate, tempDir, {
63+
disableNpmInstall: false,
64+
frameworkPath: null,
65+
ignoreScripts: false
66+
});
67+
const pathToTemplate = path.join(tempDir, constants.NODE_MODULES_FOLDER_NAME, npmInstallResult.name);
68+
return { selectedTemplate, pathToTemplate };
69+
} catch (err) {
70+
this.$logger.trace("Error while trying to install specified template: ", err);
71+
this.$errors.failWithoutHelp(`Unable to install platform template ${selectedTemplate}. Make sure the specified value is valid.`);
72+
}
73+
}
74+
75+
return null;
76+
}
77+
78+
private async copyTnsModules(platform: string, platformData: IPlatformData, projectData: IProjectData, projectFilesConfig?: IProjectFilesConfig): Promise<void> {
79+
const appDestinationDirectoryPath = path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME);
80+
const lastModifiedTime = this.$fs.exists(appDestinationDirectoryPath) ? this.$fs.getFsStats(appDestinationDirectoryPath).mtime : null;
81+
82+
try {
83+
const tnsModulesDestinationPath = path.join(appDestinationDirectoryPath, constants.TNS_MODULES_FOLDER_NAME);
84+
// Process node_modules folder
85+
await this.$nodeModulesBuilder.prepareJSNodeModules(tnsModulesDestinationPath, platform, lastModifiedTime, projectData, projectFilesConfig);
86+
} catch (error) {
87+
this.$logger.debug(error);
88+
shell.rm("-rf", appDestinationDirectoryPath);
89+
this.$errors.failWithoutHelp(`Processing node_modules failed. ${error}`);
90+
}
91+
}
92+
}
93+
94+
$injector.register("preparePlatformJSService", PreparePlatformJSService);

0 commit comments

Comments
 (0)