@aiot-toolkit/emulator 2.0.2 → 2.0.3-beta.10
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.
- package/README.md +133 -8
- package/lib/emulatorutil/EmulatorLog.js +22 -18
- package/lib/emulatorutil/constants.d.ts +18 -5
- package/lib/emulatorutil/constants.js +94 -53
- package/lib/emulatorutil/index.d.ts +3 -2
- package/lib/emulatorutil/index.js +38 -8
- package/lib/emulatorutil/running.d.ts +24 -0
- package/lib/emulatorutil/running.js +108 -0
- package/lib/emulatorutil/skinLayoutParser.d.ts +14 -0
- package/lib/emulatorutil/skinLayoutParser.js +111 -0
- package/lib/index.d.ts +5 -5
- package/lib/index.js +76 -26
- package/lib/instance/common.d.ts +38 -39
- package/lib/instance/common.js +141 -236
- package/lib/instance/dev.d.ts +7 -42
- package/lib/instance/dev.js +54 -235
- package/lib/instance/index.d.ts +6 -5
- package/lib/instance/index.js +51 -35
- package/lib/instance/miwear.d.ts +14 -75
- package/lib/instance/miwear.js +93 -370
- package/lib/instance/pre.d.ts +11 -3
- package/lib/instance/pre.js +55 -93
- package/lib/instance/pre5.d.ts +11 -0
- package/lib/instance/pre5.js +38 -0
- package/lib/static/avdConfigIni.json +5 -5
- package/lib/typing/Instance.d.ts +30 -15
- package/lib/typing/Instance.js +13 -6
- package/lib/typing/Vvd.d.ts +105 -0
- package/lib/typing/Vvd.js +31 -0
- package/lib/utils/file.d.ts +0 -0
- package/lib/utils/file.js +1 -0
- package/lib/utils/index.js +86 -100
- package/lib/vvd/index.d.ts +107 -0
- package/lib/vvd/index.js +698 -0
- package/lib/vvd/logcat.d.ts +16 -0
- package/lib/vvd/logcat.js +67 -0
- package/package.json +9 -8
- package/lib/avd/index.d.ts +0 -28
- package/lib/avd/index.js +0 -173
- package/lib/emulatorutil/EmulatorCmd.d.ts +0 -9
- package/lib/emulatorutil/EmulatorCmd.js +0 -226
- package/lib/instance/preDev.d.ts +0 -53
- package/lib/instance/preDev.js +0 -249
- package/lib/typing/Avd.d.ts +0 -23
- package/lib/typing/Avd.js +0 -8
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import readline from 'readline';
|
|
2
|
+
import { ChildProcessWithoutNullStreams } from 'child_process';
|
|
3
|
+
import { EmulatorReadlines } from '../typing/Instance';
|
|
4
|
+
export declare function creatLogcat(sn: string, onStdout?: (msg: string) => void, onErrout?: (msg: string) => void, p?: ChildProcessWithoutNullStreams, rls?: EmulatorReadlines): {
|
|
5
|
+
logcatProcess: ChildProcessWithoutNullStreams;
|
|
6
|
+
onStdout: (msg: string) => void;
|
|
7
|
+
onErrout: (msg: string) => void;
|
|
8
|
+
stdoutReadline: readline.Interface;
|
|
9
|
+
stderrReadline: readline.Interface;
|
|
10
|
+
dispose(): void;
|
|
11
|
+
};
|
|
12
|
+
export declare function attachReadline(p: ChildProcessWithoutNullStreams, onStdout: any, onErrout: any): {
|
|
13
|
+
stdoutReadline: readline.Interface;
|
|
14
|
+
stderrReadline: readline.Interface;
|
|
15
|
+
dispose: () => void;
|
|
16
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.attachReadline = attachReadline;
|
|
7
|
+
exports.creatLogcat = creatLogcat;
|
|
8
|
+
var _readline = _interopRequireDefault(require("readline"));
|
|
9
|
+
var _adb = require("@miwt/adb");
|
|
10
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
function creatLogcat(sn) {
|
|
12
|
+
let onStdout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : console.log;
|
|
13
|
+
let onErrout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : console.log;
|
|
14
|
+
let p = arguments.length > 3 ? arguments[3] : undefined;
|
|
15
|
+
let rls = arguments.length > 4 ? arguments[4] : undefined;
|
|
16
|
+
const logcatProcess = p || (0, _adb.spawnAdbCmd)('adb', ['-s', sn, 'logcat']);
|
|
17
|
+
const readlines = rls || attachReadline(logcatProcess, onStdout, onErrout);
|
|
18
|
+
return {
|
|
19
|
+
...readlines,
|
|
20
|
+
logcatProcess,
|
|
21
|
+
onStdout,
|
|
22
|
+
onErrout
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
function attachReadline(p, onStdout, onErrout) {
|
|
26
|
+
let stdoutReadline;
|
|
27
|
+
let stderrReadline;
|
|
28
|
+
|
|
29
|
+
// 利用 readline 接口可解决子进程日志换行的问题
|
|
30
|
+
if (p.stdout) {
|
|
31
|
+
stdoutReadline = _readline.default.createInterface({
|
|
32
|
+
input: p.stdout
|
|
33
|
+
});
|
|
34
|
+
stdoutReadline.on('line', str => {
|
|
35
|
+
onStdout(str);
|
|
36
|
+
});
|
|
37
|
+
p.stdout.on('close', () => {
|
|
38
|
+
stdoutReadline?.close();
|
|
39
|
+
stdoutReadline = undefined;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (p.stderr) {
|
|
43
|
+
stderrReadline = _readline.default.createInterface({
|
|
44
|
+
input: p.stderr
|
|
45
|
+
});
|
|
46
|
+
stderrReadline.on('line', str => {
|
|
47
|
+
onErrout(str);
|
|
48
|
+
});
|
|
49
|
+
p.stderr.on('close', () => {
|
|
50
|
+
stderrReadline?.close();
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function dispose() {
|
|
54
|
+
stdoutReadline?.close();
|
|
55
|
+
stderrReadline?.close();
|
|
56
|
+
stdoutReadline = undefined;
|
|
57
|
+
stderrReadline = undefined;
|
|
58
|
+
}
|
|
59
|
+
p.on('exit', () => {
|
|
60
|
+
dispose();
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
stdoutReadline,
|
|
64
|
+
stderrReadline,
|
|
65
|
+
dispose
|
|
66
|
+
};
|
|
67
|
+
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiot-toolkit/emulator",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3-beta.10",
|
|
4
4
|
"description": "vela emulator tool.",
|
|
5
5
|
"homepage": "",
|
|
6
6
|
"license": "ISC",
|
|
7
7
|
"main": "lib/index.js",
|
|
8
|
+
"types": "lib/index.d.ts",
|
|
8
9
|
"directories": {
|
|
9
10
|
"lib": "lib",
|
|
10
11
|
"test": "__tests__"
|
|
@@ -35,20 +36,20 @@
|
|
|
35
36
|
"emulator"
|
|
36
37
|
],
|
|
37
38
|
"dependencies": {
|
|
38
|
-
"@aiot-toolkit/
|
|
39
|
-
"@aiot-toolkit/shared-utils": "2.0.2",
|
|
39
|
+
"@aiot-toolkit/shared-utils": "2.0.3-beta.10",
|
|
40
40
|
"@miwt/adb": "^0.9.0",
|
|
41
|
+
"adm-zip": "^0.5.16",
|
|
41
42
|
"dayjs": "^1.11.12",
|
|
42
43
|
"find-process": "^1.4.7",
|
|
43
|
-
"
|
|
44
|
+
"get-port": "^7.1.0",
|
|
44
45
|
"ini": "^4.1.3",
|
|
46
|
+
"ipull": "^3.6.2",
|
|
45
47
|
"portfinder": "^1.0.32",
|
|
46
|
-
"semver": "^7.6.3"
|
|
47
|
-
"ws": "^8.18.0"
|
|
48
|
+
"semver": "^7.6.3"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
|
-
"@types/
|
|
51
|
+
"@types/adm-zip": "^0.5.5",
|
|
51
52
|
"@types/ini": "^4.1.1"
|
|
52
53
|
},
|
|
53
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "e591934b19bc474453ce11b63f0c8bb0d8eb8bd9"
|
|
54
55
|
}
|
package/lib/avd/index.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { IAvdParams, IAvdResourcePaths } from '../typing/Avd';
|
|
2
|
-
declare class VelaAvdCls {
|
|
3
|
-
private avdHome;
|
|
4
|
-
private sdkHome;
|
|
5
|
-
constructor(avdResourcePaths: IAvdResourcePaths);
|
|
6
|
-
/**
|
|
7
|
-
* 创建Vela端的AVD,统一保存在.android目录下
|
|
8
|
-
* 1. 创建.android/advancedFeatures.ini文件
|
|
9
|
-
* 2. 创建.android/${avdName}.ini文件
|
|
10
|
-
* 3. 创建.android/${avdName}.avd/config.ini文件
|
|
11
|
-
* @param avdParams AVD参数,宽高、绑定的镜像路径等
|
|
12
|
-
* @returns
|
|
13
|
-
*/
|
|
14
|
-
createVelaAvd(avdParams: IAvdParams): boolean;
|
|
15
|
-
/** 根据AVD名字获取模拟器的详细信息 */
|
|
16
|
-
getVelaAvdInfo(avdName: string): IAvdParams;
|
|
17
|
-
/** 根据名字删除AVD */
|
|
18
|
-
deleteVelaAvd(avdName: string): boolean;
|
|
19
|
-
/** 获取已经创建的模拟器列表 */
|
|
20
|
-
getVelaAvdList(): IAvdParams[];
|
|
21
|
-
/** 获取模拟器皮肤列表 */
|
|
22
|
-
getVelaSkinList(): string[];
|
|
23
|
-
/** 自定义模拟器的镜像目录 */
|
|
24
|
-
customImageDir(avdName: string, target: string): void;
|
|
25
|
-
/** 重置自定义的镜像目录 */
|
|
26
|
-
resetImageDir(avdName: string): void;
|
|
27
|
-
}
|
|
28
|
-
export default VelaAvdCls;
|
package/lib/avd/index.js
DELETED
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
7
|
-
const fs_1 = __importDefault(require("fs"));
|
|
8
|
-
const os_1 = __importDefault(require("os"));
|
|
9
|
-
const path_1 = __importDefault(require("path"));
|
|
10
|
-
const ini_1 = require("ini");
|
|
11
|
-
const constants_1 = require("../emulatorutil/constants");
|
|
12
|
-
const Avd_1 = require("../typing/Avd");
|
|
13
|
-
const EAvdParamsToIni = {
|
|
14
|
-
arm: {
|
|
15
|
-
abiType: 'armeabi-v7a'
|
|
16
|
-
},
|
|
17
|
-
arm64: {
|
|
18
|
-
abiType: 'arm64-v8a'
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
class VelaAvdCls {
|
|
22
|
-
constructor(avdResourcePaths) {
|
|
23
|
-
const { avdHome, sdkHome } = avdResourcePaths;
|
|
24
|
-
this.avdHome = avdHome || constants_1.defaultAvdHome;
|
|
25
|
-
this.sdkHome = sdkHome || constants_1.defaultSDKHome;
|
|
26
|
-
if (!fs_1.default.existsSync(this.avdHome)) {
|
|
27
|
-
fs_1.default.mkdirSync(this.avdHome, { recursive: true });
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* 创建Vela端的AVD,统一保存在.android目录下
|
|
32
|
-
* 1. 创建.android/advancedFeatures.ini文件
|
|
33
|
-
* 2. 创建.android/${avdName}.ini文件
|
|
34
|
-
* 3. 创建.android/${avdName}.avd/config.ini文件
|
|
35
|
-
* @param avdParams AVD参数,宽高、绑定的镜像路径等
|
|
36
|
-
* @returns
|
|
37
|
-
*/
|
|
38
|
-
createVelaAvd(avdParams) {
|
|
39
|
-
// 在.android下创建advancedFeatures.ini文件
|
|
40
|
-
const advancedFeaturesIni = path_1.default.resolve(os_1.default.homedir(), '.android/advancedFeatures.ini');
|
|
41
|
-
if (!fs_1.default.existsSync(advancedFeaturesIni)) {
|
|
42
|
-
const iniSourcePath = path_1.default.join(__dirname, '../static/advancedFeatures.ini');
|
|
43
|
-
fs_1.default.copyFileSync(iniSourcePath, advancedFeaturesIni);
|
|
44
|
-
}
|
|
45
|
-
const { avdName, avdArch, avdWidth, avdHeight, avdSkin, avdImagePath = constants_1.defaultImageHome } = avdParams;
|
|
46
|
-
const avdDir = path_1.default.resolve(this.avdHome, `${avdName}.avd`);
|
|
47
|
-
const avdIni = path_1.default.resolve(this.avdHome, `${avdName}.ini`);
|
|
48
|
-
const avdConfigIni = path_1.default.resolve(avdDir, 'config.ini');
|
|
49
|
-
const nuttxAvdIniContent = `path=${avdDir}\npath.rel=avd${path_1.default.sep}${avdName}.avd`;
|
|
50
|
-
const abiType = EAvdParamsToIni[avdArch]['abiType'];
|
|
51
|
-
const configIniJson = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '../static/avdConfigIni.json'), 'utf-8'));
|
|
52
|
-
configIniJson['AvdId'] = avdName;
|
|
53
|
-
configIniJson['abi.type'] = abiType;
|
|
54
|
-
configIniJson['avd.ini.displayname'] = avdName;
|
|
55
|
-
configIniJson['hw.cpu.arch'] = avdArch;
|
|
56
|
-
if (avdSkin) {
|
|
57
|
-
delete configIniJson['hw.lcd.height'];
|
|
58
|
-
delete configIniJson['hw.lcd.width'];
|
|
59
|
-
configIniJson['skin.dynamic'] = 'yes';
|
|
60
|
-
configIniJson['skin.name'] = avdSkin;
|
|
61
|
-
configIniJson['skin.path'] = path_1.default.resolve(this.sdkHome, 'skins', avdSkin);
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
configIniJson['hw.lcd.height'] = avdHeight;
|
|
65
|
-
configIniJson['hw.lcd.width'] = avdWidth;
|
|
66
|
-
configIniJson['skin.dynamic'] = 'no';
|
|
67
|
-
delete configIniJson['skin.name'];
|
|
68
|
-
delete configIniJson['skin.path'];
|
|
69
|
-
}
|
|
70
|
-
configIniJson['image.sysdir.1'] = avdImagePath;
|
|
71
|
-
try {
|
|
72
|
-
fs_1.default.mkdirSync(avdDir, { recursive: true });
|
|
73
|
-
// 写入Vela_Virtual_Device.ini文件
|
|
74
|
-
fs_1.default.writeFileSync(avdIni, nuttxAvdIniContent);
|
|
75
|
-
// 写入Vela_Virtual_Device.avd/config.ini文件
|
|
76
|
-
fs_1.default.writeFileSync(avdConfigIni, (0, ini_1.stringify)(configIniJson));
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
catch (e) {
|
|
80
|
-
throw `createVelaAvd: ${e.message}`;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
/** 根据AVD名字获取模拟器的详细信息 */
|
|
84
|
-
getVelaAvdInfo(avdName) {
|
|
85
|
-
const avdInfo = {
|
|
86
|
-
avdName,
|
|
87
|
-
avdArch: Avd_1.IAvdArchType.arm,
|
|
88
|
-
avdHeight: '',
|
|
89
|
-
avdWidth: '',
|
|
90
|
-
avdSkin: '',
|
|
91
|
-
avdImagePath: ''
|
|
92
|
-
};
|
|
93
|
-
const currAvdDir = path_1.default.resolve(this.avdHome, `${avdName}.avd`);
|
|
94
|
-
const configIni = path_1.default.resolve(currAvdDir, 'config.ini');
|
|
95
|
-
try {
|
|
96
|
-
const contents = fs_1.default.readFileSync(configIni, 'utf-8');
|
|
97
|
-
const config = (0, ini_1.parse)(contents);
|
|
98
|
-
avdInfo.avdArch = config['hw.cpu.arch'];
|
|
99
|
-
avdInfo.avdHeight = config['hw.lcd.height'];
|
|
100
|
-
avdInfo.avdWidth = config['hw.lcd.width'];
|
|
101
|
-
avdInfo.avdSkin = config['skin.name'];
|
|
102
|
-
avdInfo.avdImagePath = config['image.sysdir.1'];
|
|
103
|
-
avdInfo.customImagePath = config['image.sysdir.2'];
|
|
104
|
-
return avdInfo;
|
|
105
|
-
}
|
|
106
|
-
catch (err) {
|
|
107
|
-
ColorConsole_1.default.log(`getVelaAvdInfo: ${err.message}`);
|
|
108
|
-
return avdInfo;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
/** 根据名字删除AVD */
|
|
112
|
-
deleteVelaAvd(avdName) {
|
|
113
|
-
const avdDir = path_1.default.resolve(this.avdHome, `${avdName}.avd`);
|
|
114
|
-
const avdIni = path_1.default.resolve(this.avdHome, `${avdName}.ini`);
|
|
115
|
-
try {
|
|
116
|
-
fs_1.default.rmSync(avdDir, { recursive: true, force: true });
|
|
117
|
-
fs_1.default.rmSync(avdIni, { force: true });
|
|
118
|
-
return true;
|
|
119
|
-
}
|
|
120
|
-
catch (e) {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/** 获取已经创建的模拟器列表 */
|
|
125
|
-
getVelaAvdList() {
|
|
126
|
-
const avdList = [];
|
|
127
|
-
const files = fs_1.default.readdirSync(this.avdHome);
|
|
128
|
-
const regex = /^(Vela[\d\D]*)\.avd$/;
|
|
129
|
-
for (const fileName of files) {
|
|
130
|
-
const matcher = fileName.match(regex);
|
|
131
|
-
if (matcher) {
|
|
132
|
-
const avdName = matcher[1];
|
|
133
|
-
const avdInfo = this.getVelaAvdInfo(avdName);
|
|
134
|
-
avdList.push(avdInfo);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return avdList;
|
|
138
|
-
}
|
|
139
|
-
/** 获取模拟器皮肤列表 */
|
|
140
|
-
getVelaSkinList() {
|
|
141
|
-
try {
|
|
142
|
-
const skinList = [];
|
|
143
|
-
const skinHome = path_1.default.resolve(this.sdkHome, 'skins');
|
|
144
|
-
let files = fs_1.default.readdirSync(skinHome);
|
|
145
|
-
for (const fileName of files) {
|
|
146
|
-
!fileName.startsWith('.') && skinList.push(fileName);
|
|
147
|
-
}
|
|
148
|
-
return skinList;
|
|
149
|
-
}
|
|
150
|
-
catch (e) {
|
|
151
|
-
return [];
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
/** 自定义模拟器的镜像目录 */
|
|
155
|
-
customImageDir(avdName, target) {
|
|
156
|
-
const currAvdDir = path_1.default.resolve(this.avdHome, `${avdName}.avd`);
|
|
157
|
-
const configIni = path_1.default.resolve(currAvdDir, 'config.ini');
|
|
158
|
-
const contents = fs_1.default.readFileSync(configIni, 'utf-8');
|
|
159
|
-
const config = (0, ini_1.parse)(contents);
|
|
160
|
-
config['image.sysdir.2'] = target;
|
|
161
|
-
fs_1.default.writeFileSync(configIni, (0, ini_1.stringify)(config));
|
|
162
|
-
}
|
|
163
|
-
/** 重置自定义的镜像目录 */
|
|
164
|
-
resetImageDir(avdName) {
|
|
165
|
-
const currAvdDir = path_1.default.resolve(this.avdHome, `${avdName}.avd`);
|
|
166
|
-
const configIni = path_1.default.resolve(currAvdDir, 'config.ini');
|
|
167
|
-
const contents = fs_1.default.readFileSync(configIni, 'utf-8');
|
|
168
|
-
const config = (0, ini_1.parse)(contents);
|
|
169
|
-
delete config['image.sysdir.2'];
|
|
170
|
-
fs_1.default.writeFileSync(configIni, (0, ini_1.stringify)(config));
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
exports.default = VelaAvdCls;
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { IStartOptions } from '../typing/Instance';
|
|
2
|
-
declare class EmulatorCmd {
|
|
3
|
-
static startOptions: IStartOptions | undefined;
|
|
4
|
-
static createMiwerCmd(options: IStartOptions, sdkHome: string, avdHome: string): string | undefined;
|
|
5
|
-
static createDevCmd(options: IStartOptions, sdkHome: string, avdHome: string): string | undefined;
|
|
6
|
-
static createPreCmd(options: IStartOptions, sdkHome: string, avdHome: string): string[] | undefined;
|
|
7
|
-
static getEmulatorBinPath(sdkHome: string): string;
|
|
8
|
-
}
|
|
9
|
-
export default EmulatorCmd;
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const ColorConsole_1 = __importDefault(require("@aiot-toolkit/shared-utils/lib/ColorConsole"));
|
|
7
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
const avd_1 = __importDefault(require("../avd"));
|
|
10
|
-
const utils_1 = require("../utils");
|
|
11
|
-
const os_1 = __importDefault(require("os"));
|
|
12
|
-
const dayjs_1 = __importDefault(require("dayjs"));
|
|
13
|
-
const constants_1 = require("./constants");
|
|
14
|
-
class EmulatorCmd {
|
|
15
|
-
static createMiwerCmd(options, sdkHome, avdHome) {
|
|
16
|
-
var _a;
|
|
17
|
-
this.startOptions = options;
|
|
18
|
-
const { avdName, devtool } = options;
|
|
19
|
-
// 获取emulator bin的绝对路径
|
|
20
|
-
const emulatorBin = this.getEmulatorBinPath(sdkHome);
|
|
21
|
-
ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
|
|
22
|
-
// 获取vela镜像的绝对路径
|
|
23
|
-
const velaAvdCls = new avd_1.default({
|
|
24
|
-
sdkHome: sdkHome,
|
|
25
|
-
avdHome: avdHome
|
|
26
|
-
});
|
|
27
|
-
const avdInfo = velaAvdCls.getVelaAvdInfo(avdName);
|
|
28
|
-
const { avdArch, avdImagePath, customImagePath } = avdInfo;
|
|
29
|
-
ColorConsole_1.default.log(`### Emulator ### adb port: ${options.adbPort}`);
|
|
30
|
-
if (!avdImagePath) {
|
|
31
|
-
ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
32
|
-
return undefined;
|
|
33
|
-
}
|
|
34
|
-
const nuttxBinPath = path_1.default.resolve(customImagePath || avdImagePath, 'nuttx');
|
|
35
|
-
ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
|
|
36
|
-
// 端口映射
|
|
37
|
-
let portMappingStr = ``;
|
|
38
|
-
if (devtool) {
|
|
39
|
-
portMappingStr += `-network-user-mode-options hostfwd=tcp:127.0.0.1:${options.debugPort}-10.0.2.15:101`;
|
|
40
|
-
}
|
|
41
|
-
// 设备挂载节点
|
|
42
|
-
const systemImageBin = path_1.default.resolve(avdImagePath, 'vela_resource.bin'); // 只读
|
|
43
|
-
const dataImageBin = path_1.default.resolve(avdImagePath, 'vela_data.bin'); // 可读可写
|
|
44
|
-
const coreBin = path_1.default.resolve(avdImagePath, 'coredump.core'); // 只读
|
|
45
|
-
// 复制可写文件到AVD目录下(多模拟器实例时需要)
|
|
46
|
-
const dataImageBinInAvd = path_1.default.join(avdHome, `${avdName}.avd`, 'vela_data.bin');
|
|
47
|
-
if (!fs_extra_1.default.existsSync(dataImageBinInAvd)) {
|
|
48
|
-
// vela_data.bin不存在时直接copy
|
|
49
|
-
fs_extra_1.default.copyFileSync(dataImageBin, dataImageBinInAvd);
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
// vela_data.bin存在时,如果.export里的时间晚于avd里的时候,说明更新了镜像,需要重新copy
|
|
53
|
-
const statsInAvd = fs_extra_1.default.statSync(dataImageBinInAvd);
|
|
54
|
-
const stats = fs_extra_1.default.statSync(dataImageBin);
|
|
55
|
-
if ((0, dayjs_1.default)(stats.mtime).isAfter(statsInAvd.mtime)) {
|
|
56
|
-
fs_extra_1.default.copyFileSync(dataImageBin, dataImageBinInAvd);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
// 挂载节点配置,只读文件加入read-only标识
|
|
60
|
-
const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBin},read-only \
|
|
61
|
-
-device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
|
|
62
|
-
-drive index=1,id=userdata,if=none,format=raw,file=${dataImageBinInAvd} \
|
|
63
|
-
-device virtio-blk-device,bus=virtio-mmio-bus.1,drive=userdata \
|
|
64
|
-
-drive index=2,id=vendor,if=none,format=raw,file=${coreBin},read-only \
|
|
65
|
-
-device virtio-blk-device,bus=virtio-mmio-bus.4,drive=vendor \
|
|
66
|
-
-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
|
|
67
|
-
// grpc配置
|
|
68
|
-
let windowStr = '';
|
|
69
|
-
let grpcStr = '';
|
|
70
|
-
if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.grpcPort) {
|
|
71
|
-
windowStr = '-qt-hide-window';
|
|
72
|
-
grpcStr = ` -idle-grpc-timeout 300 -grpc ${this.startOptions.grpcPort}`;
|
|
73
|
-
}
|
|
74
|
-
// 启动模拟器的命令和参数
|
|
75
|
-
const cmd = `${emulatorBin} -nuttx -avd ${avdName} -port ${options.adbPort} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${portMappingStr} ${windowStr} ${grpcStr} -qemu ${imageMountStr}`;
|
|
76
|
-
return cmd;
|
|
77
|
-
}
|
|
78
|
-
static createDevCmd(options, sdkHome, avdHome) {
|
|
79
|
-
var _a;
|
|
80
|
-
this.startOptions = options;
|
|
81
|
-
const { avdName, devtool } = options;
|
|
82
|
-
const emulatorBin = this.getEmulatorBinPath(sdkHome);
|
|
83
|
-
ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
|
|
84
|
-
const velaAvdCls = new avd_1.default({
|
|
85
|
-
sdkHome: sdkHome,
|
|
86
|
-
avdHome: avdHome
|
|
87
|
-
});
|
|
88
|
-
const avdInfo = velaAvdCls.getVelaAvdInfo(avdName);
|
|
89
|
-
const { avdArch, avdImagePath, customImagePath } = avdInfo;
|
|
90
|
-
ColorConsole_1.default.log(`### Emulator ### adb port: ${options.adbPort}`);
|
|
91
|
-
if (!avdImagePath) {
|
|
92
|
-
ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
93
|
-
return undefined;
|
|
94
|
-
}
|
|
95
|
-
const nuttxBinPath = path_1.default.resolve(customImagePath || avdImagePath, 'nuttx');
|
|
96
|
-
ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
|
|
97
|
-
// 端口映射
|
|
98
|
-
let portMappingStr = ``;
|
|
99
|
-
if (devtool) {
|
|
100
|
-
portMappingStr += `-network-user-mode-options hostfwd=tcp:127.0.0.1:${options.debugPort}-10.0.2.15:101`;
|
|
101
|
-
}
|
|
102
|
-
// 文件系统配置,第一次使用fatfs镜像挂载,后续使用adb push更新应用
|
|
103
|
-
const systemImageBin = path_1.default.join(avdImagePath, 'system.img');
|
|
104
|
-
const dataImageBin = path_1.default.join(avdImagePath, 'data.img');
|
|
105
|
-
// 复制可写文件到AVD目录下(多模拟器实例时需要)
|
|
106
|
-
const dataImageBinInAvd = path_1.default.join(avdHome, `${avdName}.avd`, 'data.img');
|
|
107
|
-
if (!fs_extra_1.default.existsSync(dataImageBinInAvd)) {
|
|
108
|
-
// data.img不存在时直接copy
|
|
109
|
-
fs_extra_1.default.copyFileSync(dataImageBin, dataImageBinInAvd);
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
// data.img存在时,如果.export里的时间晚于avd里的时候,说明更新了镜像,需要重新copy
|
|
113
|
-
const statsInAvd = fs_extra_1.default.statSync(dataImageBinInAvd);
|
|
114
|
-
const stats = fs_extra_1.default.statSync(dataImageBin);
|
|
115
|
-
if ((0, dayjs_1.default)(stats.mtime).isAfter(statsInAvd.mtime)) {
|
|
116
|
-
fs_extra_1.default.copyFileSync(dataImageBin, dataImageBinInAvd);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
// 复制可写文件到AVD目录下(多模拟器实例时需要)
|
|
120
|
-
const systemImageBinInAvd = path_1.default.join(avdHome, `${avdName}.avd`, 'system.img');
|
|
121
|
-
if (!fs_extra_1.default.existsSync(systemImageBinInAvd)) {
|
|
122
|
-
// data.img不存在时直接copy
|
|
123
|
-
fs_extra_1.default.copyFileSync(systemImageBin, systemImageBinInAvd);
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
// data.img存在时,如果.export里的时间晚于avd里的时候,说明更新了镜像,需要重新copy
|
|
127
|
-
const statsInAvd = fs_extra_1.default.statSync(systemImageBinInAvd);
|
|
128
|
-
const stats = fs_extra_1.default.statSync(systemImageBin);
|
|
129
|
-
if ((0, dayjs_1.default)(stats.mtime).isAfter(statsInAvd.mtime)) {
|
|
130
|
-
fs_extra_1.default.copyFileSync(systemImageBin, systemImageBinInAvd);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
// 复制可写文件到AVD目录下(多模拟器实例时需要)
|
|
134
|
-
// const nuttxBinInAvd = path.join(this.avdHome, `${avdName}.avd`, 'nuttx')
|
|
135
|
-
// if (!fs.existsSync(nuttxBinInAvd)) {
|
|
136
|
-
// // data.img不存在时直接copy
|
|
137
|
-
// fs.copyFileSync(nuttxBinPath, nuttxBinInAvd)
|
|
138
|
-
// } else {
|
|
139
|
-
// // data.img存在时,如果.export里的时间晚于avd里的时候,说明更新了镜像,需要重新copy
|
|
140
|
-
// const statsInAvd = fs.statSync(nuttxBinInAvd)
|
|
141
|
-
// const stats = fs.statSync(nuttxBinPath)
|
|
142
|
-
// if (dayjs(stats.mtime).isAfter(statsInAvd.mtime)) {
|
|
143
|
-
// fs.copyFileSync(nuttxBinPath, nuttxBinInAvd)
|
|
144
|
-
// }
|
|
145
|
-
// }
|
|
146
|
-
const imageMountStr = `-drive index=0,id=system,if=none,format=raw,file=${systemImageBinInAvd} \
|
|
147
|
-
-device virtio-blk-device,bus=virtio-mmio-bus.0,drive=system \
|
|
148
|
-
-drive index=1,id=userdata,if=none,format=raw,file=${dataImageBinInAvd} \
|
|
149
|
-
-device virtio-blk-device,bus=virtio-mmio-bus.1,drive=userdata \
|
|
150
|
-
-device virtio-snd,bus=virtio-mmio-bus.2 -allow-host-audio -semihosting`;
|
|
151
|
-
// grpc配置
|
|
152
|
-
let windowStr = '';
|
|
153
|
-
let grpcStr = '';
|
|
154
|
-
if ((_a = this.startOptions) === null || _a === void 0 ? void 0 : _a.grpcPort) {
|
|
155
|
-
windowStr = '-qt-hide-window';
|
|
156
|
-
grpcStr = ` -idle-grpc-timeout 300 -grpc ${this.startOptions.grpcPort}`;
|
|
157
|
-
}
|
|
158
|
-
// 启动模拟器的命令和参数
|
|
159
|
-
const cmd = `${emulatorBin} -nuttx -avd ${avdName} -port ${options.adbPort} -avd-arch ${avdArch} -show-kernel -kernel ${nuttxBinPath} ${portMappingStr} ${windowStr} ${grpcStr} -qemu ${imageMountStr}`;
|
|
160
|
-
return cmd;
|
|
161
|
-
}
|
|
162
|
-
static createPreCmd(options, sdkHome, avdHome) {
|
|
163
|
-
this.startOptions = options;
|
|
164
|
-
const { avdName, devtool } = options;
|
|
165
|
-
// 获取emulator bin的绝对路径
|
|
166
|
-
const emulatorBin = this.getEmulatorBinPath(sdkHome);
|
|
167
|
-
ColorConsole_1.default.log(`### Emulator ### emulator path: ${emulatorBin}`);
|
|
168
|
-
// 获取vela镜像的绝对路径
|
|
169
|
-
const velaAvdCls = new avd_1.default({
|
|
170
|
-
sdkHome: sdkHome,
|
|
171
|
-
avdHome: avdHome
|
|
172
|
-
});
|
|
173
|
-
const avdInfo = velaAvdCls.getVelaAvdInfo(avdName);
|
|
174
|
-
const { avdArch, avdImagePath, customImagePath } = avdInfo;
|
|
175
|
-
ColorConsole_1.default.log(`### Emulator ### adb port: ${options.adbPort}`);
|
|
176
|
-
if (!avdImagePath) {
|
|
177
|
-
ColorConsole_1.default.throw(`### Emulator ### Unable to find vela image via avd`);
|
|
178
|
-
return undefined;
|
|
179
|
-
}
|
|
180
|
-
const nuttxBinPath = path_1.default.resolve(customImagePath || avdImagePath, 'nuttx');
|
|
181
|
-
ColorConsole_1.default.log(`### Emulator ### nuttx path: ${nuttxBinPath}`);
|
|
182
|
-
// 端口映射,adb端口和debug端口
|
|
183
|
-
let portMappingStr = `user,id=u1,hostfwd=tcp:127.0.0.1:${options.adbPort}-10.0.2.15:5555`;
|
|
184
|
-
if (devtool) {
|
|
185
|
-
ColorConsole_1.default.log(`### Emulator ### debug port: ${options.debugPort}`);
|
|
186
|
-
portMappingStr += `,hostfwd=tcp:127.0.0.1:${options.debugPort}-10.0.2.15:101`;
|
|
187
|
-
}
|
|
188
|
-
ColorConsole_1.default.log(`### Emulator ### Start qemu with TCP: ${portMappingStr}`);
|
|
189
|
-
// vnc配置
|
|
190
|
-
let noWindow = false;
|
|
191
|
-
let vncStr = '';
|
|
192
|
-
if (options.grpcPort) {
|
|
193
|
-
noWindow = true;
|
|
194
|
-
const portSuffix = options.grpcPort - constants_1.defaultVncPort;
|
|
195
|
-
vncStr = `-vnc :${portSuffix}`;
|
|
196
|
-
}
|
|
197
|
-
// 启动goldfish的命令和参数
|
|
198
|
-
const spawnArgs = [
|
|
199
|
-
emulatorBin,
|
|
200
|
-
'-nuttx',
|
|
201
|
-
'-avd',
|
|
202
|
-
avdName,
|
|
203
|
-
'-avd-arch',
|
|
204
|
-
avdArch,
|
|
205
|
-
'-show-kernel',
|
|
206
|
-
'-kernel',
|
|
207
|
-
nuttxBinPath,
|
|
208
|
-
noWindow ? '-no-window' : '',
|
|
209
|
-
'-qemu',
|
|
210
|
-
vncStr,
|
|
211
|
-
'-netdev',
|
|
212
|
-
portMappingStr,
|
|
213
|
-
'-device',
|
|
214
|
-
'virtio-net-device,netdev=u1,bus=virtio-mmio-bus.3'
|
|
215
|
-
];
|
|
216
|
-
return spawnArgs;
|
|
217
|
-
}
|
|
218
|
-
static getEmulatorBinPath(sdkHome) {
|
|
219
|
-
const osPlatform = os_1.default.platform();
|
|
220
|
-
const arch = (0, utils_1.getSystemArch)();
|
|
221
|
-
const platform = osPlatform === 'win32' ? 'windows' : osPlatform;
|
|
222
|
-
const emulatorHome = path_1.default.resolve(sdkHome, 'emulator');
|
|
223
|
-
return path_1.default.resolve(emulatorHome, `${platform}-${arch}`, 'emulator');
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
exports.default = EmulatorCmd;
|
package/lib/instance/preDev.d.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { ChildProcess } from 'child_process';
|
|
2
|
-
import readline from 'readline';
|
|
3
|
-
import { INewGoldfishInstanceParams, IStartOptions } from '../typing/Instance';
|
|
4
|
-
import CommonInstance from './common';
|
|
5
|
-
/**
|
|
6
|
-
* OldGoldfishInstance
|
|
7
|
-
* 针对 Vela开发版(dev, 0.0.2)的镜像
|
|
8
|
-
*/
|
|
9
|
-
declare class OldGoldfishInstance extends CommonInstance {
|
|
10
|
-
private host9pPort;
|
|
11
|
-
v9fsProcess: ChildProcess | undefined;
|
|
12
|
-
stdoutReadline: readline.Interface;
|
|
13
|
-
stderrReadline: readline.Interface;
|
|
14
|
-
constructor(params: INewGoldfishInstanceParams);
|
|
15
|
-
/**
|
|
16
|
-
* 1. 启动9p server
|
|
17
|
-
* 2. 将打包好的rpk推到host的挂载目录
|
|
18
|
-
* 3. 启动模拟器
|
|
19
|
-
* 4. 模拟器启动成功后,adb连接模拟器
|
|
20
|
-
* 5. 连接成功后,在模拟器中启动快应用
|
|
21
|
-
*/
|
|
22
|
-
start(options: IStartOptions): Promise<void>;
|
|
23
|
-
/**
|
|
24
|
-
* 在模拟器中启动快应用(快应用都在模拟器的/data/app目录下)
|
|
25
|
-
* 1. 是否为调试模式
|
|
26
|
-
* 若是,在模拟器终端执行vapp app/${packageName} &
|
|
27
|
-
* 若否,在模拟器终端执行vapp --jsdebugger=10.0.2.15:101 app/${packageName} &
|
|
28
|
-
*/
|
|
29
|
-
startupQuickApp(options: IStartOptions): void;
|
|
30
|
-
/** host启动9pServer
|
|
31
|
-
* 作用是将本地的quickappMountDir目录挂载到模拟器的/data目录
|
|
32
|
-
*/
|
|
33
|
-
ensure9pServerRunnning(): Promise<void>;
|
|
34
|
-
/**
|
|
35
|
-
* 启动模拟器
|
|
36
|
-
* 1. 通过options生成模拟器的启动命令
|
|
37
|
-
* 2. 执行启动命令
|
|
38
|
-
* 3. 判断模拟器是否启动成功
|
|
39
|
-
* 3.1 若disableNSH=true,输出流中匹配到/quickapp_rpk_installer_init|rpk installer init done/,认为模拟器启动成功了
|
|
40
|
-
* 3.2 若disableNSH=false,认为8s过后模拟器启动成功了
|
|
41
|
-
* @param options
|
|
42
|
-
* @returns
|
|
43
|
-
*/
|
|
44
|
-
startGoldfish(options: IStartOptions): Promise<void>;
|
|
45
|
-
/**
|
|
46
|
-
* 推送文件到本地的${sdkHome}/qa/app/${packageName}目录
|
|
47
|
-
* @param sourceRoot 源目录
|
|
48
|
-
*/
|
|
49
|
-
pushRpk(sourceRoot: string): Promise<void>;
|
|
50
|
-
/** 停止模拟器并释放相关资源 */
|
|
51
|
-
stop(): Promise<void>;
|
|
52
|
-
}
|
|
53
|
-
export default OldGoldfishInstance;
|