Skip to content

Commit 5e5f18a

Browse files
Merge pull request #3750 from NativeScript/vladimirov/rebuild-plugin-when-required-only
feat: Improve rebuild of native plugins and node_modules checks
2 parents 0f403d2 + 1a2388e commit 5e5f18a

15 files changed

+172
-34
lines changed

lib/commands/appstore-upload.ts

-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ export class PublishIOS implements ICommand {
6060
const platformInfo: IPreparePlatformInfo = {
6161
platform,
6262
appFilesUpdaterOptions,
63-
skipModulesNativeCheck: !this.$options.syncAllFiles,
6463
platformTemplate: this.$options.platformTemplate,
6564
projectData: this.$projectData,
6665
config: this.$options,

lib/commands/build.ts

-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ export class BuildCommandBase {
1717
const platformInfo: IPreparePlatformInfo = {
1818
platform,
1919
appFilesUpdaterOptions,
20-
skipModulesNativeCheck: !this.$options.syncAllFiles,
2120
platformTemplate: this.$options.platformTemplate,
2221
projectData: this.$projectData,
2322
config: this.$options,

lib/commands/prepare.ts

-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ export class PrepareCommand implements ICommand {
1414
const platformInfo: IPreparePlatformInfo = {
1515
platform: args[0],
1616
appFilesUpdaterOptions,
17-
skipModulesNativeCheck: !this.$options.syncAllFiles,
1817
platformTemplate: this.$options.platformTemplate,
1918
projectData: this.$projectData,
2019
config: this.$options,

lib/constants.ts

+2
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,5 @@ export const PACKAGE_PLACEHOLDER_NAME = "__PACKAGE__";
217217
export class AddPlaformErrors {
218218
public static InvalidFrameworkPathStringFormat = "Invalid frameworkPath: %s. Please ensure the specified frameworkPath exists.";
219219
}
220+
221+
export const PLUGIN_BUILD_DATA_FILENAME = "plugin-data.json";
+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
interface IFilesHashService {
22
generateHashes(files: string[]): Promise<IStringDictionary>;
33
getChanges(files: string[], oldHashes: IStringDictionary): Promise<IStringDictionary>;
4-
}
4+
hasChangesInShasums(oldHashes: IStringDictionary, newHashes: IStringDictionary): boolean;
5+
}

lib/definitions/project-changes.d.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,12 @@ interface IProjectChangesOptions extends IAppFilesUpdaterOptions, IProvision, IT
4141
nativePlatformStatus?: "1" | "2" | "3";
4242
}
4343

44+
interface ICheckForChangesOptions extends IPlatform, IProjectDataComposition {
45+
projectChangesOptions: IProjectChangesOptions;
46+
}
47+
4448
interface IProjectChangesService {
45-
checkForChanges(platform: string, projectData: IProjectData, buildOptions: IProjectChangesOptions): Promise<IProjectChangesInfo>;
49+
checkForChanges(checkForChangesOpts: ICheckForChangesOptions): Promise<IProjectChangesInfo>;
4650
getPrepareInfo(platform: string, projectData: IProjectData): IPrepareInfo;
4751
savePrepareInfo(platform: string, projectData: IProjectData): void;
4852
getPrepareInfoFilePath(platform: string, projectData: IProjectData): string;

lib/services/android-plugin-build-service.ts

+65-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as path from "path";
2-
import { MANIFEST_FILE_NAME, INCLUDE_GRADLE_NAME, ASSETS_DIR, RESOURCES_DIR, TNS_ANDROID_RUNTIME_NAME, AndroidBuildDefaults } from "../constants";
2+
import { MANIFEST_FILE_NAME, INCLUDE_GRADLE_NAME, ASSETS_DIR, RESOURCES_DIR, TNS_ANDROID_RUNTIME_NAME, AndroidBuildDefaults, PLUGIN_BUILD_DATA_FILENAME } from "../constants";
33
import { getShortPluginName, hook } from "../common/helpers";
44
import { Builder, parseString } from "xml2js";
55
import { ILogger } from "log4js";
@@ -25,7 +25,8 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService {
2525
private $npm: INodePackageManager,
2626
private $projectDataService: IProjectDataService,
2727
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
28-
private $errors: IErrors) { }
28+
private $errors: IErrors,
29+
private $filesHashService: IFilesHashService) { }
2930

3031
private static MANIFEST_ROOT = {
3132
$: {
@@ -172,23 +173,80 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService {
172173
this.validateOptions(options);
173174
const manifestFilePath = this.getManifest(options.platformsAndroidDirPath);
174175
const androidSourceDirectories = this.getAndroidSourceDirectories(options.platformsAndroidDirPath);
175-
const shouldBuildAar = !!manifestFilePath || androidSourceDirectories.length > 0;
176+
const shortPluginName = getShortPluginName(options.pluginName);
177+
const pluginTempDir = path.join(options.tempPluginDirPath, shortPluginName);
178+
const pluginSourceFileHashesInfo = await this.getSourceFilesHashes(options.platformsAndroidDirPath, shortPluginName);
179+
180+
const shouldBuildAar = await this.shouldBuildAar({
181+
manifestFilePath,
182+
androidSourceDirectories,
183+
pluginTempDir,
184+
pluginSourceDir: options.platformsAndroidDirPath,
185+
shortPluginName,
186+
fileHashesInfo: pluginSourceFileHashesInfo
187+
});
176188

177189
if (shouldBuildAar) {
178-
const shortPluginName = getShortPluginName(options.pluginName);
179-
const pluginTempDir = path.join(options.tempPluginDirPath, shortPluginName);
180-
const pluginTempMainSrcDir = path.join(pluginTempDir, "src", "main");
190+
this.cleanPluginDir(pluginTempDir);
181191

192+
const pluginTempMainSrcDir = path.join(pluginTempDir, "src", "main");
182193
await this.updateManifest(manifestFilePath, pluginTempMainSrcDir, shortPluginName);
183194
this.copySourceSetDirectories(androidSourceDirectories, pluginTempMainSrcDir);
184195
await this.setupGradle(pluginTempDir, options.platformsAndroidDirPath, options.projectDir);
185196
await this.buildPlugin({ pluginDir: pluginTempDir, pluginName: options.pluginName });
186197
this.copyAar(shortPluginName, pluginTempDir, options.aarOutputDir);
198+
this.writePluginHashInfo(pluginSourceFileHashesInfo, pluginTempDir);
187199
}
188200

189201
return shouldBuildAar;
190202
}
191203

204+
private cleanPluginDir(pluginTempDir: string): void {
205+
// In case plugin was already built in the current process, we need to clean the old sources as they may break the new build.
206+
this.$fs.deleteDirectory(pluginTempDir);
207+
this.$fs.ensureDirectoryExists(pluginTempDir);
208+
}
209+
210+
private getSourceFilesHashes(pluginTempPlatformsAndroidDir: string, shortPluginName: string): Promise<IStringDictionary> {
211+
const pathToAar = path.join(pluginTempPlatformsAndroidDir, `${shortPluginName}.aar`);
212+
const pluginNativeDataFiles = this.$fs.enumerateFilesInDirectorySync(pluginTempPlatformsAndroidDir, (file: string, stat: IFsStats) => file !== pathToAar);
213+
return this.$filesHashService.generateHashes(pluginNativeDataFiles);
214+
}
215+
216+
private writePluginHashInfo(fileHashesInfo: IStringDictionary, pluginTempDir: string): void {
217+
const buildDataFile = this.getPathToPluginBuildDataFile(pluginTempDir);
218+
this.$fs.writeJson(buildDataFile, fileHashesInfo);
219+
}
220+
221+
private async shouldBuildAar(opts: {
222+
manifestFilePath: string,
223+
androidSourceDirectories: string[],
224+
pluginTempDir: string,
225+
pluginSourceDir: string,
226+
shortPluginName: string,
227+
fileHashesInfo: IStringDictionary
228+
}): Promise<boolean> {
229+
230+
let shouldBuildAar = !!opts.manifestFilePath || !!opts.androidSourceDirectories.length;
231+
232+
if (shouldBuildAar &&
233+
this.$fs.exists(opts.pluginTempDir) &&
234+
this.$fs.exists(path.join(opts.pluginSourceDir, `${opts.shortPluginName}.aar`))) {
235+
236+
const buildDataFile = this.getPathToPluginBuildDataFile(opts.pluginTempDir);
237+
if (this.$fs.exists(buildDataFile)) {
238+
const oldHashes = this.$fs.readJson(buildDataFile);
239+
shouldBuildAar = this.$filesHashService.hasChangesInShasums(oldHashes, opts.fileHashesInfo);
240+
}
241+
}
242+
243+
return shouldBuildAar;
244+
}
245+
246+
private getPathToPluginBuildDataFile(pluginDir: string): string {
247+
return path.join(pluginDir, PLUGIN_BUILD_DATA_FILENAME);
248+
}
249+
192250
private async updateManifest(manifestFilePath: string, pluginTempMainSrcDir: string, shortPluginName: string): Promise<void> {
193251
let updatedManifestContent;
194252
this.$fs.ensureDirectoryExists(pluginTempMainSrcDir);
@@ -256,7 +314,7 @@ export class AndroidPluginBuildService implements IAndroidPluginBuildService {
256314
return runtimeGradleVersions || {};
257315
}
258316

259-
private getGradleVersions(packageData: { gradle: { version: string, android: string }}): IRuntimeGradleVersions {
317+
private getGradleVersions(packageData: { gradle: { version: string, android: string } }): IRuntimeGradleVersions {
260318
const packageJsonGradle = packageData && packageData.gradle;
261319
let runtimeVersions: IRuntimeGradleVersions = null;
262320
if (packageJsonGradle && (packageJsonGradle.version || packageJsonGradle.android)) {

lib/services/files-hash-service.ts

+8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ export class FilesHashService implements IFilesHashService {
2626

2727
public async getChanges(files: string[], oldHashes: IStringDictionary): Promise<IStringDictionary> {
2828
const newHashes = await this.generateHashes(files);
29+
return this.getChangesInShasums(oldHashes, newHashes);
30+
}
31+
32+
public hasChangesInShasums(oldHashes: IStringDictionary, newHashes: IStringDictionary): boolean {
33+
return !!_.keys(this.getChangesInShasums(oldHashes, newHashes)).length;
34+
}
35+
36+
private getChangesInShasums(oldHashes: IStringDictionary, newHashes: IStringDictionary): IStringDictionary {
2937
return _.omitBy(newHashes, (hash: string, pathToFile: string) => !!_.find(oldHashes, (oldHash: string, oldPath: string) => pathToFile === oldPath && hash === oldHash));
3038
}
3139
}

lib/services/livesync/livesync-service.ts

-1
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,6 @@ export class LiveSyncService extends EventEmitter implements IDebugLiveSyncServi
469469
deviceBuildInfoDescriptor,
470470
liveSyncData,
471471
settings,
472-
skipModulesNativeCheck: !liveSyncData.watchAllFiles,
473472
bundle: liveSyncData.bundle,
474473
release: liveSyncData.release,
475474
env: liveSyncData.env

lib/services/platform-service.ts

+11-7
Original file line numberDiff line numberDiff line change
@@ -269,13 +269,17 @@ export class PlatformService extends EventEmitter implements IPlatformService {
269269

270270
const bundle = appFilesUpdaterOptions.bundle;
271271
const nativePlatformStatus = (nativePrepare && nativePrepare.skipNativePrepare) ? constants.NativePlatformStatus.requiresPlatformAdd : constants.NativePlatformStatus.requiresPrepare;
272-
const changesInfo = await this.$projectChangesService.checkForChanges(platform, projectData, {
273-
bundle,
274-
release: appFilesUpdaterOptions.release,
275-
provision: config.provision,
276-
teamId: config.teamId,
277-
nativePlatformStatus,
278-
skipModulesNativeCheck: skipNativeCheckOptions.skipModulesNativeCheck
272+
const changesInfo = await this.$projectChangesService.checkForChanges({
273+
platform,
274+
projectData,
275+
projectChangesOptions: {
276+
bundle,
277+
release: appFilesUpdaterOptions.release,
278+
provision: config.provision,
279+
teamId: config.teamId,
280+
nativePlatformStatus,
281+
skipModulesNativeCheck: skipNativeCheckOptions.skipModulesNativeCheck
282+
}
279283
});
280284

281285
this.$logger.trace("Changes info in prepare platform:", changesInfo);

lib/services/project-changes-service.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as path from "path";
22
import { NODE_MODULES_FOLDER_NAME, NativePlatformStatus, PACKAGE_JSON_FILE_NAME, APP_GRADLE_FILE_NAME, BUILD_XCCONFIG_FILE_NAME } from "../constants";
3-
import { getHash } from "../common/helpers";
3+
import { getHash, hook } from "../common/helpers";
44

55
const prepareInfoFileName = ".nsprepareinfo";
66

@@ -45,18 +45,25 @@ export class ProjectChangesService implements IProjectChangesService {
4545
private _outputProjectMtime: number;
4646
private _outputProjectCTime: number;
4747

48+
private get $hooksService(): IHooksService {
49+
return this.$injector.resolve<IHooksService>("hooksService");
50+
}
51+
4852
constructor(
4953
private $platformsData: IPlatformsData,
5054
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
5155
private $fs: IFileSystem,
52-
private $filesHashService: IFilesHashService) {
56+
private $filesHashService: IFilesHashService,
57+
private $injector: IInjector) {
5358
}
5459

5560
public get currentChanges(): IProjectChangesInfo {
5661
return this._changesInfo;
5762
}
5863

59-
public async checkForChanges(platform: string, projectData: IProjectData, projectChangesOptions: IProjectChangesOptions): Promise<IProjectChangesInfo> {
64+
@hook("checkForChanges")
65+
public async checkForChanges(checkForChangesOpts: ICheckForChangesOptions): Promise<IProjectChangesInfo> {
66+
const { platform, projectData, projectChangesOptions } = checkForChangesOpts;
6067
const platformData = this.$platformsData.getPlatformData(platform, projectData);
6168
this._changesInfo = new ProjectChangesInfo();
6269
const isNewPrepareInfo = await this.ensurePrepareInfo(platform, projectData, projectChangesOptions);

lib/services/test-execution-service.ts

-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ class TestExecutionService implements ITestExecutionService {
5959
const preparePlatformInfo: IPreparePlatformInfo = {
6060
platform,
6161
appFilesUpdaterOptions,
62-
skipModulesNativeCheck: !this.$options.syncAllFiles,
6362
platformTemplate: this.$options.platformTemplate,
6463
projectData,
6564
config: this.$options,
@@ -187,7 +186,6 @@ class TestExecutionService implements ITestExecutionService {
187186
const preparePlatformInfo: IPreparePlatformInfo = {
188187
platform,
189188
appFilesUpdaterOptions,
190-
skipModulesNativeCheck: !this.$options.syncAllFiles,
191189
platformTemplate: this.$options.platformTemplate,
192190
projectData,
193191
config: this.$options,

test/project-changes-service.ts

+23-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { PlatformsData } from "../lib/platforms-data";
66
import { ProjectChangesService } from "../lib/services/project-changes-service";
77
import * as Constants from "../lib/constants";
88
import { FileSystem } from "../lib/common/file-system";
9+
import { HooksServiceStub } from "./stubs";
910

1011
// start tracking temporary folders/files
1112
temp.track();
@@ -36,6 +37,7 @@ class ProjectChangesServiceTest extends BaseServiceTest {
3637
this.injector.register("logger", {
3738
warn: () => ({})
3839
});
40+
this.injector.register("hooksService", HooksServiceStub);
3941

4042
const fs = this.injector.resolve<IFileSystem>("fs");
4143
fs.writeJson(path.join(this.projectDir, Constants.PACKAGE_JSON_FILE_NAME), {
@@ -149,9 +151,28 @@ describe("Project Changes Service Tests", () => {
149151

150152
describe("Accumulates Changes From Project Services", () => {
151153
it("accumulates changes from the project service", async () => {
152-
const iOSChanges = await serviceTest.projectChangesService.checkForChanges("ios", serviceTest.projectData, { bundle: false, release: false, provision: undefined, teamId: undefined });
154+
const iOSChanges = await serviceTest.projectChangesService.checkForChanges({
155+
platform: "ios",
156+
projectData: serviceTest.projectData,
157+
projectChangesOptions: {
158+
bundle: false,
159+
release: false,
160+
provision: undefined,
161+
teamId: undefined
162+
}
163+
});
153164
assert.isTrue(!!iOSChanges.signingChanged, "iOS signingChanged expected to be true");
154-
const androidChanges = await serviceTest.projectChangesService.checkForChanges("android", serviceTest.projectData, { bundle: false, release: false, provision: undefined, teamId: undefined });
165+
166+
const androidChanges = await serviceTest.projectChangesService.checkForChanges({
167+
platform: "android",
168+
projectData: serviceTest.projectData,
169+
projectChangesOptions: {
170+
bundle: false,
171+
release: false,
172+
provision: undefined,
173+
teamId: undefined
174+
}
175+
});
155176
assert.isFalse(!!androidChanges.signingChanged, "Android signingChanged expected to be false");
156177
});
157178
});

0 commit comments

Comments
 (0)