Skip to content

Commit 54003cc

Browse files
committed
Refactor code in order to remove duplications of logic for generating hashes -> Extract all this logic to base class and reuse it from livesync with sockets and old livesync service
Remove all $options from services
1 parent 9267dc9 commit 54003cc

14 files changed

+549
-136
lines changed

lib/definitions/files-hash-service.d.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,15 @@ interface IFilesHashService {
77
* A map with key file's path and value - file's hash
88
*/
99
generateHashesForProject(platformData: IPlatformData): Promise<IStringDictionary>;
10-
/**
11-
* @param hashesFileDirectory - Path to directory containing the hash file.
12-
* @returns {IStringDictionary}
13-
* In case .nshashes file exists (under `hashesFileDirectory` directory), returns its content
14-
* In case .nshashes file does not exist (under `hashesFileDirectory` directory), returns {}
15-
*/
16-
getGeneratedHashes(hashesFileDirectory: string): IStringDictionary;
1710
/**
1811
* Generates hashes for all prepared files (all files from app folder under platforms folder)
1912
* and saves them in .nshashes file under `hashFileDirectory` directory.
2013
* @param platformData - Current platform's data
2114
* @param hashesFileDirectory - Path to directory containing the hash file.
2215
* @returns {Promise<void>}
2316
*/
24-
saveHashesForProject(platformData: IPlatformData, hashesFileDirectory: string): Promise<void>;
17+
saveHashesForProject(platformData: IPlatformData, hashesFileDirectory: string): Promise<IStringDictionary>;
18+
saveHashes(hashes: IStringDictionary, hashesFileDirectory: string): void;
2519
getChanges(files: string[], oldHashes: IStringDictionary): Promise<IStringDictionary>;
2620
hasChangesInShasums(oldHashes: IStringDictionary, newHashes: IStringDictionary): boolean;
2721
}

lib/definitions/livesync.d.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,13 @@ interface ILiveSyncInfo extends IProjectDir, IEnvOptions, IBundle, IRelease, IOp
154154
*/
155155
clean?: boolean;
156156

157+
/**
158+
* Defines if initial sync will be forced.
159+
* In case it is true, transfers all project's directory on device
160+
* In case it is false, transfers only changed files.
161+
*/
162+
force?: boolean;
163+
157164
/**
158165
* Defines the timeout in seconds {N} CLI will wait to find the inspector socket port from device's logs.
159166
* If not provided, defaults to 10seconds.
@@ -330,6 +337,8 @@ interface ILiveSyncWatchInfo extends IProjectDataComposition, IHasUseHotModuleRe
330337
filesToSync: string[];
331338
isReinstalled: boolean;
332339
syncAllFiles: boolean;
340+
liveSyncDeviceInfo: ILiveSyncDeviceInfo;
341+
force?: boolean;
333342
}
334343

335344
interface ILiveSyncResultInfo extends IHasUseHotModuleReloadOption {
@@ -344,6 +353,13 @@ interface IFullSyncInfo extends IProjectDataComposition, IHasUseHotModuleReloadO
344353
device: Mobile.IDevice;
345354
watch: boolean;
346355
syncAllFiles: boolean;
356+
liveSyncDeviceInfo: ILiveSyncDeviceInfo;
357+
force?: boolean;
358+
}
359+
360+
interface ITransferFilesOptions {
361+
isFullSync: boolean;
362+
force?: boolean;
347363
}
348364

349365
interface IPlatformLiveSyncService {
@@ -383,7 +399,7 @@ interface INativeScriptDeviceLiveSyncService extends IDeviceLiveSyncServiceBase
383399
* @param {boolean} isFullSync Indicates if the operation is part of a fullSync
384400
* @return {Promise<Mobile.ILocalToDevicePathData[]>} Returns the ILocalToDevicePathData of all transfered files
385401
*/
386-
transferFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string, isFullSync: boolean): Promise<Mobile.ILocalToDevicePathData[]>;
402+
transferFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string, projectData: IProjectData, liveSyncDeviceInfo: ILiveSyncDeviceInfo, options: ITransferFilesOptions): Promise<Mobile.ILocalToDevicePathData[]>;
387403
}
388404

389405
interface IAndroidNativeScriptDeviceLiveSyncService extends INativeScriptDeviceLiveSyncService {

lib/helpers/livesync-command-helper.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ export class LiveSyncCommandHelper implements ILiveSyncCommandHelper {
115115
release: this.$options.release,
116116
env: this.$options.env,
117117
timeout: this.$options.timeout,
118-
useHotModuleReload: this.$options.hmr
118+
useHotModuleReload: this.$options.hmr,
119+
force: this.$options.force
119120
};
120121

121122
await this.$liveSyncService.liveSync(deviceDescriptors, liveSyncInfo);

lib/services/files-hash-service.ts

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,10 @@ export class FilesHashService implements IFilesHashService {
3333
return hashes;
3434
}
3535

36-
public async saveHashesForProject(platformData: IPlatformData, hashesFileDirectory: string): Promise<void> {
36+
public async saveHashesForProject(platformData: IPlatformData, hashesFileDirectory: string): Promise<IStringDictionary> {
3737
const hashes = await this.generateHashesForProject(platformData);
38-
const hashesFilePath = path.join(hashesFileDirectory, HASHES_FILE_NAME);
39-
this.$fs.writeJson(hashesFilePath, hashes);
40-
}
41-
42-
public getGeneratedHashes(hashesFileDirectory: string): IStringDictionary {
43-
let result = {};
44-
const hashesFilePath = path.join(hashesFileDirectory, HASHES_FILE_NAME);
45-
if (this.$fs.exists(hashesFilePath)) {
46-
result = this.$fs.readJson(hashesFilePath);
47-
}
48-
49-
return result;
38+
this.saveHashes(hashes, hashesFileDirectory);
39+
return hashes;
5040
}
5141

5242
public async getChanges(files: string[], oldHashes: IStringDictionary): Promise<IStringDictionary> {
@@ -58,6 +48,11 @@ export class FilesHashService implements IFilesHashService {
5848
return !!_.keys(this.getChangesInShasums(oldHashes, newHashes)).length;
5949
}
6050

51+
public saveHashes(hashes: IStringDictionary, hashesFileDirectory: string): void {
52+
const hashesFilePath = path.join(hashesFileDirectory, HASHES_FILE_NAME);
53+
this.$fs.writeJson(hashesFilePath, hashes);
54+
}
55+
6156
private getChangesInShasums(oldHashes: IStringDictionary, newHashes: IStringDictionary): IStringDictionary {
6257
return _.omitBy(newHashes, (hash: string, pathToFile: string) => !!_.find(oldHashes, (oldHash: string, oldPath: string) => pathToFile === oldPath && hash === oldHash));
6358
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { DeviceLiveSyncServiceBase } from './device-livesync-service-base';
2+
import { AndroidDeviceHashService } from "../../common/mobile/android/android-device-hash-service";
3+
4+
export abstract class AndroidDeviceLiveSyncServiceBase extends DeviceLiveSyncServiceBase {
5+
private deviceHashServices: IDictionary<Mobile.IAndroidDeviceHashService>;
6+
7+
constructor(protected $injector: IInjector,
8+
protected $platformsData: IPlatformsData,
9+
protected $filesHashService: IFilesHashService,
10+
protected $logger: ILogger,
11+
protected device: Mobile.IAndroidDevice) {
12+
super($platformsData, device);
13+
this.deviceHashServices = {};
14+
}
15+
16+
public abstract async transferFilesOnDevice(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[]): Promise<void>;
17+
public abstract async transferDirectoryOnDevice(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string): Promise<void>;
18+
19+
public getDeviceHashService(appIdentifier: string): Mobile.IAndroidDeviceHashService {
20+
const key = `${this.device.deviceInfo.identifier}${appIdentifier}`;
21+
if (!this.deviceHashServices[key]) {
22+
const deviceHashService = this.$injector.resolve(AndroidDeviceHashService, { adb: this.device.adb, appIdentifier });
23+
this.deviceHashServices[key] = deviceHashService;
24+
}
25+
26+
return this.deviceHashServices[key];
27+
}
28+
29+
public async transferFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string, projectData: IProjectData, liveSyncDeviceInfo: ILiveSyncDeviceInfo, options: ITransferFilesOptions): Promise<Mobile.ILocalToDevicePathData[]> {
30+
const transferredFiles = await this.transferFilesCore(deviceAppData, localToDevicePaths, projectFilesPath, options);
31+
await this.updateHashes(deviceAppData, localToDevicePaths, projectData, liveSyncDeviceInfo);
32+
return transferredFiles;
33+
}
34+
35+
private async transferFilesCore(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string, options: ITransferFilesOptions): Promise<Mobile.ILocalToDevicePathData[]> {
36+
if (options.force && options.isFullSync) {
37+
const hashFileDevicePath = this.getDeviceHashService(deviceAppData.appIdentifier).hashFileDevicePath;
38+
await this.device.fileSystem.deleteFile(hashFileDevicePath, deviceAppData.appIdentifier);
39+
this.$logger.trace("Before transfer directory on device ", localToDevicePaths);
40+
await this.transferDirectoryOnDevice(deviceAppData, localToDevicePaths, projectFilesPath);
41+
return localToDevicePaths;
42+
}
43+
44+
const localToDevicePathsToTransfer = await this.getLocalToDevicePathsToTransfer(deviceAppData, localToDevicePaths, options);
45+
this.$logger.trace("Files to transfer: ", localToDevicePathsToTransfer);
46+
await this.transferFilesOnDevice(deviceAppData, localToDevicePathsToTransfer);
47+
return localToDevicePathsToTransfer;
48+
}
49+
50+
private async getLocalToDevicePathsToTransfer(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], options: ITransferFilesOptions): Promise<Mobile.ILocalToDevicePathData[]> {
51+
if (options.force || !options.isFullSync) {
52+
return localToDevicePaths;
53+
}
54+
55+
const changedLocalToDevicePaths = await this.getChangedLocalToDevicePaths(deviceAppData.appIdentifier, localToDevicePaths);
56+
return changedLocalToDevicePaths;
57+
}
58+
59+
private async getChangedLocalToDevicePaths(appIdentifier: string, localToDevicePaths: Mobile.ILocalToDevicePathData[]): Promise<Mobile.ILocalToDevicePathData[]> {
60+
const deviceHashService = this.getDeviceHashService(appIdentifier);
61+
const currentHashes = await deviceHashService.generateHashesFromLocalToDevicePaths(localToDevicePaths);
62+
const oldHashes = (await deviceHashService.getShasumsFromDevice()) || {};
63+
const changedHashes = deviceHashService.getChangedShasums(oldHashes, currentHashes);
64+
const changedFiles = _.keys(changedHashes);
65+
const changedLocalToDevicePaths = localToDevicePaths.filter(localToDevicePathData => changedFiles.indexOf(localToDevicePathData.getLocalPath()) >= 0);
66+
return changedLocalToDevicePaths;
67+
}
68+
69+
private async updateHashes(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectData: IProjectData, liveSyncDeviceInfo: ILiveSyncDeviceInfo): Promise<void> {
70+
const hashes = await this.updateHashesOnDevice(deviceAppData, localToDevicePaths, projectData, liveSyncDeviceInfo);
71+
this.updateLocalHashes(hashes, deviceAppData, projectData, liveSyncDeviceInfo);
72+
}
73+
74+
private async updateHashesOnDevice(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectData: IProjectData, liveSyncDeviceInfo: ILiveSyncDeviceInfo): Promise<IStringDictionary> {
75+
const deviceHashService = this.getDeviceHashService(deviceAppData.appIdentifier);
76+
const currentHashes = await deviceHashService.generateHashesFromLocalToDevicePaths(localToDevicePaths);
77+
await deviceHashService.uploadHashFileToDevice(currentHashes);
78+
return currentHashes;
79+
}
80+
81+
private updateLocalHashes(hashes: IStringDictionary, deviceAppData: Mobile.IDeviceAppData, projectData: IProjectData, liveSyncDeviceInfo: ILiveSyncDeviceInfo): void {
82+
const hashFilePath = liveSyncDeviceInfo.outputPath || this.$platformsData.getPlatformData(deviceAppData.platform, projectData).deviceBuildOutputPath;
83+
this.$filesHashService.saveHashes(hashes, hashFilePath);
84+
}
85+
}

lib/services/livesync/android-device-livesync-service.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,29 @@
1-
import { DeviceAndroidDebugBridge } from "../../common/mobile/android/device-android-debug-bridge";
2-
import { AndroidDeviceHashService } from "../../common/mobile/android/android-device-hash-service";
3-
import { DeviceLiveSyncServiceBase } from "./device-livesync-service-base";
1+
import { AndroidDeviceLiveSyncServiceBase } from "./android-device-livesync-service-base";
42
import * as helpers from "../../common/helpers";
53
import { LiveSyncPaths } from "../../common/constants";
6-
import { cache } from "../../common/decorators";
74
import * as path from "path";
85
import * as net from "net";
96

10-
export class AndroidDeviceLiveSyncService extends DeviceLiveSyncServiceBase implements IAndroidNativeScriptDeviceLiveSyncService, INativeScriptDeviceLiveSyncService {
7+
export class AndroidDeviceLiveSyncService extends AndroidDeviceLiveSyncServiceBase implements IAndroidNativeScriptDeviceLiveSyncService, INativeScriptDeviceLiveSyncService {
118
private port: number;
129

13-
constructor(
14-
private $mobileHelper: Mobile.IMobileHelper,
10+
constructor(private $mobileHelper: Mobile.IMobileHelper,
1511
private $devicePathProvider: IDevicePathProvider,
16-
private $injector: IInjector,
12+
$injector: IInjector,
1713
private $androidProcessService: Mobile.IAndroidProcessService,
1814
protected $platformsData: IPlatformsData,
19-
protected device: Mobile.IAndroidDevice) {
20-
super($platformsData, device);
15+
protected device: Mobile.IAndroidDevice,
16+
$filesHashService: IFilesHashService,
17+
$logger: ILogger) {
18+
super($injector, $platformsData, $filesHashService, $logger, device);
19+
}
20+
21+
public async transferFilesOnDevice(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[]): Promise<void> {
22+
await this.device.fileSystem.transferFiles(deviceAppData, localToDevicePaths);
23+
}
24+
25+
public async transferDirectoryOnDevice(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string): Promise<void> {
26+
await this.device.fileSystem.transferDirectory(deviceAppData, localToDevicePaths, projectFilesPath);
2127
}
2228

2329
public async refreshApplication(projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo): Promise<void> {
@@ -116,12 +122,6 @@ export class AndroidDeviceLiveSyncService extends DeviceLiveSyncServiceBase impl
116122
await this.getDeviceHashService(deviceAppData.appIdentifier).removeHashes(localToDevicePaths);
117123
}
118124

119-
@cache()
120-
public getDeviceHashService(appIdentifier: string): Mobile.IAndroidDeviceHashService {
121-
const adb = this.$injector.resolve(DeviceAndroidDebugBridge, { identifier: this.device.deviceInfo.identifier });
122-
return this.$injector.resolve(AndroidDeviceHashService, { adb, appIdentifier });
123-
}
124-
125125
private async awaitRuntimeReloadSuccessMessage(): Promise<boolean> {
126126
return new Promise<boolean>((resolve, reject) => {
127127
let isResolved = false;

lib/services/livesync/android-device-livesync-sockets-service.ts

Lines changed: 15 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,30 @@
1-
import { DeviceAndroidDebugBridge } from "../../common/mobile/android/device-android-debug-bridge";
2-
import { AndroidDeviceHashService } from "../../common/mobile/android/android-device-hash-service";
3-
import { DeviceLiveSyncServiceBase } from "./device-livesync-service-base";
1+
import { AndroidDeviceLiveSyncServiceBase } from "./android-device-livesync-service-base";
42
import { APP_FOLDER_NAME } from "../../constants";
53
import { LiveSyncPaths } from "../../common/constants";
64
import { AndroidLivesyncTool } from "./android-livesync-tool";
75
import * as path from "path";
86
import * as temp from "temp";
97
import * as semver from "semver";
108

11-
export class AndroidDeviceSocketsLiveSyncService extends DeviceLiveSyncServiceBase implements IAndroidNativeScriptDeviceLiveSyncService, INativeScriptDeviceLiveSyncService {
9+
export class AndroidDeviceSocketsLiveSyncService extends AndroidDeviceLiveSyncServiceBase implements IAndroidNativeScriptDeviceLiveSyncService, INativeScriptDeviceLiveSyncService {
1210
private livesyncTool: IAndroidLivesyncTool;
1311
private static STATUS_UPDATE_INTERVAL = 10000;
1412
private static MINIMAL_VERSION_LONG_LIVING_CONNECTION = "0.2.0";
1513

1614
constructor(
1715
private data: IProjectData,
18-
private $injector: IInjector,
16+
$injector: IInjector,
1917
protected $platformsData: IPlatformsData,
2018
protected $staticConfig: Config.IStaticConfig,
21-
private $logger: ILogger,
19+
$logger: ILogger,
2220
protected device: Mobile.IAndroidDevice,
2321
private $options: IOptions,
2422
private $processService: IProcessService,
2523
private $fs: IFileSystem,
26-
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants) {
27-
super($platformsData, device);
28-
this.livesyncTool = this.$injector.resolve(AndroidLivesyncTool);
24+
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
25+
$filesHashService: IFilesHashService) {
26+
super($injector, $platformsData, $filesHashService, $logger, device);
27+
this.livesyncTool = this.$injector.resolve(AndroidLivesyncTool);
2928
}
3029

3130
public async beforeLiveSyncAction(deviceAppData: Mobile.IDeviceAppData): Promise<void> {
@@ -101,67 +100,17 @@ export class AndroidDeviceSocketsLiveSyncService extends DeviceLiveSyncServiceBa
101100

102101
public async removeFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string): Promise<void> {
103102
await this.livesyncTool.removeFiles(_.map(localToDevicePaths, (element: any) => element.filePath));
104-
105-
await this.getDeviceHashService(deviceAppData.appIdentifier).removeHashes(localToDevicePaths);
106-
}
107-
108-
public async transferFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string, isFullSync: boolean): Promise<Mobile.ILocalToDevicePathData[]> {
109-
let transferredFiles;
110-
111-
if (isFullSync) {
112-
transferredFiles = await this._transferDirectory(deviceAppData, localToDevicePaths, projectFilesPath);
113-
} else {
114-
transferredFiles = await this._transferFiles(deviceAppData, localToDevicePaths);
115-
}
116-
117-
return transferredFiles;
118-
}
119-
120-
public getDeviceHashService(appIdentifier: string): Mobile.IAndroidDeviceHashService {
121-
const adb = this.$injector.resolve(DeviceAndroidDebugBridge, { identifier: this.device.deviceInfo.identifier });
122-
return this.$injector.resolve(AndroidDeviceHashService, { adb, appIdentifier });
123-
}
124-
125-
private async _transferFiles(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[]): Promise<Mobile.ILocalToDevicePathData[]> {
126-
await this.livesyncTool.sendFiles(localToDevicePaths.map(localToDevicePathData => localToDevicePathData.getLocalPath()));
127-
128-
// Update hashes
129103
const deviceHashService = this.getDeviceHashService(deviceAppData.appIdentifier);
130-
if (! await deviceHashService.updateHashes(localToDevicePaths)) {
131-
this.$logger.trace("Unable to find hash file on device. The next livesync command will create it.");
132-
}
133-
134-
return localToDevicePaths;
104+
await deviceHashService.removeHashes(localToDevicePaths);
135105
}
136106

137-
private async _transferDirectory(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string): Promise<Mobile.ILocalToDevicePathData[]> {
138-
let transferredLocalToDevicePaths: Mobile.ILocalToDevicePathData[];
139-
const deviceHashService = this.getDeviceHashService(deviceAppData.appIdentifier);
140-
const currentHashes = await deviceHashService.generateHashesFromLocalToDevicePaths(localToDevicePaths);
141-
const oldHashes = await deviceHashService.getShasumsFromDevice();
142-
console.log("!!!!! OLD HASHES!!!!!!");
143-
console.log(oldHashes);
144-
145-
if (this.$options.force || !oldHashes) {
146-
console.log("!!!!!!!!! NO OLD HASHES!!!!! THIS SHOULD NOT HAPPEN!!!!!!!");
147-
await this.livesyncTool.sendDirectory(projectFilesPath);
148-
await deviceHashService.uploadHashFileToDevice(currentHashes);
149-
transferredLocalToDevicePaths = localToDevicePaths;
150-
} else {
151-
const changedShasums = deviceHashService.getChangedShasums(oldHashes, currentHashes);
152-
console.log("CHANGEDSHASUMS!!!!!!!!!!!!!!!");
153-
console.log(changedShasums);
154-
const changedFiles = _.keys(changedShasums);
155-
if (changedFiles.length) {
156-
await this.livesyncTool.sendFiles(changedFiles);
157-
await deviceHashService.uploadHashFileToDevice(currentHashes);
158-
transferredLocalToDevicePaths = localToDevicePaths.filter(localToDevicePathData => changedFiles.indexOf(localToDevicePathData.getLocalPath()) >= 0);
159-
} else {
160-
transferredLocalToDevicePaths = [];
161-
}
162-
}
107+
public async transferFilesOnDevice(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[]): Promise<void> {
108+
const files = _.map(localToDevicePaths, localToDevicePath => localToDevicePath.getLocalPath());
109+
await this.livesyncTool.sendFiles(files);
110+
}
163111

164-
return transferredLocalToDevicePaths;
112+
public async transferDirectoryOnDevice(deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[], projectFilesPath: string): Promise<void> {
113+
await this.livesyncTool.sendDirectory(projectFilesPath);
165114
}
166115

167116
private async connectLivesyncTool(appIdentifier: string) {

0 commit comments

Comments
 (0)