-
-
Notifications
You must be signed in to change notification settings - Fork 197
/
Copy pathlivesync-service.ts
145 lines (131 loc) · 6.48 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
134
135
136
137
138
139
140
141
142
143
144
145
import * as constants from "../../constants";
import * as helpers from "../../common/helpers";
import * as path from "path";
import * as semver from "semver";
import * as fiberBootstrap from "../../common/fiber-bootstrap";
let choki = require("chokidar");
class LiveSyncService implements ILiveSyncService {
private _isInitialized = false;
constructor(private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
private $errors: IErrors,
private $platformsData: IPlatformsData,
private $platformService: IPlatformService,
private $projectData: IProjectData,
private $projectDataService: IProjectDataService,
private $prompter: IPrompter,
private $injector: IInjector,
private $liveSyncProvider: ILiveSyncProvider,
private $mobileHelper: Mobile.IMobileHelper,
private $devicesService: Mobile.IDevicesService,
private $options: IOptions,
private $logger: ILogger,
private $dispatcher: IFutureDispatcher,
private $hooksService: IHooksService,
private $processService: IProcessService) { }
private ensureAndroidFrameworkVersion(platformData: IPlatformData): IFuture<void> { // TODO: this can be moved inside command or canExecute function
return (() => {
this.$projectDataService.initialize(this.$projectData.projectDir);
let frameworkVersion = this.$projectDataService.getValue(platformData.frameworkPackageName).version;
if (platformData.normalizedPlatformName.toLowerCase() === this.$devicePlatformsConstants.Android.toLowerCase()) {
if (semver.lt(frameworkVersion, "1.2.1")) {
let shouldUpdate = this.$prompter.confirm("You need Android Runtime 1.2.1 or later for LiveSync to work properly. Do you want to update your runtime now?").wait();
if (shouldUpdate) {
this.$platformService.updatePlatforms([this.$devicePlatformsConstants.Android.toLowerCase()]).wait();
} else {
return;
}
}
}
}).future<void>()();
}
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 liveSync(platform: string, applicationReloadAction?: (deviceAppData: Mobile.IDeviceAppData) => IFuture<void>): IFuture<void> {
return (() => {
if (this.$options.justlaunch) {
this.$options.watch = false;
}
let liveSyncData: ILiveSyncData[] = [];
if (platform) {
this.$devicesService.initialize({ platform: platform, deviceId: this.$options.device }).wait();
liveSyncData.push(this.prepareLiveSyncData(platform));
} else if (this.$options.device) {
this.$devicesService.initialize({ platform: platform, deviceId: this.$options.device }).wait();
platform = this.$devicesService.getDeviceByIdentifier(this.$options.device).deviceInfo.platform;
liveSyncData.push(this.prepareLiveSyncData(platform));
} else {
this.$devicesService.initialize({ skipInferPlatform: true }).wait();
this.$devicesService.stopDeviceDetectionInterval().wait();
for(let installedPlatform of this.$platformService.getInstalledPlatforms()) {
if (this.$devicesService.getDevicesForPlatform(installedPlatform).length === 0) {
this.$devicesService.startEmulator(installedPlatform).wait();
}
liveSyncData.push(this.prepareLiveSyncData(installedPlatform));
}
}
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
this.liveSyncCore(liveSyncData, applicationReloadAction).wait();
}).future<void>()();
}
private prepareLiveSyncData(platform: string): ILiveSyncData {
platform = platform || this.$devicesService.platform;
let platformData = this.$platformsData.getPlatformData(platform.toLowerCase());
if (this.$mobileHelper.isAndroidPlatform(platform)) {
this.ensureAndroidFrameworkVersion(platformData).wait();
}
let liveSyncData: ILiveSyncData = {
platform: platform,
appIdentifier: this.$projectData.projectId,
projectFilesPath: path.join(platformData.appDestinationDirectoryPath, constants.APP_FOLDER_NAME),
syncWorkingDirectory: this.$projectData.projectDir,
excludedProjectDirsAndFiles: this.$options.release ? constants.LIVESYNC_EXCLUDED_FILE_PATTERNS : []
};
return liveSyncData;
}
@helpers.hook('livesync')
private liveSyncCore(liveSyncData: ILiveSyncData[], applicationReloadAction: (deviceAppData: Mobile.IDeviceAppData, localToDevicePaths: Mobile.ILocalToDevicePathData[]) => IFuture<void>): IFuture<void> {
return (() => {
this.$platformService.trackProjectType().wait();
let watchForChangeActions: ((event: string, filePath: string, dispatcher: IFutureDispatcher) => void)[] = [];
_.each(liveSyncData, (dataItem) => {
let service: IPlatformLiveSyncService = this.$injector.resolve("platformLiveSyncService", { _liveSyncData: dataItem });
watchForChangeActions.push((event: string, filePath: string, dispatcher: IFutureDispatcher) => {
service.partialSync(event, filePath, dispatcher, applicationReloadAction);
});
service.fullSync(applicationReloadAction).wait();
});
if(this.$options.watch && !this.$options.justlaunch) {
this.$hooksService.executeBeforeHooks('watch').wait();
this.partialSync(liveSyncData[0].syncWorkingDirectory, watchForChangeActions);
}
}).future<void>()();
}
private partialSync(syncWorkingDirectory: string, onChangedActions: ((event: string, filePath: string, dispatcher: IFutureDispatcher) => void )[]): void {
let that = this;
let pattern = ["app", "package.json", "node_modules"];
let watcher = choki.watch(pattern, { ignoreInitial: true, cwd: syncWorkingDirectory }).on("all", (event: string, filePath: string) => {
fiberBootstrap.run(() => {
that.$dispatcher.dispatch(() => (() => {
try {
filePath = path.join(syncWorkingDirectory, filePath);
for (let i = 0; i < onChangedActions.length; i++) {
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.");
}
}).future<void>()());
});
});
this.$processService.attachToProcessExitSignals(this, () => {
watcher.close(pattern);
});
this.$dispatcher.run();
}
}
$injector.register("usbLiveSyncService", LiveSyncService);