@aiot-toolkit/emulator 2.0.2-beta.12 → 2.0.2-beta.14

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,53 +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
- yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} push ${sourceRoot} ${this.appRunDir}`);
245
- yield adbMiwt.execAdbCmdAsync(`adb -s ${sn} shell mv ${this.appRunDir}/${basename} ${this.appRunDir}/${appPackageName}`);
171
+ // 注意 sourceRoot 中可能会有空格
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);
246
182
  }
247
183
  else {
248
184
  // 支持通配符处理: 1. 模拟器中mkdir创建目录 2. adb push ./XXXXX/* /XXX
249
185
  const sourcePath = path_1.default.join(sourceRoot, './*');
250
- const mkdirCmd = `adb -s ${sn} shell mkdir ${this.appRunDir}/${appPackageName}`;
251
- 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}`);
252
188
  yield adbMiwt.execAdbCmdAsync(mkdirCmd);
253
- const pushCmd = `adb -s ${sn} push ${sourcePath} ${this.appRunDir}/${appPackageName}`;
254
- 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}`);
255
191
  yield adbMiwt.execAdbCmdAsync(pushCmd);
256
192
  }
257
- 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();
258
202
  });
259
203
  }
260
204
  /**
261
205
  * 重新推送,然后重启应用
262
206
  */
263
207
  pushAndReloadApp() {
264
- var _a;
265
208
  return __awaiter(this, void 0, void 0, function* () {
266
209
  try {
267
- // 1. 将整包重新推到miwear中(TODO:增量更新)
268
- // adb push快应用到模拟器的/data/app目录
269
- // aspect应用后续要考虑各种形状表盘的推包
270
- const buildedFilesPath = this.isRpk
271
- ? this.projectPath
272
- : this.isDistributedApp
273
- ? ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.dist) ||
274
- path_1.default.join(this.projectPath, './build', `${this.projectInfo.package}.watch`)
275
- : path_1.default.join(this.projectPath, './build');
276
- yield this.pushRpk(buildedFilesPath);
210
+ yield this.pushAndInstall();
211
+ yield this.reboot();
277
212
  this.reloadApp();
278
213
  }
279
214
  catch (e) {
280
- shared_utils_1.ColorConsole.error(`${e}`);
215
+ ColorConsole_1.default.error(`${e}`);
281
216
  }
282
217
  });
283
218
  }
@@ -288,13 +223,13 @@ class GoldfishInstance extends common_1.default {
288
223
  return __awaiter(this, void 0, void 0, function* () {
289
224
  const { package: appPackageName } = this.projectInfo;
290
225
  this.startupQuickApp(this.startOptions);
291
- shared_utils_1.ColorConsole.info(`### Emulator start ${appPackageName} successfully`);
226
+ ColorConsole_1.default.info(`### Emulator start ${appPackageName} successfully`);
292
227
  });
293
228
  }
294
229
  reboot() {
295
230
  return __awaiter(this, void 0, void 0, function* () {
296
231
  const rebootCmd = `adb -s ${this.sn} shell reboot`;
297
- shared_utils_1.ColorConsole.log(`### Emulator ### Excuting adb cmd: ${rebootCmd}`);
232
+ ColorConsole_1.default.log(`### Emulator ### Excuting adb cmd: ${rebootCmd}`);
298
233
  yield adbMiwt.execAdbCmdAsync(rebootCmd);
299
234
  return this.isConnected();
300
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,11 +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
+ stdoutReadline: readline.Interface;
15
+ stderrReadline: readline.Interface;
14
16
  constructor(params: INewGoldfishInstanceParams);
15
17
  /**
16
18
  * 1. 启动模拟器
@@ -46,7 +48,7 @@ declare class MiwearInstance extends CommonInstance {
46
48
  * @param rpkPath rpk的绝对目录
47
49
  * @param targetDir 要将rpk放到模拟器的哪个目录下
48
50
  */
49
- installRpkToAppList(rpkPath: string, targetDir: string): Promise<void>;
51
+ pushAndInstall(rpkPath: string, targetDir: string): Promise<void>;
50
52
  /** 使用am start启动快应用 */
51
53
  launchQuickapp(): Promise<void>;
52
54
  /** 连接模拟器中的调试服务,创建debugSocket
@@ -62,6 +64,10 @@ declare class MiwearInstance extends CommonInstance {
62
64
  handleUpdate(): Promise<void>;
63
65
  /** 热更新时push目录 */
64
66
  pushBuild(): Promise<void>;
67
+ /** 通过命令行启动时,在watich模式下监听websocket消息,
68
+ * 在文件发生变动时,重新启动应用
69
+ */
70
+ restart(): Promise<void>;
65
71
  /** 在模拟器中重启快应用(基于am命令,需要保证镜像中已经有am功能)
66
72
  * 1. 使用adb push将build文件下的内容推到/data/quickapp/app/${packageName}
67
73
  * 2. nsh中执行am stop命令退出快应用