nativescript
Version:
Command-line interface for building NativeScript projects
275 lines • 13.8 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ProjectChangesService = void 0;
const path = require("path");
const constants_1 = require("../constants");
const helpers_1 = require("../common/helpers");
const _ = require("lodash");
const yok_1 = require("../common/yok");
const prepareInfoFileName = ".nsprepareinfo";
class ProjectChangesInfo {
get hasChanges() {
return (this.nativeChanged ||
this.appResourcesChanged ||
this.configChanged ||
this.signingChanged);
}
get changesRequireBuild() {
return this.appResourcesChanged || this.nativeChanged;
}
get changesRequirePrepare() {
return this.appResourcesChanged || this.signingChanged;
}
}
class ProjectChangesService {
constructor($devicePlatformsConstants, $fs, $logger, $options, $hooksService, $nodeModulesDependenciesBuilder) {
this.$devicePlatformsConstants = $devicePlatformsConstants;
this.$fs = $fs;
this.$logger = $logger;
this.$options = $options;
this.$hooksService = $hooksService;
this.$nodeModulesDependenciesBuilder = $nodeModulesDependenciesBuilder;
}
get currentChanges() {
return this._changesInfo;
}
async checkForChanges(platformData, projectData, prepareData) {
this._changesInfo = new ProjectChangesInfo();
const isNewPrepareInfo = await this.ensurePrepareInfo(platformData, projectData, prepareData);
if (!isNewPrepareInfo) {
let platformResourcesDir = path.join(projectData.appResourcesDirectoryPath, platformData.normalizedPlatformName);
if (!this.$fs.exists(platformResourcesDir) &&
platformData.platformNameLowerCase ===
this.$devicePlatformsConstants.visionOS.toLowerCase()) {
platformResourcesDir = path.join(projectData.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS);
}
this._changesInfo.appResourcesChanged = this.containsNewerFiles(platformResourcesDir, projectData);
this.$nodeModulesDependenciesBuilder
.getProductionDependencies(projectData.projectDir, projectData.ignoredDependencies)
.filter((dep) => dep.nativescript &&
this.$fs.exists(path.join(dep.directory, constants_1.PLATFORMS_DIR_NAME, platformData.platformNameLowerCase)))
.forEach((dep) => {
this._changesInfo.nativeChanged =
this._changesInfo.nativeChanged ||
this.containsNewerFiles(path.join(dep.directory, constants_1.PLATFORMS_DIR_NAME, platformData.platformNameLowerCase), projectData) ||
this.isFileModified(path.join(dep.directory, constants_1.PACKAGE_JSON_FILE_NAME));
});
if (!this._changesInfo.nativeChanged) {
this._prepareInfo.projectFileHash = this.getProjectFileStrippedHash(projectData.projectDir, platformData);
this._changesInfo.nativeChanged = this.isProjectFileChanged(projectData.projectDir, platformData);
}
// If this causes too much rebuilds of the plugins or uncecessary builds for Android, move overrideCocoapods to prepareInfo.
this._changesInfo.nsConfigChanged = this.filesChanged([
path.join(projectData.projectDir, constants_1.CONFIG_FILE_NAME_JS),
path.join(projectData.projectDir, constants_1.CONFIG_FILE_NAME_TS),
path.join(projectData.projectDir, constants_1.CONFIG_NS_FILE_NAME),
]);
this._changesInfo.nativeChanged =
this._changesInfo.nativeChanged || this._changesInfo.nsConfigChanged;
this.$logger.trace(`Set nativeChanged to ${this._changesInfo.nativeChanged}.`);
if (platformData.platformNameLowerCase ===
this.$devicePlatformsConstants.iOS.toLowerCase()) {
this._changesInfo.configChanged = this.filesChanged([
path.join(platformResourcesDir, platformData.configurationFileName),
path.join(platformResourcesDir, "LaunchScreen.storyboard"),
path.join(platformResourcesDir, constants_1.BUILD_XCCONFIG_FILE_NAME),
]);
}
else {
this._changesInfo.configChanged = this.filesChanged([
path.join(platformResourcesDir, platformData.configurationFileName),
path.join(platformResourcesDir, constants_1.APP_GRADLE_FILE_NAME),
]);
}
this.$logger.trace(`Set value of configChanged to ${this._changesInfo.configChanged}`);
}
if (!prepareData.nativePrepare ||
!prepareData.nativePrepare.skipNativePrepare) {
await platformData.platformProjectService.checkForChanges(this._changesInfo, prepareData, projectData);
}
if (!!prepareData.release !== !!this._prepareInfo.release) {
this.$logger.trace(`Setting all setting to true. Current options are: `, prepareData, " old prepare info is: ", this._prepareInfo);
this._changesInfo.appResourcesChanged = true;
this._changesInfo.configChanged = true;
this._prepareInfo.release = prepareData.release;
}
if (this._changesInfo.appResourcesChanged) {
this.$logger.trace(`Set configChanged to true, appResourcesChanged is: ${this._changesInfo.appResourcesChanged}`);
this._changesInfo.configChanged = true;
}
if (this._changesInfo.hasChanges) {
this._prepareInfo.changesRequireBuild =
this._changesInfo.changesRequireBuild;
this._prepareInfo.time = new Date().toString();
if (this._prepareInfo.changesRequireBuild) {
this._prepareInfo.changesRequireBuildTime = this._prepareInfo.time;
}
}
this._changesInfo.nativePlatformStatus =
this._prepareInfo.nativePlatformStatus;
this.$logger.trace("checkForChanges returns", this._changesInfo);
return this._changesInfo;
}
getPrepareInfoFilePath(platformData) {
const prepareInfoFilePath = path.join(platformData.projectRoot, prepareInfoFileName);
return prepareInfoFilePath;
}
getPrepareInfo(platformData) {
if (this.$options.hostProjectPath) {
// TODO: always prepare for now until we decide where to keep the .nsprepareinfo file when embedding
return null;
}
const prepareInfoFilePath = this.getPrepareInfoFilePath(platformData);
let prepareInfo = null;
if (this.$fs.exists(prepareInfoFilePath)) {
try {
prepareInfo = this.$fs.readJson(prepareInfoFilePath);
}
catch (e) {
prepareInfo = null;
}
}
return prepareInfo;
}
async savePrepareInfo(platformData, projectData, prepareData) {
if (!this._prepareInfo) {
await this.ensurePrepareInfo(platformData, projectData, prepareData);
}
if (this.$options.hostProjectPath) {
// TODO: do not save for now until we decide where to keep the .nsprepareinfo file when embedding
return null;
}
const prepareInfoFilePath = this.getPrepareInfoFilePath(platformData);
this.$fs.writeJson(prepareInfoFilePath, this._prepareInfo);
}
async setNativePlatformStatus(platformData, projectData, addedPlatform) {
this._prepareInfo = this._prepareInfo || this.getPrepareInfo(platformData);
if (this._prepareInfo &&
addedPlatform.nativePlatformStatus ===
"3" /* NativePlatformStatus.alreadyPrepared */) {
this._prepareInfo.nativePlatformStatus =
addedPlatform.nativePlatformStatus;
}
else {
this._prepareInfo = {
nativePlatformStatus: addedPlatform.nativePlatformStatus,
};
}
await this.savePrepareInfo(platformData, projectData, null);
}
async ensurePrepareInfo(platformData, projectData, prepareData) {
this._prepareInfo = this.getPrepareInfo(platformData);
if (this._prepareInfo) {
const prepareInfoFile = path.join(platformData.projectRoot, prepareInfoFileName);
this._outputProjectMtime = this.$fs
.getFsStats(prepareInfoFile)
.mtime.getTime();
this._outputProjectCTime = this.$fs
.getFsStats(prepareInfoFile)
.ctime.getTime();
return false;
}
const nativePlatformStatus = !prepareData.nativePrepare || !prepareData.nativePrepare.skipNativePrepare
? "2" /* NativePlatformStatus.requiresPrepare */
: "1" /* NativePlatformStatus.requiresPlatformAdd */;
this._prepareInfo = {
time: "",
nativePlatformStatus,
release: prepareData.release,
changesRequireBuild: true,
projectFileHash: this.getProjectFileStrippedHash(projectData.projectDir, platformData),
changesRequireBuildTime: null,
};
this._outputProjectMtime = 0;
this._outputProjectCTime = 0;
this._changesInfo = this._changesInfo || new ProjectChangesInfo();
this._changesInfo.appResourcesChanged = true;
this._changesInfo.configChanged = true;
this._changesInfo.nativeChanged = true;
this._changesInfo.nsConfigChanged = true;
return true;
}
getProjectFileStrippedHash(projectDir, platformData) {
const projectFilePath = path.join(projectDir, constants_1.PACKAGE_JSON_FILE_NAME);
const projectFileContents = this.$fs.readJson(projectFilePath);
const relevantProperties = ["dependencies"];
const projectFileStrippedContents = _.pick(projectFileContents, relevantProperties);
// _(this.$devicePlatformsConstants)
// .keys()
// .map(k => k.toLowerCase())
// .difference([platformData.platformNameLowerCase])
// .each(otherPlatform => {
// delete projectFileContents.nativescript[`tns-${otherPlatform}`];
// });
return (0, helpers_1.getHash)(JSON.stringify(projectFileStrippedContents));
}
isProjectFileChanged(projectDir, platformData) {
const projectFileStrippedContentsHash = this.getProjectFileStrippedHash(projectDir, platformData);
const prepareInfo = this.getPrepareInfo(platformData);
return projectFileStrippedContentsHash !== prepareInfo.projectFileHash;
}
filesChanged(files) {
for (const file of files) {
if (this.$fs.exists(file)) {
const fileStats = this.$fs.getFsStats(file);
if (fileStats.mtime.getTime() >= this._outputProjectMtime ||
fileStats.ctime.getTime() >= this._outputProjectCTime) {
return true;
}
}
}
return false;
}
containsNewerFiles(dir, projectData) {
const dirName = path.basename(dir);
this.$logger.trace(`containsNewerFiles will check ${dir}`);
if (_.startsWith(dirName, ".")) {
return false;
}
if (this.isFileModified(dir)) {
this.$logger.trace(`containsNewerFiles returns true for ${dir} as the dir itself has been modified.`);
return true;
}
const files = this.$fs.readDirectory(dir);
for (const file of files) {
const filePath = path.join(dir, file);
const fileStats = this.$fs.getFsStats(filePath);
const changed = this.isFileModified(filePath, fileStats);
if (changed) {
this.$logger.trace(`containsNewerFiles returns true for ${dir}. The modified file is ${filePath}`);
return true;
}
if (fileStats.isDirectory()) {
if (this.containsNewerFiles(filePath, projectData)) {
this.$logger.trace(`containsNewerFiles returns true for ${dir}.`);
return true;
}
}
}
return false;
}
isFileModified(filePath, filePathStats) {
filePathStats = filePathStats || this.$fs.getFsStats(filePath);
let changed = filePathStats.mtime.getTime() >= this._outputProjectMtime ||
filePathStats.ctime.getTime() >= this._outputProjectCTime;
if (!changed) {
const lFileStats = this.$fs.getLsStats(filePath);
changed =
lFileStats.mtime.getTime() >= this._outputProjectMtime ||
lFileStats.ctime.getTime() >= this._outputProjectCTime;
}
return changed;
}
}
exports.ProjectChangesService = ProjectChangesService;
__decorate([
(0, helpers_1.hook)("checkForChanges")
], ProjectChangesService.prototype, "checkForChanges", null);
yok_1.injector.register("projectChangesService", ProjectChangesService);
//# sourceMappingURL=project-changes-service.js.map