-
-
Notifications
You must be signed in to change notification settings - Fork 197
/
Copy pathlivesync-service.ts
133 lines (107 loc) · 5.81 KB
/
livesync-service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import * as constants from "../../constants";
import * as helpers from "../../common/helpers";
import * as path from "path";
import { NodeModulesDependenciesBuilder } from "../../tools/node-modules/node-modules-dependencies-builder";
let choki = require("chokidar");
class LiveSyncService implements ILiveSyncService {
private _isInitialized = false;
constructor(private $errors: IErrors,
private $platformsData: IPlatformsData,
private $platformService: IPlatformService,
private $injector: IInjector,
private $devicesService: Mobile.IDevicesService,
private $options: IOptions,
private $logger: ILogger,
private $dispatcher: IFutureDispatcher,
private $hooksService: IHooksService,
private $processService: IProcessService) { }
public get isInitialized(): boolean { // This function is used from https://github.com/NativeScript/nativescript-dev-typescript/blob/master/lib/before-prepare.js#L4
return this._isInitialized;
}
public async liveSync(platform: string, projectData: IProjectData, applicationReloadAction?: (deviceAppData: Mobile.IDeviceAppData) => Promise<void>): Promise<void> {
if (this.$options.justlaunch) {
this.$options.watch = false;
}
let liveSyncData: ILiveSyncData[] = [];
if (platform) {
await this.$devicesService.initialize({ platform: platform, deviceId: this.$options.device });
liveSyncData.push(await this.prepareLiveSyncData(platform, projectData));
} else if (this.$options.device) {
await this.$devicesService.initialize({ platform: platform, deviceId: this.$options.device });
platform = this.$devicesService.getDeviceByIdentifier(this.$options.device).deviceInfo.platform;
liveSyncData.push(await this.prepareLiveSyncData(platform, projectData));
} else {
await this.$devicesService.initialize({ skipInferPlatform: true, skipDeviceDetectionInterval: true });
for (let installedPlatform of this.$platformService.getInstalledPlatforms(projectData)) {
if (this.$devicesService.getDevicesForPlatform(installedPlatform).length === 0) {
await this.$devicesService.startEmulator(installedPlatform);
}
liveSyncData.push(await this.prepareLiveSyncData(installedPlatform, projectData));
}
}
if (liveSyncData.length === 0) {
this.$errors.fail("There are no platforms installed in this project. Please specify platform or install one by using `tns platform add` command!");
}
this._isInitialized = true; // If we want before-prepare hooks to work properly, this should be set after preparePlatform function
await this.liveSyncCore(liveSyncData, applicationReloadAction, projectData);
}
private async prepareLiveSyncData(platform: string, projectData: IProjectData): Promise<ILiveSyncData> {
platform = platform || this.$devicesService.platform;
let platformData = this.$platformsData.getPlatformData(platform.toLowerCase(), projectData);
let liveSyncData: ILiveSyncData = {
platform: platform,
appIdentifier: projectData.projectId,
projectFilesPath: path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME),
syncWorkingDirectory: projectData.projectDir,
excludedProjectDirsAndFiles: this.$options.release ? constants.LIVESYNC_EXCLUDED_FILE_PATTERNS : []
};
return liveSyncData;
}
@helpers.hook('livesync')
private async liveSyncCore(liveSyncData: ILiveSyncData[], applicationReloadAction: (deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[]) => Promise<void>, projectData: IProjectData): Promise<void> {
await this.$platformService.trackProjectType(projectData);
let watchForChangeActions: ((event: string, filePath: string, dispatcher: IFutureDispatcher) => Promise<void>)[] = [];
for (let dataItem of liveSyncData) {
let service: IPlatformLiveSyncService = this.$injector.resolve("platformLiveSyncService", { _liveSyncData: dataItem });
watchForChangeActions.push((event: string, filePath: string, dispatcher: IFutureDispatcher) =>
service.partialSync(event, filePath, dispatcher, applicationReloadAction, projectData));
await service.fullSync(projectData, applicationReloadAction);
}
if (this.$options.watch && !this.$options.justlaunch) {
await this.$hooksService.executeBeforeHooks('watch');
await this.partialSync(liveSyncData[0].syncWorkingDirectory, watchForChangeActions, projectData);
}
}
private partialSync(syncWorkingDirectory: string, onChangedActions: ((event: string, filePath: string, dispatcher: IFutureDispatcher) => Promise<void>)[], projectData: IProjectData): void {
let that = this;
let dependenciesBuilder = this.$injector.resolve(NodeModulesDependenciesBuilder, {});
let productionDependencies = dependenciesBuilder.getProductionDependencies(projectData.projectDir);
let pattern = ["app"];
if (this.$options.syncAllFiles) {
pattern.push("package.json");
// watch only production node_module/packages same one prepare uses
for (let index in productionDependencies) {
pattern.push("node_modules/" + productionDependencies[index].name);
}
}
let watcher = choki.watch(pattern, { ignoreInitial: true, cwd: syncWorkingDirectory, ignored: '**/*.DS_Store' }).on("all", (event: string, filePath: string) => {
that.$dispatcher.dispatch(async () => {
try {
filePath = path.join(syncWorkingDirectory, filePath);
for (let i = 0; i < onChangedActions.length; i++) {
that.$logger.trace(`Event '${event}' triggered for path: '${filePath}'`);
await onChangedActions[i](event, filePath, that.$dispatcher);
}
} catch (err) {
that.$logger.info(`Unable to sync file ${filePath}. Error is:${err.message}`.red.bold);
that.$logger.info("Try saving it again or restart the livesync operation.");
}
});
});
this.$processService.attachToProcessExitSignals(this, () => {
watcher.close(pattern);
});
this.$dispatcher.run();
}
}
$injector.register("usbLiveSyncService", LiveSyncService);