@arkts/image-manager 0.2.3 → 0.3.1
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/dist/default-product-config.d.cts +1 -1
- package/dist/default-product-config.d.mts +1 -1
- package/dist/index.cjs +269 -210
- package/dist/index.d.cts +266 -43
- package/dist/index.d.mts +266 -43
- package/dist/index.mjs +267 -210
- package/dist/product-config-2xNDbvax.d.cts +72 -0
- package/dist/product-config-CDvEXtfy.d.mts +72 -0
- package/package.json +3 -1
- package/dist/product-config-BwP_DEGj.d.mts +0 -263
- package/dist/product-config-C-0AD84Q.d.cts +0 -263
package/dist/index.mjs
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import axios, { AxiosError } from "axios";
|
|
2
|
+
import satisfies from "semver/functions/satisfies";
|
|
2
3
|
import mitt from "mitt";
|
|
3
4
|
import progress from "progress-stream";
|
|
4
5
|
import unzipper from "unzipper";
|
|
5
6
|
|
|
6
7
|
//#region package.json
|
|
7
|
-
var version = "0.
|
|
8
|
+
var version = "0.3.1";
|
|
8
9
|
|
|
9
10
|
//#endregion
|
|
10
|
-
//#region src/
|
|
11
|
+
//#region src/devices/list.ts
|
|
11
12
|
let DevModel = /* @__PURE__ */ function(DevModel) {
|
|
12
13
|
DevModel["MCHEMU_AL00CN"] = "MCHEMU-AL00CN";
|
|
13
14
|
DevModel["PHEMU_FD00"] = "PHEMU-FD00";
|
|
@@ -28,6 +29,9 @@ var DeployError = class extends Error {
|
|
|
28
29
|
this.message = message;
|
|
29
30
|
this.cause = cause;
|
|
30
31
|
}
|
|
32
|
+
getCode() {
|
|
33
|
+
return this.code;
|
|
34
|
+
}
|
|
31
35
|
};
|
|
32
36
|
(function(_DeployError) {
|
|
33
37
|
_DeployError.Code = /* @__PURE__ */ function(Code) {
|
|
@@ -52,221 +56,237 @@ var RequestUrlError = class extends Error {
|
|
|
52
56
|
};
|
|
53
57
|
|
|
54
58
|
//#endregion
|
|
55
|
-
//#region src/
|
|
56
|
-
var
|
|
57
|
-
options
|
|
58
|
-
|
|
59
|
-
isCustomize = false;
|
|
60
|
-
isPublic = true;
|
|
61
|
-
vendorCountry = "CN";
|
|
62
|
-
hwHdcPort = "notset";
|
|
63
|
-
constructor(image, uuid, name, config) {
|
|
64
|
-
this.image = image;
|
|
65
|
-
this.config = config;
|
|
66
|
-
this.options.uuid = uuid;
|
|
67
|
-
this.options.name = name;
|
|
68
|
-
Object.assign(this.options, config);
|
|
69
|
-
if ("productName" in this.options) delete this.options.productName;
|
|
59
|
+
//#region src/screens/screen.ts
|
|
60
|
+
var ScreenImpl = class {
|
|
61
|
+
constructor(options) {
|
|
62
|
+
this.options = options;
|
|
70
63
|
}
|
|
71
|
-
|
|
72
|
-
this.options.
|
|
73
|
-
return this;
|
|
64
|
+
getDiagonal() {
|
|
65
|
+
return this.options.diagonal;
|
|
74
66
|
}
|
|
75
|
-
|
|
76
|
-
this.options.
|
|
67
|
+
setDiagonal(diagonal) {
|
|
68
|
+
this.options.diagonal = diagonal;
|
|
77
69
|
return this;
|
|
78
70
|
}
|
|
79
|
-
|
|
80
|
-
this.options.
|
|
81
|
-
return this;
|
|
71
|
+
getDensity() {
|
|
72
|
+
return this.options.density;
|
|
82
73
|
}
|
|
83
|
-
|
|
84
|
-
this.options.
|
|
74
|
+
setDensity(density) {
|
|
75
|
+
this.options.density = density;
|
|
85
76
|
return this;
|
|
86
77
|
}
|
|
87
|
-
|
|
88
|
-
this.options.
|
|
89
|
-
return this;
|
|
78
|
+
getHeight() {
|
|
79
|
+
return this.options.height;
|
|
90
80
|
}
|
|
91
|
-
|
|
92
|
-
this.options.
|
|
81
|
+
setHeight(height) {
|
|
82
|
+
this.options.height = height;
|
|
93
83
|
return this;
|
|
94
84
|
}
|
|
95
|
-
|
|
96
|
-
this.options.
|
|
97
|
-
return this;
|
|
85
|
+
getWidth() {
|
|
86
|
+
return this.options.width;
|
|
98
87
|
}
|
|
99
|
-
|
|
100
|
-
this.options.
|
|
88
|
+
setWidth(width) {
|
|
89
|
+
this.options.width = width;
|
|
101
90
|
return this;
|
|
102
91
|
}
|
|
103
|
-
|
|
104
|
-
this.options
|
|
105
|
-
return this;
|
|
92
|
+
toJSON() {
|
|
93
|
+
return this.options;
|
|
106
94
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
95
|
+
};
|
|
96
|
+
function createScreen(options) {
|
|
97
|
+
return new ScreenImpl(options);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/screens/product-preset.ts
|
|
102
|
+
var ProductPresetImpl = class {
|
|
103
|
+
constructor(productConfig, deviceType) {
|
|
104
|
+
this.productConfig = productConfig;
|
|
105
|
+
this.deviceType = deviceType;
|
|
110
106
|
}
|
|
111
|
-
|
|
112
|
-
this.
|
|
113
|
-
return this;
|
|
107
|
+
getProductConfig() {
|
|
108
|
+
return this.productConfig;
|
|
114
109
|
}
|
|
115
|
-
|
|
116
|
-
this.
|
|
117
|
-
|
|
110
|
+
getDeviceType() {
|
|
111
|
+
return this.deviceType;
|
|
112
|
+
}
|
|
113
|
+
toScreen() {
|
|
114
|
+
return createScreen({
|
|
115
|
+
diagonal: Number(this.productConfig.screenDiagonal),
|
|
116
|
+
density: Number(this.productConfig.screenDensity),
|
|
117
|
+
height: Number(this.productConfig.screenHeight),
|
|
118
|
+
width: Number(this.productConfig.screenWidth)
|
|
119
|
+
});
|
|
118
120
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
toJSON() {
|
|
122
|
+
return {
|
|
123
|
+
product: this.productConfig,
|
|
124
|
+
deviceType: this.deviceType
|
|
125
|
+
};
|
|
122
126
|
}
|
|
123
|
-
|
|
124
|
-
|
|
127
|
+
};
|
|
128
|
+
async function createProductPreset(productConfig, deviceType) {
|
|
129
|
+
return new ProductPresetImpl(productConfig, deviceType);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/devices/device.ts
|
|
134
|
+
var DeviceImpl = class {
|
|
135
|
+
uuid;
|
|
136
|
+
constructor(image, options) {
|
|
137
|
+
this.image = image;
|
|
138
|
+
this.options = options;
|
|
139
|
+
this.uuid = image.getImageManager().getOptions().crypto.randomUUID();
|
|
140
|
+
}
|
|
141
|
+
getOptions() {
|
|
142
|
+
return this.options;
|
|
143
|
+
}
|
|
144
|
+
getImage() {
|
|
145
|
+
return this.image;
|
|
146
|
+
}
|
|
147
|
+
getScreen() {
|
|
148
|
+
if (this.options.screen instanceof ProductPresetImpl) return this.options.screen.toScreen();
|
|
149
|
+
return this.options.screen;
|
|
150
|
+
}
|
|
151
|
+
setUuid(uuid) {
|
|
152
|
+
this.uuid = uuid;
|
|
125
153
|
return this;
|
|
126
154
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const productConfigItem = (await this.image.getProductConfig()).find((item) => item.name === this.config.productName);
|
|
130
|
-
if (!productConfigItem) throw new Error(`Product config item ${this.config.productName} not found`);
|
|
131
|
-
if (productConfigItem.devModel) return productConfigItem.devModel;
|
|
132
|
-
const defaultProductConfigItem = (await this.image.getProductConfig(true)).find((item) => item.name === this.config.productName);
|
|
133
|
-
if (!defaultProductConfigItem) throw new Error(`Default product config item ${this.config.productName} not found`);
|
|
134
|
-
if (defaultProductConfigItem.devModel) return defaultProductConfigItem.devModel;
|
|
155
|
+
getUuid() {
|
|
156
|
+
return this.uuid;
|
|
135
157
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
"
|
|
141
|
-
"abi": this.image.getArch(),
|
|
158
|
+
buildList() {
|
|
159
|
+
const { path, deployedPath, imageBasePath, configPath, logPath } = this.image.getImageManager().getOptions();
|
|
160
|
+
const screen = this.getScreen();
|
|
161
|
+
const list = {
|
|
162
|
+
"name": this.options.name,
|
|
142
163
|
"apiVersion": this.image.getApiVersion(),
|
|
143
|
-
"
|
|
164
|
+
"cpuNumber": this.options.cpuNumber.toFixed(),
|
|
165
|
+
"diagonalSize": screen.getDiagonal().toFixed(2),
|
|
166
|
+
"resolutionHeight": screen.getHeight().toFixed(),
|
|
167
|
+
"resolutionWidth": screen.getWidth().toFixed(),
|
|
168
|
+
"density": screen.getDensity().toFixed(),
|
|
169
|
+
"memoryRamSize": this.options.memorySize.toFixed(),
|
|
170
|
+
"dataDiskSize": this.options.diskSize.toFixed(),
|
|
171
|
+
"path": path.resolve(deployedPath, this.options.name),
|
|
172
|
+
"type": this.image.getSnakecaseDeviceType(),
|
|
173
|
+
"uuid": this.uuid,
|
|
174
|
+
"version": this.image.getVersion(),
|
|
175
|
+
"imageDir": this.image.getPath().split(",").join(path.sep) + path.sep,
|
|
144
176
|
"showVersion": `${this.image.getTargetOS()} ${this.image.getTargetVersion()}(${this.image.getApiVersion()})`,
|
|
145
|
-
"
|
|
177
|
+
"harmonyos.sdk.path": imageBasePath,
|
|
178
|
+
"harmonyos.config.path": configPath,
|
|
179
|
+
"harmonyos.log.path": logPath,
|
|
146
180
|
"hw.apiName": this.image.getTargetVersion(),
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"type": this.image.getSnakecaseDeviceType(),
|
|
151
|
-
"devModel": await this.getDevModel()
|
|
181
|
+
"abi": this.image.getArch(),
|
|
182
|
+
"harmonyOSVersion": `${this.image.getTargetOS()}-${this.image.getTargetVersion()}`,
|
|
183
|
+
"guestVersion": `${this.image.getTargetOS()} ${this.image.getVersion()}(${this.image.getReleaseType()})`
|
|
152
184
|
};
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
return
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
"
|
|
177
|
-
"
|
|
178
|
-
"
|
|
179
|
-
"
|
|
180
|
-
"
|
|
181
|
-
"
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"
|
|
185
|
-
"
|
|
186
|
-
"
|
|
187
|
-
"
|
|
188
|
-
"
|
|
189
|
-
"
|
|
190
|
-
"
|
|
191
|
-
"
|
|
192
|
-
"
|
|
193
|
-
"hw.
|
|
185
|
+
if (this.options.screen instanceof ProductPresetImpl) {
|
|
186
|
+
const productConfig = this.options.screen.getProductConfig();
|
|
187
|
+
if (productConfig.devModel) list.devModel = productConfig.devModel;
|
|
188
|
+
if (productConfig.name) list.model = productConfig.name;
|
|
189
|
+
}
|
|
190
|
+
return list;
|
|
191
|
+
}
|
|
192
|
+
buildIni(options = {}) {
|
|
193
|
+
const listConfig = this.buildList();
|
|
194
|
+
const screen = this.getScreen();
|
|
195
|
+
const is2in1Foldable = listConfig.type === "2in1_foldable";
|
|
196
|
+
const productPreset = this.options.screen instanceof ProductPresetImpl ? this.options.screen : null;
|
|
197
|
+
const productConfig = productPreset?.getProductConfig();
|
|
198
|
+
const useDualScreen = is2in1Foldable && productConfig?.outerScreenWidth != null && productConfig?.outerScreenHeight != null && productConfig?.outerScreenDiagonal != null;
|
|
199
|
+
const singleDiagonal = useDualScreen ? productConfig.outerScreenDiagonal : screen.getDiagonal().toString();
|
|
200
|
+
const singleHeight = useDualScreen ? productConfig.outerScreenHeight : screen.getHeight().toString();
|
|
201
|
+
const singleWidth = useDualScreen ? productConfig.outerScreenWidth : screen.getWidth().toString();
|
|
202
|
+
const doubleDiagonal = useDualScreen ? productConfig.screenDiagonal : void 0;
|
|
203
|
+
const doubleHeight = useDualScreen ? productConfig.screenHeight : void 0;
|
|
204
|
+
const doubleWidth = useDualScreen ? productConfig.screenWidth : void 0;
|
|
205
|
+
const ini = {
|
|
206
|
+
"name": listConfig.name,
|
|
207
|
+
"deviceType": listConfig.type,
|
|
208
|
+
"deviceModel": listConfig.devModel,
|
|
209
|
+
"productModel": listConfig.model,
|
|
210
|
+
"vendorCountry": options.vendorCountry ?? "CN",
|
|
211
|
+
"uuid": this.uuid,
|
|
212
|
+
"configPath": listConfig["harmonyos.config.path"],
|
|
213
|
+
"logPath": listConfig["harmonyos.log.path"],
|
|
214
|
+
"sdkPath": listConfig["harmonyos.sdk.path"],
|
|
215
|
+
"imageSubPath": listConfig.imageDir,
|
|
216
|
+
"instancePath": listConfig.path,
|
|
217
|
+
"os.osVersion": `${this.image.getTargetOS()} ${this.image.getTargetVersion()}(${this.image.getApiVersion()})`,
|
|
218
|
+
"os.apiVersion": this.image.getApiVersion(),
|
|
219
|
+
"os.softwareVersion": this.image.getVersion(),
|
|
220
|
+
"os.isPublic": options.isPublic ?? true ? "true" : "false",
|
|
221
|
+
"hw.cpu.arch": listConfig.abi,
|
|
222
|
+
"hw.cpu.ncore": listConfig.cpuNumber,
|
|
223
|
+
"hw.lcd.density": screen.getDensity().toFixed(),
|
|
224
|
+
"hw.lcd.single.diagonalSize": singleDiagonal,
|
|
225
|
+
"hw.lcd.single.height": singleHeight,
|
|
226
|
+
"hw.lcd.single.width": singleWidth,
|
|
227
|
+
"hw.lcd.number": useDualScreen ? "2" : "1",
|
|
228
|
+
"hw.ramSize": listConfig.memoryRamSize,
|
|
229
|
+
"hw.dataPartitionSize": listConfig.dataDiskSize,
|
|
230
|
+
"isCustomize": productPreset ? "false" : "true",
|
|
231
|
+
"hw.hdc.port": "notset",
|
|
232
|
+
...options.overrides
|
|
194
233
|
};
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
async writeToListWithCheck(config) {
|
|
200
|
-
const fs = this.image.getImageManager().getOptions().fs;
|
|
201
|
-
const listsPath = this.image.getImageManager().getOptions().path.resolve(this.image.getImageManager().getOptions().deployedPath, "lists.json");
|
|
202
|
-
try {
|
|
203
|
-
if (!fs.existsSync(listsPath)) fs.writeFileSync(listsPath, JSON.stringify([config], null, 2));
|
|
204
|
-
else {
|
|
205
|
-
const lists = JSON.parse(fs.readFileSync(listsPath, "utf-8")) ?? [];
|
|
206
|
-
if (!Array.isArray(lists)) return new DeployError(DeployError.Code.LIST_JSON_NOT_AN_ARRAY, "Lists is not an array");
|
|
207
|
-
if (lists.find((item) => item.name === config.name)) return;
|
|
208
|
-
lists.push(config);
|
|
209
|
-
fs.writeFileSync(listsPath, JSON.stringify(lists, null, 2));
|
|
210
|
-
}
|
|
211
|
-
} catch (err) {
|
|
212
|
-
return err instanceof Error ? new DeployError(DeployError.Code.CATCHED_ERROR, String(err)) : new DeployError(DeployError.Code.CATCHED_ERROR, String(err));
|
|
234
|
+
if (useDualScreen && doubleDiagonal != null && doubleHeight != null && doubleWidth != null) {
|
|
235
|
+
ini["hw.lcd.double.diagonalSize"] = doubleDiagonal;
|
|
236
|
+
ini["hw.lcd.double.height"] = doubleHeight;
|
|
237
|
+
ini["hw.lcd.double.width"] = doubleWidth;
|
|
213
238
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (!Array.isArray(content)) resolve(new DeployError(DeployError.Code.LIST_JSON_NOT_AN_ARRAY, "List rechecker is not an array!"));
|
|
218
|
-
else if (!content.find((item) => item.name === config.name)) resolve(new DeployError(DeployError.Code.MAYBE_OPENED_DEVICE_MANAGER_IN_DEVECO_STUDIO, `Device ${config.name} not found in lists.json! Maybe not deployed yet?`));
|
|
219
|
-
else resolve();
|
|
220
|
-
clearTimeout(timer);
|
|
221
|
-
}, 1e3);
|
|
222
|
-
});
|
|
223
|
-
}
|
|
224
|
-
async deploy(symlinkImage = true) {
|
|
225
|
-
const { fs, path, imageBasePath, sdkPath } = this.image.getImageManager().getOptions();
|
|
226
|
-
const config = await this.buildList();
|
|
227
|
-
if (fs.existsSync(config.path)) return new DeployError(DeployError.Code.DEVICE_ALREADY_DEPLOYED, `Image ${config.name} already deployed`);
|
|
228
|
-
const error = await this.writeToListWithCheck(config);
|
|
229
|
-
if (error) return error;
|
|
230
|
-
fs.mkdirSync(config.path, { recursive: true });
|
|
231
|
-
fs.writeFileSync(path.join(config.path, "config.ini"), await this.toIniString());
|
|
232
|
-
const symlinkSdkPath = path.resolve(imageBasePath, "default", "openharmony");
|
|
233
|
-
if (!fs.existsSync(path.dirname(symlinkSdkPath))) fs.mkdirSync(path.dirname(symlinkSdkPath), { recursive: true });
|
|
234
|
-
try {
|
|
235
|
-
if (fs.lstatSync(symlinkSdkPath).isSymbolicLink()) fs.unlinkSync(symlinkSdkPath);
|
|
236
|
-
else return new DeployError(DeployError.Code.SYMLINK_SDK_PATH_EXISTS, "Symlink SDK path already exists");
|
|
237
|
-
} catch {}
|
|
238
|
-
fs.symlinkSync(sdkPath, symlinkSdkPath, "dir");
|
|
239
|
-
const systemImageDir = path.join(imageBasePath, "system-image");
|
|
240
|
-
if (symlinkImage && fs.existsSync(systemImageDir)) {
|
|
241
|
-
const linkPath = path.join(config.path, "system-image");
|
|
242
|
-
try {
|
|
243
|
-
const target = path.relative(config.path, systemImageDir);
|
|
244
|
-
fs.symlinkSync(target, linkPath);
|
|
245
|
-
} catch (err) {
|
|
246
|
-
return err instanceof Error ? new DeployError(DeployError.Code.CATCHED_ERROR, String(err)) : new DeployError(DeployError.Code.CATCHED_ERROR, String(err));
|
|
247
|
-
}
|
|
239
|
+
if (productPreset && productConfig && !useDualScreen) {
|
|
240
|
+
if (productConfig.outerScreenHeight) ini["hw.phy.height"] = productConfig.outerScreenHeight;
|
|
241
|
+
if (productConfig.outerScreenWidth) ini["hw.phy.width"] = productConfig.outerScreenWidth;
|
|
248
242
|
}
|
|
243
|
+
return ini;
|
|
249
244
|
}
|
|
250
|
-
async
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
245
|
+
async toIniString() {
|
|
246
|
+
return `${Object.entries(this.buildIni()).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${value}`).join("\n")}\n`;
|
|
247
|
+
}
|
|
248
|
+
async deploy() {
|
|
249
|
+
const { fs, path, deployedPath } = this.image.getImageManager().getOptions();
|
|
250
|
+
if (!fs.existsSync(deployedPath)) fs.mkdirSync(deployedPath, { recursive: true });
|
|
251
|
+
const listsPath = path.join(deployedPath, "lists.json");
|
|
252
|
+
const listConfig = this.buildList();
|
|
253
|
+
if (fs.existsSync(listConfig.path)) throw new DeployError(DeployError.Code.DEVICE_ALREADY_DEPLOYED, `Image ${listConfig.name} already deployed`);
|
|
254
|
+
if (!fs.existsSync(listsPath)) return fs.writeFileSync(listsPath, JSON.stringify([listConfig], null, 2));
|
|
255
|
+
const lists = JSON.parse(fs.readFileSync(listsPath, "utf-8")) ?? [];
|
|
256
|
+
if (!Array.isArray(lists)) throw new DeployError(DeployError.Code.LIST_JSON_NOT_AN_ARRAY, "Lists is not an array");
|
|
257
|
+
if (lists.find((item) => item.name === listConfig.name)) throw new DeployError(DeployError.Code.DEVICE_ALREADY_DEPLOYED, `Image ${listConfig.name} already deployed in lists.json`);
|
|
258
|
+
lists.push(listConfig);
|
|
259
|
+
fs.writeFileSync(listsPath, JSON.stringify(lists, null, 2));
|
|
260
|
+
fs.mkdirSync(listConfig.path, { recursive: true });
|
|
261
|
+
fs.writeFileSync(path.join(listConfig.path, "config.ini"), await this.toIniString());
|
|
255
262
|
}
|
|
256
263
|
async delete() {
|
|
257
|
-
const { fs, path } = this.image.getImageManager().getOptions();
|
|
258
|
-
const listsPath = path.
|
|
259
|
-
if (!fs.existsSync(listsPath) || !fs.statSync(listsPath).isFile())
|
|
264
|
+
const { fs, path, deployedPath } = this.image.getImageManager().getOptions();
|
|
265
|
+
const listsPath = path.join(deployedPath, "lists.json");
|
|
266
|
+
if (!fs.existsSync(listsPath) || !fs.statSync(listsPath).isFile()) throw new Error("Lists file not found");
|
|
260
267
|
const lists = JSON.parse(fs.readFileSync(listsPath, "utf-8")) ?? [];
|
|
261
268
|
const index = lists.findIndex((item) => item.name === this.options.name);
|
|
262
|
-
if (index === -1)
|
|
269
|
+
if (index === -1) throw new Error(`Device ${this.options.name} not found`);
|
|
263
270
|
lists.splice(index, 1);
|
|
264
271
|
fs.writeFileSync(listsPath, JSON.stringify(lists, null, 2));
|
|
265
|
-
fs.rmSync(path.resolve(this.
|
|
272
|
+
fs.rmSync(path.resolve(this.buildList().path), { recursive: true });
|
|
273
|
+
}
|
|
274
|
+
async isDeployed() {
|
|
275
|
+
const { fs, path, deployedPath } = this.image.getImageManager().getOptions();
|
|
276
|
+
const listsPath = path.join(deployedPath, "lists.json");
|
|
277
|
+
if (!fs.existsSync(listsPath) || !fs.statSync(listsPath).isFile()) return false;
|
|
278
|
+
return (JSON.parse(fs.readFileSync(listsPath, "utf-8")) ?? []).some((item) => item.name === this.options.name && fs.existsSync(path.resolve(item.path, "config.ini")));
|
|
279
|
+
}
|
|
280
|
+
toJSON() {
|
|
281
|
+
return {
|
|
282
|
+
...this.options,
|
|
283
|
+
list: this.buildList(),
|
|
284
|
+
ini: this.buildIni()
|
|
285
|
+
};
|
|
266
286
|
}
|
|
267
287
|
};
|
|
268
|
-
function
|
|
269
|
-
return new
|
|
288
|
+
function createDevice(image, options) {
|
|
289
|
+
return new DeviceImpl(image, options);
|
|
270
290
|
}
|
|
271
291
|
|
|
272
292
|
//#endregion
|
|
@@ -433,6 +453,9 @@ var ImageBase = class {
|
|
|
433
453
|
getChecksum() {
|
|
434
454
|
return this.response?.archive?.complete?.checksum;
|
|
435
455
|
}
|
|
456
|
+
getReleaseType() {
|
|
457
|
+
return this.response?.releaseType;
|
|
458
|
+
}
|
|
436
459
|
getFsPath() {
|
|
437
460
|
return this.resolvedFsPath;
|
|
438
461
|
}
|
|
@@ -508,8 +531,25 @@ var ImageBase = class {
|
|
|
508
531
|
//#region src/images/local-image.ts
|
|
509
532
|
var LocalImageImpl = class extends ImageBase {
|
|
510
533
|
imageType = "local";
|
|
511
|
-
createDevice(
|
|
512
|
-
return
|
|
534
|
+
createDevice(options) {
|
|
535
|
+
return createDevice(this, options);
|
|
536
|
+
}
|
|
537
|
+
async getPascalCaseDeviceType() {
|
|
538
|
+
const deviceType = this.getDeviceType().toLowerCase();
|
|
539
|
+
if (!deviceType) return;
|
|
540
|
+
if (deviceType === "pc") return "2in1 Foldable";
|
|
541
|
+
const key = [
|
|
542
|
+
"phone",
|
|
543
|
+
"tablet",
|
|
544
|
+
"2in1",
|
|
545
|
+
"foldable",
|
|
546
|
+
"widefold",
|
|
547
|
+
"triplefold",
|
|
548
|
+
"2in1 foldable",
|
|
549
|
+
"tv",
|
|
550
|
+
"wearable"
|
|
551
|
+
].find((key) => key === deviceType);
|
|
552
|
+
if (key) return key;
|
|
513
553
|
}
|
|
514
554
|
async getProductConfig(usingDefaultProductConfig = false) {
|
|
515
555
|
const productConfig = usingDefaultProductConfig ? (await import("./default-product-config.mjs")).default : await this.getImageManager().getProductConfig();
|
|
@@ -533,8 +573,8 @@ var LocalImageImpl = class extends ImageBase {
|
|
|
533
573
|
const { emulatorPath, process, path } = this.getImageManager().getOptions();
|
|
534
574
|
return process.platform === "win32" ? path.join(emulatorPath, "Emulator.exe") : path.join(emulatorPath, "Emulator");
|
|
535
575
|
}
|
|
536
|
-
async buildStartCommand(
|
|
537
|
-
const config =
|
|
576
|
+
async buildStartCommand(device) {
|
|
577
|
+
const config = device.buildList();
|
|
538
578
|
return `${this.getExecutablePath()} ${[
|
|
539
579
|
"-hvd",
|
|
540
580
|
`"${config.name.replace(/"/g, "\\\"")}"`,
|
|
@@ -548,29 +588,49 @@ var LocalImageImpl = class extends ImageBase {
|
|
|
548
588
|
const { child_process, emulatorPath } = this.getImageManager().getOptions();
|
|
549
589
|
return child_process.exec(await this.buildStartCommand(deployer), { cwd: emulatorPath });
|
|
550
590
|
}
|
|
551
|
-
async buildStopCommand(
|
|
552
|
-
const config =
|
|
591
|
+
async buildStopCommand(device) {
|
|
592
|
+
const config = device.buildList();
|
|
553
593
|
return `${this.getExecutablePath()} ${["-stop", `"${config.name.replace(/"/g, "\\\"")}"`].join(" ")}`;
|
|
554
594
|
}
|
|
555
|
-
async stop(
|
|
595
|
+
async stop(device) {
|
|
556
596
|
const { child_process, emulatorPath } = this.getImageManager().getOptions();
|
|
557
|
-
return child_process.exec(await this.buildStopCommand(
|
|
597
|
+
return child_process.exec(await this.buildStopCommand(device), { cwd: emulatorPath });
|
|
598
|
+
}
|
|
599
|
+
async createScreenLike(listsJsonItem) {
|
|
600
|
+
if (!listsJsonItem.model) return createScreen({
|
|
601
|
+
diagonal: Number(listsJsonItem.diagonalSize),
|
|
602
|
+
height: Number(listsJsonItem.resolutionHeight),
|
|
603
|
+
width: Number(listsJsonItem.resolutionWidth),
|
|
604
|
+
density: Number(listsJsonItem.density)
|
|
605
|
+
});
|
|
606
|
+
const productConfigItem = (await this.getProductConfig()).find((item) => item.name === listsJsonItem.model);
|
|
607
|
+
const pascalCaseDeviceType = await this.getPascalCaseDeviceType();
|
|
608
|
+
if (!productConfigItem || !pascalCaseDeviceType || productConfigItem.screenDiagonal !== listsJsonItem.diagonalSize || productConfigItem.screenHeight !== listsJsonItem.resolutionHeight || productConfigItem.screenWidth !== listsJsonItem.resolutionWidth || productConfigItem.screenDensity !== listsJsonItem.density) return createScreen({
|
|
609
|
+
diagonal: Number(listsJsonItem.diagonalSize),
|
|
610
|
+
height: Number(listsJsonItem.resolutionHeight),
|
|
611
|
+
width: Number(listsJsonItem.resolutionWidth),
|
|
612
|
+
density: Number(listsJsonItem.density)
|
|
613
|
+
});
|
|
614
|
+
return createProductPreset(productConfigItem, pascalCaseDeviceType);
|
|
558
615
|
}
|
|
559
|
-
typeAssert(value) {}
|
|
560
616
|
async getDevices() {
|
|
561
|
-
const { path, fs, imageBasePath } = this.getImageManager().getOptions();
|
|
562
|
-
const listsJsonPath = path.resolve(
|
|
617
|
+
const { path, fs, deployedPath, imageBasePath } = this.getImageManager().getOptions();
|
|
618
|
+
const listsJsonPath = path.resolve(deployedPath, "lists.json");
|
|
563
619
|
if (!fs.existsSync(listsJsonPath) || !fs.statSync(listsJsonPath).isFile()) return [];
|
|
564
620
|
const listsJson = JSON.parse(fs.readFileSync(listsJsonPath, "utf-8"));
|
|
565
621
|
if (!Array.isArray(listsJson) || this.imageType !== "local") return [];
|
|
566
|
-
this.typeAssert(this);
|
|
567
622
|
const devices = [];
|
|
568
623
|
for (const listsJsonItem of listsJson) {
|
|
569
|
-
if (
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
624
|
+
if (path.resolve(imageBasePath, listsJsonItem.imageDir) !== this.getFsPath()) continue;
|
|
625
|
+
const device = this.createDevice({
|
|
626
|
+
name: listsJsonItem.name,
|
|
627
|
+
cpuNumber: Number(listsJsonItem.cpuNumber),
|
|
628
|
+
diskSize: Number(listsJsonItem.dataDiskSize),
|
|
629
|
+
memorySize: Number(listsJsonItem.memoryRamSize),
|
|
630
|
+
screen: await this.createScreenLike(listsJsonItem)
|
|
631
|
+
});
|
|
632
|
+
if (!fs.existsSync(device.buildList().path) || !fs.statSync(device.buildList().path).isDirectory()) continue;
|
|
633
|
+
devices.push(device);
|
|
574
634
|
}
|
|
575
635
|
return devices;
|
|
576
636
|
}
|
|
@@ -702,22 +762,19 @@ var ImageManagerImpl = class {
|
|
|
702
762
|
if (existSkip && this.resolvedOptions.fs.existsSync(productConfigPath)) return;
|
|
703
763
|
this.resolvedOptions.fs.writeFileSync(productConfigPath, JSON.stringify((await import("./default-product-config.mjs")).default, null, 2));
|
|
704
764
|
}
|
|
765
|
+
async isCompatible() {
|
|
766
|
+
const { fs, path, emulatorPath } = this.resolvedOptions;
|
|
767
|
+
const sdkPkgPath = path.resolve(emulatorPath, "sdk-pkg.json");
|
|
768
|
+
if (!fs.existsSync(sdkPkgPath) || !fs.statSync(sdkPkgPath).isFile()) return false;
|
|
769
|
+
const sdkPkg = JSON.parse(fs.readFileSync(sdkPkgPath, "utf-8"));
|
|
770
|
+
if (!sdkPkg?.data?.version || typeof sdkPkg.data.version !== "string") return false;
|
|
771
|
+
const [major, minor, patch] = sdkPkg.data.version.split(".").map(Number);
|
|
772
|
+
return satisfies(`${major}.${minor}.${patch}`, ">=6.0.2");
|
|
773
|
+
}
|
|
705
774
|
};
|
|
706
775
|
async function createImageManager(options = {}) {
|
|
707
776
|
return new ImageManagerImpl(await resolveImageManagerOptions(options));
|
|
708
777
|
}
|
|
709
778
|
|
|
710
779
|
//#endregion
|
|
711
|
-
|
|
712
|
-
function createDeployedImageConfig(productConfigItem) {
|
|
713
|
-
return {
|
|
714
|
-
density: productConfigItem.screenDensity,
|
|
715
|
-
resolutionHeight: productConfigItem.screenHeight,
|
|
716
|
-
resolutionWidth: productConfigItem.screenWidth,
|
|
717
|
-
diagonalSize: productConfigItem.screenDiagonal,
|
|
718
|
-
productName: productConfigItem.name
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
//#endregion
|
|
723
|
-
export { DeployError, DevModel, RequestUrlError, createDeployedImageConfig, createImageManager, version };
|
|
780
|
+
export { DeployError, DevModel, RequestUrlError, createImageManager, createProductPreset, createScreen, version };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
2
|
+
interface Stringifiable<T> {
|
|
3
|
+
toJSON(): T;
|
|
4
|
+
}
|
|
5
|
+
type OS = 'windows' | 'mac' | 'linux';
|
|
6
|
+
type Arch = 'x86' | 'arm64';
|
|
7
|
+
type DeviceType = 'pc' | 'phone' | 'tablet' | 'wearable' | 'tv' | 'foldable' | 'widefold' | '2in1';
|
|
8
|
+
type SnakecaseDeviceType = 'phone' | 'tablet' | '2in1' | 'foldable' | 'widefold' | 'triplefold' | '2in1_foldable' | 'tv' | 'wearable';
|
|
9
|
+
type PascalCaseDeviceType = 'Phone' | 'Tablet' | '2in1' | 'Foldable' | 'WideFold' | 'TripleFold' | '2in1 Foldable' | 'TV' | 'Wearable';
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/product-config.d.ts
|
|
12
|
+
interface ProductConfigItem {
|
|
13
|
+
/**
|
|
14
|
+
* The name of the product.
|
|
15
|
+
*/
|
|
16
|
+
name: string;
|
|
17
|
+
/**
|
|
18
|
+
* The screen width of the product.
|
|
19
|
+
*/
|
|
20
|
+
screenWidth: string;
|
|
21
|
+
/**
|
|
22
|
+
* The screen height of the product.
|
|
23
|
+
*/
|
|
24
|
+
screenHeight: string;
|
|
25
|
+
/**
|
|
26
|
+
* The screen diagonal of the product.
|
|
27
|
+
*/
|
|
28
|
+
screenDiagonal: string;
|
|
29
|
+
/**
|
|
30
|
+
* The screen density of the product.
|
|
31
|
+
*/
|
|
32
|
+
screenDensity: string;
|
|
33
|
+
/**
|
|
34
|
+
* The outer screen width of the product.
|
|
35
|
+
*/
|
|
36
|
+
outerScreenWidth?: string;
|
|
37
|
+
/**
|
|
38
|
+
* The outer screen height of the product.
|
|
39
|
+
*/
|
|
40
|
+
outerDoubleScreenWidth?: string;
|
|
41
|
+
/**
|
|
42
|
+
* The outer double screen height of the product.
|
|
43
|
+
*/
|
|
44
|
+
outerDoubleScreenHeight?: string;
|
|
45
|
+
/**
|
|
46
|
+
* The outer double screen diagonal of the product.
|
|
47
|
+
*/
|
|
48
|
+
outerDoubleScreenDiagonal?: string;
|
|
49
|
+
/**
|
|
50
|
+
* The outer screen height of the product.
|
|
51
|
+
*/
|
|
52
|
+
outerScreenHeight?: string;
|
|
53
|
+
/**
|
|
54
|
+
* The outer screen diagonal of the product.
|
|
55
|
+
*/
|
|
56
|
+
outerScreenDiagonal?: string;
|
|
57
|
+
/**
|
|
58
|
+
* Whether the product is visible.
|
|
59
|
+
*/
|
|
60
|
+
visible: boolean;
|
|
61
|
+
/**
|
|
62
|
+
* The one cutout path of the product.
|
|
63
|
+
*/
|
|
64
|
+
oneCutoutPath?: string;
|
|
65
|
+
/**
|
|
66
|
+
* The dev model of the product.
|
|
67
|
+
*/
|
|
68
|
+
devModel?: string;
|
|
69
|
+
}
|
|
70
|
+
type ProductConfig = Record<PascalCaseDeviceType, ProductConfigItem[]>;
|
|
71
|
+
//#endregion
|
|
72
|
+
export { OS as a, Stringifiable as c, DeviceType as i, ProductConfigItem as n, PascalCaseDeviceType as o, Arch as r, SnakecaseDeviceType as s, ProductConfig as t };
|