@aiot-toolkit/emulator 2.0.2-beta.13 → 2.0.2-beta.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,18 +35,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
- const shared_utils_1 = require("@aiot-toolkit/shared-utils");
38
+ const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
39
39
  const adbMiwt = __importStar(require("@miwt/adb"));
40
40
  const child_process_1 = require("child_process");
41
- const dayjs_1 = __importDefault(require("dayjs"));
42
- const fs_1 = __importDefault(require("fs"));
41
+ const readline_1 = __importDefault(require("readline"));
43
42
  const os_1 = __importDefault(require("os"));
44
43
  const path_1 = __importDefault(require("path"));
44
+ const Instance_1 = require("../typing/Instance");
45
45
  const common_1 = __importDefault(require("./common"));
46
+ const emulatorutil_1 = require("../emulatorutil");
46
47
  class GoldfishInstance extends common_1.default {
47
48
  constructor(params) {
48
49
  super(params);
49
- this.appRunDir = '/data/app';
50
+ this.appDir = '/data/app';
50
51
  this.emulatorStartedFlag = '(NSH)';
51
52
  }
52
53
  /**
@@ -62,26 +63,18 @@ class GoldfishInstance extends common_1.default {
62
63
  yield this.startGoldfish(options);
63
64
  const connected = yield this.isConnected();
64
65
  if (connected) {
65
- shared_utils_1.ColorConsole.log('### Emulator ### Goldfish emulator connected successfully');
66
+ ColorConsole_1.default.log('### Emulator ### Goldfish emulator connected successfully');
66
67
  if (this.isFirstStart && this.startOptions.serverPort) {
67
68
  yield this.createWebsockeServer();
68
69
  }
69
- // adb push快应用到模拟器的/data/app目录
70
- // aspect应用后续要考虑各种形状表盘的推包
71
- const buildedFilesPath = this.isRpk
72
- ? this.projectPath
73
- : this.isDistributedApp
74
- ? options.dist ||
75
- path_1.default.join(this.projectPath, './build', `${this.projectInfo.package}.watch`)
76
- : path_1.default.join(this.projectPath, './build');
77
- yield this.pushRpk(buildedFilesPath);
70
+ yield this.pushAndInstall();
78
71
  // 在模拟器中启动快应用
79
72
  this.startupQuickApp(options);
80
73
  this.isFirstStart = false;
81
74
  }
82
75
  else {
83
76
  const msg = '### Emulator ### Failed to connect emulator, please check whether the adb is normal';
84
- shared_utils_1.ColorConsole.throw(msg);
77
+ ColorConsole_1.default.throw(msg);
85
78
  throw new Error(msg);
86
79
  }
87
80
  });
@@ -99,12 +92,12 @@ class GoldfishInstance extends common_1.default {
99
92
  if (options.devtool) {
100
93
  vappCmd = `adb -s ${this.sn} shell vapp --jsdebugger=10.0.2.15:101 app/${packageName} &`;
101
94
  }
102
- shared_utils_1.ColorConsole.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
95
+ ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${vappCmd}`);
103
96
  // vapp进程会一直pending,不会退出。这里必须加stdio: 'ignore',否则快应用无法运行成功
104
97
  adbMiwt.execAdbCmdAsync(vappCmd, { stdio: 'ignore', encoding: 'utf-8' });
105
98
  }
106
99
  catch (e) {
107
- shared_utils_1.ColorConsole.error(`### Emulator ### Failed to startup quickapp: ${e.message}`);
100
+ ColorConsole_1.default.error(`### Emulator ### Failed to startup quickapp: ${e.message}`);
108
101
  }
109
102
  });
110
103
  }
@@ -119,110 +112,44 @@ class GoldfishInstance extends common_1.default {
119
112
  * @returns
120
113
  */
121
114
  startGoldfish(options) {
122
- var _a;
123
115
  return __awaiter(this, void 0, void 0, function* () {
124
- const { avdName, devtool, origin = 'terminal' } = options;
125
- const emulatorBin = this.getEmulatorBinPath();
126
- shared_utils_1.ColorConsole.log(`### Emulator ### emulator path: ${emulatorBin}`);
127
- const avdInfo = this.velaAvdCls.getVelaAvdInfo(avdName);
128
- const { avdArch, avdImagePath, customImagePath } = avdInfo;
129
- shared_utils_1.ColorConsole.log(`### Emulator ### adb port: ${options.adbPort}`);
130
- if (!avdImagePath) {
131
- return shared_utils_1.ColorConsole.throw(`### Emulator ### Unable to find vela image via avd`);
132
- }
133
- const nuttxBinPath = path_1.default.resolve(customImagePath || avdImagePath, 'nuttx');
134
- shared_utils_1.ColorConsole.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
135
- // 端口映射
136
- let portMappingStr = ``;
137
- if (devtool) {
138
- portMappingStr += `-network-user-mode-options hostfwd=tcp:127.0.0.1:${options.debugPort}-10.0.2.15:101`;
139
- }
140
- // 文件系统配置,第一次使用fatfs镜像挂载,后续使用adb push更新应用
141
- const systemImageBin = path_1.default.join(avdImagePath, 'system.img');
142
- const dataImageBin = path_1.default.join(avdImagePath, 'data.img');
143
- // 复制可写文件到AVD目录下(多模拟器实例时需要)
144
- const dataImageBinInAvd = path_1.default.join(this.avdHome, `${avdName}.avd`, 'data.img');
145
- if (!fs_1.default.existsSync(dataImageBinInAvd)) {
146
- // data.img不存在时直接copy
147
- fs_1.default.copyFileSync(dataImageBin, dataImageBinInAvd);
148
- }
149
- else {
150
- // data.img存在时,如果.export里的时间晚于avd里的时候,说明更新了镜像,需要重新copy
151
- const statsInAvd = fs_1.default.statSync(dataImageBinInAvd);
152
- const stats = fs_1.default.statSync(dataImageBin);
153
- if ((0, dayjs_1.default)(stats.mtime).isAfter(statsInAvd.mtime)) {
154
- fs_1.default.copyFileSync(dataImageBin, dataImageBinInAvd);
155
- }
156
- }
157
- // 复制可写文件到AVD目录下(多模拟器实例时需要)
158
- const systemImageBinInAvd = path_1.default.join(this.avdHome, `${avdName}.avd`, 'system.img');
159
- if (!fs_1.default.existsSync(systemImageBinInAvd)) {
160
- // data.img不存在时直接copy
161
- fs_1.default.copyFileSync(systemImageBin, systemImageBinInAvd);
162
- }
163
- else {
164
- // data.img存在时,如果.export里的时间晚于avd里的时候,说明更新了镜像,需要重新copy
165
- const statsInAvd = fs_1.default.statSync(systemImageBinInAvd);
166
- const stats = fs_1.default.statSync(systemImageBin);
167
- if ((0, dayjs_1.default)(stats.mtime).isAfter(statsInAvd.mtime)) {
168
- fs_1.default.copyFileSync(systemImageBin, systemImageBinInAvd);
169
- }
170
- }
171
- // 复制可写文件到AVD目录下(多模拟器实例时需要)
172
- // const nuttxBinInAvd = path.join(this.avdHome, `${avdName}.avd`, 'nuttx')
173
- // if (!fs.existsSync(nuttxBinInAvd)) {
174
- // // data.img不存在时直接copy
175
- // fs.copyFileSync(nuttxBinPath, nuttxBinInAvd)
176
- // } else {
177
- // // data.img存在时,如果.export里的时间晚于avd里的时候,说明更新了镜像,需要重新copy
178
- // const statsInAvd = fs.statSync(nuttxBinInAvd)
179
- // const stats = fs.statSync(nuttxBinPath)
180
- // if (dayjs(stats.mtime).isAfter(statsInAvd.mtime)) {
181
- // fs.copyFileSync(nuttxBinPath, nuttxBinInAvd)
182
- // }
183
- // }
184
- const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBinInAvd} \
185
- -device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
186
- -drive index=1,id=userdata,if=none,format=raw,file=${dataImageBinInAvd} \
187
- -device virtio-blk-device,bus=virtio-mmio-bus.1,drive=userdata \
188
- -device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
189
- // grpc配置
190
- let windowStr = '';
191
- let grpcStr = '';
192
- if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.grpcPort) {
193
- windowStr = '-qt-hide-window';
194
- grpcStr = ` -idle-grpc-timeout 300 -grpc ${this.startOptions.grpcPort}`;
195
- }
116
+ const { origin = Instance_1.IStartOrigin.Terminal } = options;
196
117
  // 启动模拟器的命令和参数
197
- const cmd = `${emulatorBin} -nuttx -avd ${avdName} -port ${options.adbPort} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${portMappingStr} ${windowStr} ${grpcStr} -qemu ${imageMountStr}`;
118
+ const cmd = emulatorutil_1.EmulatorCmd.createDevCmd(options, this.sdkHome, this.avdHome);
119
+ if (!cmd)
120
+ return;
198
121
  const spawnArgs = cmd.split(' ');
199
122
  const spawnBin = spawnArgs.shift();
200
- shared_utils_1.ColorConsole.log(`### Emulator ### Start CMD: ${cmd}`);
123
+ ColorConsole_1.default.log(`### Emulator ### Start CMD dev: ${cmd}`);
201
124
  return new Promise((resolve) => {
202
- var _a, _b, _c;
125
+ var _a, _b;
203
126
  this.goldfishProcess = (0, child_process_1.spawn)(spawnBin, spawnArgs, { stdio: 'pipe', shell: true });
204
- (_a = this.goldfishProcess.stderr) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
127
+ // 利用 readline 接口可解决子进程日志换行的问题
128
+ this.stdoutReadline = readline_1.default.createInterface({
129
+ input: this.goldfishProcess.stdout
130
+ });
131
+ this.stderrReadline = readline_1.default.createInterface({
132
+ input: this.goldfishProcess.stderr
133
+ });
134
+ (_a = this.stderrReadline) === null || _a === void 0 ? void 0 : _a.on('line', (data) => {
205
135
  const stderrCb = options.stderrCallback || console.log;
206
136
  stderrCb(data.toString());
207
137
  });
208
- if (origin === 'terminal') {
209
- process.stdout.pipe(this.goldfishProcess.stdin);
210
- (_b = this.goldfishProcess.stdout) === null || _b === void 0 ? void 0 : _b.pipe(process.stdout);
138
+ if (origin === Instance_1.IStartOrigin.Terminal) {
139
+ process.stdin.pipe(this.goldfishProcess.stdin);
211
140
  }
212
141
  this.goldfishProcess.on('exit', (code) => {
213
- shared_utils_1.ColorConsole.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
142
+ ColorConsole_1.default.error(`### Emulator ### Goldfish emulator exited with code ${code}`);
214
143
  if (options.exitCallback) {
215
144
  options.exitCallback(code);
216
145
  }
217
146
  });
218
- (_c = this.goldfishProcess.stdout) === null || _c === void 0 ? void 0 : _c.on('data', (data) => {
147
+ (_b = this.stdoutReadline) === null || _b === void 0 ? void 0 : _b.on('line', (data) => {
219
148
  const msg = data.toString();
220
- if (origin === 'ide') {
221
- const stdoutCb = options.stdoutCallback || console.log;
222
- stdoutCb(msg);
223
- }
224
- if (msg.includes(this.emulatorStartedFlag)) {
225
- shared_utils_1.ColorConsole.log(`### Emulator ### Goldfish emulator starts successfully`);
149
+ const stdoutCb = options.stdoutCallback || console.log;
150
+ stdoutCb(msg);
151
+ if (emulatorutil_1.EmulatorLog.devIsStart(msg)) {
152
+ ColorConsole_1.default.log(`### Emulator ### Goldfish emulator starts successfully`);
226
153
  resolve();
227
154
  }
228
155
  });
@@ -231,54 +158,61 @@ class GoldfishInstance extends common_1.default {
231
158
  }
232
159
  /**
233
160
  * 将目录通过adb push到模拟器中
234
- * @param sourceRoot
235
161
  */
236
- pushRpk(sourceRoot) {
162
+ pushAndInstall(rpkPath) {
237
163
  return __awaiter(this, void 0, void 0, function* () {
238
164
  const sn = this.sn;
239
165
  const { package: appPackageName } = this.projectInfo;
166
+ const sourceRoot = rpkPath || this.isRpk ? this.projectPath : path_1.default.join(this.projectPath, './build');
240
167
  // 获取最后一层目录,比如build
241
168
  const basename = path_1.default.basename(sourceRoot);
242
169
  if (os_1.default.platform() === 'win32' || this.projectPath.indexOf(' ') > 0) {
243
170
  // windows系统或者项目路径有空格:1. adb push目录;2. 在模拟器中使用mv命令重命名
244
171
  // 注意 sourceRoot 中可能会有空格
245
- yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push "${sourceRoot}" ${this.appRunDir}`);
246
- yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell mv ${this.appRunDir}/${basename} ${this.appRunDir}/${appPackageName}`);
172
+ const pushCmd = `adb -s ${sn} push "${sourceRoot}" ${this.appDir}`;
173
+ ColorConsole_1.default.info(`### Emulator ### push CMD: ${pushCmd}`);
174
+ yield adbMiwt.execAdbCmdAsync(pushCmd);
175
+ // 在 windows 上 mv 命令不能更新原有的文件,需要先删除
176
+ const rmCmd = `adb -s ${sn} shell rm -r ${this.appDir}/${appPackageName}`;
177
+ ColorConsole_1.default.info(`### Emulator ### mv CMD: ${rmCmd}`);
178
+ yield adbMiwt.execAdbCmdAsync(rmCmd);
179
+ const mvCmd = `adb -s ${sn} shell mv ${this.appDir}/${basename} ${this.appDir}/${appPackageName}`;
180
+ ColorConsole_1.default.info(`### Emulator ### mv CMD: ${mvCmd}`);
181
+ yield adbMiwt.execAdbCmdAsync(mvCmd);
247
182
  }
248
183
  else {
249
184
  // 支持通配符处理: 1. 模拟器中mkdir创建目录 2. adb push ./XXXXX/* /XXX
250
185
  const sourcePath = path_1.default.join(sourceRoot, './*');
251
- const mkdirCmd = `adb -s ${sn} shell mkdir ${this.appRunDir}/${appPackageName}`;
252
- shared_utils_1.ColorConsole.log(`### Emulator ### mkdir CMD: ${mkdirCmd}`);
186
+ const mkdirCmd = `adb -s ${sn} shell mkdir ${this.appDir}/${appPackageName}`;
187
+ ColorConsole_1.default.log(`### Emulator ### mkdir CMD: ${mkdirCmd}`);
253
188
  yield adbMiwt.execAdbCmdAsync(mkdirCmd);
254
- const pushCmd = `adb -s ${sn} push ${sourcePath} ${this.appRunDir}/${appPackageName}`;
255
- shared_utils_1.ColorConsole.log(`### Emulator ### pushCmd CMD: ${pushCmd}`);
189
+ const pushCmd = `adb -s ${sn} push ${sourcePath} ${this.appDir}/${appPackageName}`;
190
+ ColorConsole_1.default.log(`### Emulator ### pushCmd CMD: ${pushCmd}`);
256
191
  yield adbMiwt.execAdbCmdAsync(pushCmd);
257
192
  }
258
- shared_utils_1.ColorConsole.info(`### Emulator push to ${this.appRunDir}/${appPackageName} successfully`);
193
+ ColorConsole_1.default.info(`### Emulator push to ${this.appDir}/${appPackageName} successfully`);
194
+ });
195
+ }
196
+ /** 通过命令行启动时,在watich模式下监听websocket消息,
197
+ * 在文件发生变动时,重新启动应用
198
+ */
199
+ restart() {
200
+ return __awaiter(this, void 0, void 0, function* () {
201
+ this.pushAndReloadApp();
259
202
  });
260
203
  }
261
204
  /**
262
205
  * 重新推送,然后重启应用
263
206
  */
264
207
  pushAndReloadApp() {
265
- var _a;
266
208
  return __awaiter(this, void 0, void 0, function* () {
267
209
  try {
268
- // 1. 将整包重新推到miwear中(TODO:增量更新)
269
- // adb push快应用到模拟器的/data/app目录
270
- // aspect应用后续要考虑各种形状表盘的推包
271
- const buildedFilesPath = this.isRpk
272
- ? this.projectPath
273
- : this.isDistributedApp
274
- ? ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.dist) ||
275
- path_1.default.join(this.projectPath, './build', `${this.projectInfo.package}.watch`)
276
- : path_1.default.join(this.projectPath, './build');
277
- yield this.pushRpk(buildedFilesPath);
210
+ yield this.pushAndInstall();
211
+ yield this.reboot();
278
212
  this.reloadApp();
279
213
  }
280
214
  catch (e) {
281
- shared_utils_1.ColorConsole.error(`${e}`);
215
+ ColorConsole_1.default.error(`${e}`);
282
216
  }
283
217
  });
284
218
  }
@@ -289,13 +223,13 @@ class GoldfishInstance extends common_1.default {
289
223
  return __awaiter(this, void 0, void 0, function* () {
290
224
  const { package: appPackageName } = this.projectInfo;
291
225
  this.startupQuickApp(this.startOptions);
292
- shared_utils_1.ColorConsole.info(`### Emulator start ${appPackageName} successfully`);
226
+ ColorConsole_1.default.info(`### Emulator start ${appPackageName} successfully`);
293
227
  });
294
228
  }
295
229
  reboot() {
296
230
  return __awaiter(this, void 0, void 0, function* () {
297
231
  const rebootCmd = `adb -s ${this.sn} shell reboot`;
298
- shared_utils_1.ColorConsole.log(`### Emulator ### Excuting adb cmd: ${rebootCmd}`);
232
+ ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${rebootCmd}`);
299
233
  yield adbMiwt.execAdbCmdAsync(rebootCmd);
300
234
  return this.isConnected();
301
235
  });
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.findInstance = exports.PreInstance = exports.OldGoldfishInstance = exports.MiwearInstance = exports.GoldfishInstance = exports.CommonInstance = void 0;
7
- const shared_utils_1 = require("@aiot-toolkit/shared-utils");
7
+ const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
8
8
  const avd_1 = __importDefault(require("../avd"));
9
9
  const common_1 = __importDefault(require("./common"));
10
10
  exports.CommonInstance = common_1.default;
@@ -27,7 +27,7 @@ function findInstance(avdName, params) {
27
27
  const { sdkHome, avdHome } = params;
28
28
  const { avdImagePath } = new avd_1.default({ sdkHome, avdHome }).getVelaAvdInfo(avdName);
29
29
  if (!avdImagePath) {
30
- shared_utils_1.ColorConsole.throw(`### Emulator ### Unable to find vela image via avd`);
30
+ ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
31
31
  return;
32
32
  }
33
33
  if (avdImagePath.includes('vela-pre-4.0')) {
@@ -1,3 +1,5 @@
1
+ /// <reference types="node" />
2
+ import readline from 'readline';
1
3
  import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
2
4
  import CommonInstance from './common';
3
5
  /**
@@ -6,12 +8,11 @@ import CommonInstance from './common';
6
8
  */
7
9
  declare class MiwearInstance extends CommonInstance {
8
10
  private params;
9
- quickappStartedFlag: RegExp;
10
- private appPathInEmulator;
11
+ private appDir;
11
12
  private debugSocket?;
12
13
  private reconnectCount;
13
- emulatorStartedFlag: RegExp;
14
- installBol: boolean;
14
+ stdoutReadline: readline.Interface;
15
+ stderrReadline: readline.Interface;
15
16
  constructor(params: INewGoldfishInstanceParams);
16
17
  /**
17
18
  * 1. 启动模拟器
@@ -47,13 +48,9 @@ declare class MiwearInstance extends CommonInstance {
47
48
  * @param rpkPath rpk的绝对目录
48
49
  * @param targetDir 要将rpk放到模拟器的哪个目录下
49
50
  */
50
- installRpkToAppList(rpkPath: string, targetDir: string): Promise<void>;
51
+ pushAndInstall(rpkPath: string, targetDir: string): Promise<void>;
51
52
  /** 使用am start启动快应用 */
52
53
  launchQuickapp(): Promise<void>;
53
- /** 命令行模式下添加重复调用防止app无法拉起
54
- * 主要用将子进程的流输出到主进程后,由于流写入的过多可能会影响事件循环
55
- */
56
- pmInstallApp(maxRepeats: number, count?: number): void;
57
54
  /** 连接模拟器中的调试服务,创建debugSocket
58
55
  * 主要用于热更新时,通过debugSocket通知调试服务更新页面
59
56
  * 设置了重连机制,会重复连接8次
@@ -67,6 +64,10 @@ declare class MiwearInstance extends CommonInstance {
67
64
  handleUpdate(): Promise<void>;
68
65
  /** 热更新时push目录 */
69
66
  pushBuild(): Promise<void>;
67
+ /** 通过命令行启动时,在watich模式下监听websocket消息,
68
+ * 在文件发生变动时,重新启动应用
69
+ */
70
+ restart(): Promise<void>;
70
71
  /** 在模拟器中重启快应用(基于am命令,需要保证镜像中已经有am功能)
71
72
  * 1. 使用adb push将build文件下的内容推到/data/quickapp/app/${packageName}
72
73
  * 2. nsh中执行am stop命令退出快应用