@oniroproject/core 0.7.0 → 0.9.0
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 +18 -6
- package/dist/index.cjs +899 -444
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +301 -18
- package/dist/index.d.ts +301 -18
- package/dist/index.js +874 -445
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -37,22 +37,29 @@ __export(index_exports, {
|
|
|
37
37
|
ChecksumMismatchError: () => ChecksumMismatchError,
|
|
38
38
|
CmdToolsNotInstalledError: () => CmdToolsNotInstalledError,
|
|
39
39
|
CommandFailedError: () => CommandFailedError,
|
|
40
|
+
INSTALL_TMP_DIRNAME: () => INSTALL_TMP_DIRNAME,
|
|
41
|
+
InsufficientSpaceError: () => InsufficientSpaceError,
|
|
40
42
|
OHOS_URL_BASE: () => OHOS_URL_BASE,
|
|
41
43
|
OniroError: () => OniroError,
|
|
42
44
|
SdkNotInstalledError: () => SdkNotInstalledError,
|
|
45
|
+
TMP_DIR_HINT: () => TMP_DIR_HINT,
|
|
43
46
|
UnsupportedPlatformError: () => UnsupportedPlatformError,
|
|
44
47
|
VERSION: () => VERSION,
|
|
45
48
|
applyChanges: () => applyChanges,
|
|
46
49
|
attemptHdcConnection: () => attemptHdcConnection,
|
|
50
|
+
buildCmdWrapper: () => buildCmdWrapper,
|
|
47
51
|
buildGestureCommands: () => buildGestureCommands,
|
|
52
|
+
buildGestureUitestCommand: () => buildGestureUitestCommand,
|
|
48
53
|
buildHap: () => buildHap,
|
|
49
54
|
buildHvigorwArgs: () => buildHvigorwArgs,
|
|
50
55
|
buildInputCommand: () => buildInputCommand,
|
|
51
56
|
buildRawTouchCommand: () => buildRawTouchCommand,
|
|
52
57
|
captureBurst: () => captureBurst,
|
|
53
58
|
consoleLogger: () => consoleLogger,
|
|
59
|
+
createInstallTempDir: () => createInstallTempDir,
|
|
54
60
|
createMaterial: () => createMaterial,
|
|
55
61
|
createScaffold: () => createScaffold,
|
|
62
|
+
createTempWorkDir: () => createTempWorkDir,
|
|
56
63
|
decideInstallMethod: () => decideInstallMethod,
|
|
57
64
|
decideReboot: () => decideReboot,
|
|
58
65
|
decryptPwd: () => decryptPwd,
|
|
@@ -73,14 +80,19 @@ __export(index_exports, {
|
|
|
73
80
|
dumpScreen: () => dumpScreen,
|
|
74
81
|
dumpWindow: () => dumpWindow,
|
|
75
82
|
encryptPwd: () => encryptPwd,
|
|
83
|
+
ensureFreeSpace: () => ensureFreeSpace,
|
|
76
84
|
ensureOhModules: () => ensureOhModules,
|
|
77
85
|
ensureOk: () => ensureOk,
|
|
86
|
+
ensureRemoteOk: () => ensureRemoteOk,
|
|
87
|
+
escapeCmdArgument: () => escapeCmdArgument,
|
|
88
|
+
escapeCmdCommand: () => escapeCmdCommand,
|
|
78
89
|
extractTarball: () => extractTarball,
|
|
79
90
|
extractZipWithProgress: () => extractZipWithProgress,
|
|
80
91
|
findAppProcessId: () => findAppProcessId,
|
|
81
92
|
findCmdToolsSourceDir: () => findCmdToolsSourceDir,
|
|
82
93
|
findRunningProcess: () => findRunningProcess,
|
|
83
94
|
forceStop: () => forceStop,
|
|
95
|
+
formatBytes: () => formatBytes,
|
|
84
96
|
generateSigningConfigs: () => generateSigningConfigs,
|
|
85
97
|
getBundleName: () => getBundleName,
|
|
86
98
|
getCmdToolsBin: () => getCmdToolsBin,
|
|
@@ -90,6 +102,7 @@ __export(index_exports, {
|
|
|
90
102
|
getDeviceInfo: () => getDeviceInfo,
|
|
91
103
|
getDisplaySize: () => getDisplaySize,
|
|
92
104
|
getEmulatorDir: () => getEmulatorDir,
|
|
105
|
+
getFreeSpaceBytes: () => getFreeSpaceBytes,
|
|
93
106
|
getHdcPath: () => getHdcPath,
|
|
94
107
|
getHvigorwPath: () => getHvigorwPath,
|
|
95
108
|
getInstalledSdks: () => getInstalledSdks,
|
|
@@ -107,14 +120,18 @@ __export(index_exports, {
|
|
|
107
120
|
installEmulator: () => installEmulator,
|
|
108
121
|
isCmdToolsInstalled: () => isCmdToolsInstalled,
|
|
109
122
|
isEmulatorInstalled: () => isEmulatorInstalled,
|
|
123
|
+
isOutOfSpaceError: () => isOutOfSpaceError,
|
|
124
|
+
isRamBackedPath: () => isRamBackedPath,
|
|
110
125
|
isValidBundleName: () => isValidBundleName,
|
|
111
126
|
isValidProjectName: () => isValidProjectName,
|
|
127
|
+
killProcessTree: () => killProcessTree,
|
|
112
128
|
launchApp: () => launchApp,
|
|
113
129
|
listAbilities: () => listAbilities,
|
|
114
130
|
listDevices: () => listDevices,
|
|
115
131
|
listModules: () => listModules,
|
|
116
132
|
listRunningProcesses: () => listRunningProcesses,
|
|
117
133
|
listTemplates: () => listTemplates,
|
|
134
|
+
needsCmdWrapper: () => needsCmdWrapper,
|
|
118
135
|
nonInteractivePrompter: () => nonInteractivePrompter,
|
|
119
136
|
noopLogger: () => noopLogger,
|
|
120
137
|
noopProgress: () => noopProgress,
|
|
@@ -124,6 +141,8 @@ __export(index_exports, {
|
|
|
124
141
|
parseCodelinterFindings: () => parseCodelinterFindings,
|
|
125
142
|
parseDeviceList: () => parseDeviceList,
|
|
126
143
|
parseHilogLine: () => parseHilogLine,
|
|
144
|
+
parseMainAbilityFromBmDump: () => parseMainAbilityFromBmDump,
|
|
145
|
+
parseRemoteExit: () => parseRemoteExit,
|
|
127
146
|
pickSigningKind: () => pickSigningKind,
|
|
128
147
|
prepareSigning: () => prepareSigning,
|
|
129
148
|
pruneLayout: () => pruneLayout,
|
|
@@ -134,6 +153,8 @@ __export(index_exports, {
|
|
|
134
153
|
removeCmdTools: () => removeCmdTools,
|
|
135
154
|
removeEmulator: () => removeEmulator,
|
|
136
155
|
removeSdk: () => removeSdk,
|
|
156
|
+
removeTempWorkDir: () => removeTempWorkDir,
|
|
157
|
+
resolveTmpRoot: () => resolveTmpRoot,
|
|
137
158
|
runCodelinter: () => runCodelinter,
|
|
138
159
|
runHvigorw: () => runHvigorw,
|
|
139
160
|
runOhpm: () => runOhpm,
|
|
@@ -146,11 +167,15 @@ __export(index_exports, {
|
|
|
146
167
|
sendRawTouch: () => sendRawTouch,
|
|
147
168
|
setHilogLevel: () => setHilogLevel,
|
|
148
169
|
shell: () => shell,
|
|
170
|
+
shellChecked: () => shellChecked,
|
|
171
|
+
spawnCompat: () => spawnCompat,
|
|
149
172
|
startEmulator: () => startEmulator,
|
|
150
173
|
staticConfig: () => staticConfig,
|
|
151
174
|
stopEmulator: () => stopEmulator,
|
|
152
175
|
streamHilog: () => streamHilog,
|
|
153
176
|
takeScreenshot: () => takeScreenshot,
|
|
177
|
+
toLongPath: () => toLongPath,
|
|
178
|
+
toSpaceError: () => toSpaceError,
|
|
154
179
|
uninstallApp: () => uninstallApp,
|
|
155
180
|
validateTemplateLayout: () => validateTemplateLayout,
|
|
156
181
|
verifySha256: () => verifySha256,
|
|
@@ -159,6 +184,7 @@ __export(index_exports, {
|
|
|
159
184
|
waitForCondition: () => waitForCondition,
|
|
160
185
|
waitForLog: () => waitForLog,
|
|
161
186
|
watchLog: () => watchLog,
|
|
187
|
+
waypointsToRawEvents: () => waypointsToRawEvents,
|
|
162
188
|
writeJson5File: () => writeJson5File,
|
|
163
189
|
writeJsonFile: () => writeJsonFile
|
|
164
190
|
});
|
|
@@ -271,9 +297,9 @@ var CmdToolsNotInstalledError = class extends OniroError {
|
|
|
271
297
|
expectedPath;
|
|
272
298
|
};
|
|
273
299
|
var UnsupportedPlatformError = class extends OniroError {
|
|
274
|
-
constructor(
|
|
275
|
-
super(`Unsupported platform: ${
|
|
276
|
-
this.platform =
|
|
300
|
+
constructor(platform7) {
|
|
301
|
+
super(`Unsupported platform: ${platform7}.`);
|
|
302
|
+
this.platform = platform7;
|
|
277
303
|
this.name = "UnsupportedPlatformError";
|
|
278
304
|
}
|
|
279
305
|
platform;
|
|
@@ -288,6 +314,14 @@ var ChecksumMismatchError = class extends OniroError {
|
|
|
288
314
|
expected;
|
|
289
315
|
actual;
|
|
290
316
|
};
|
|
317
|
+
var InsufficientSpaceError = class extends OniroError {
|
|
318
|
+
constructor(message, dir, cause) {
|
|
319
|
+
super(message, cause);
|
|
320
|
+
this.dir = dir;
|
|
321
|
+
this.name = "InsufficientSpaceError";
|
|
322
|
+
}
|
|
323
|
+
dir;
|
|
324
|
+
};
|
|
291
325
|
var CancelledError = class extends OniroError {
|
|
292
326
|
constructor(message = "Operation cancelled.") {
|
|
293
327
|
super(message);
|
|
@@ -334,29 +368,29 @@ var OHOS_URL_BASE = "https://repo.huaweicloud.com/openharmony/os";
|
|
|
334
368
|
// src/sdk/platform.ts
|
|
335
369
|
var os2 = __toESM(require("os"), 1);
|
|
336
370
|
function getOsFolder() {
|
|
337
|
-
const
|
|
338
|
-
if (
|
|
339
|
-
if (
|
|
340
|
-
if (
|
|
341
|
-
throw new UnsupportedPlatformError(
|
|
371
|
+
const platform7 = os2.platform();
|
|
372
|
+
if (platform7 === "linux") return "linux";
|
|
373
|
+
if (platform7 === "darwin") return "darwin";
|
|
374
|
+
if (platform7 === "win32") return "windows";
|
|
375
|
+
throw new UnsupportedPlatformError(platform7);
|
|
342
376
|
}
|
|
343
377
|
function getSdkFilename(version) {
|
|
344
|
-
const
|
|
378
|
+
const platform7 = os2.platform();
|
|
345
379
|
const v = version ?? ALL_SDKS[ALL_SDKS.length - 1].version;
|
|
346
380
|
const strips = ALL_SDKS.find((r) => r.version === v)?.tarballStrip ?? { linuxWindows: 1, darwin: 3 };
|
|
347
|
-
if (
|
|
381
|
+
if (platform7 === "linux") {
|
|
348
382
|
return { filename: "ohos-sdk-windows_linux-public.tar.gz", osFolder: "linux", strip: strips.linuxWindows };
|
|
349
383
|
}
|
|
350
|
-
if (
|
|
384
|
+
if (platform7 === "darwin") {
|
|
351
385
|
if (os2.arch() === "arm64") {
|
|
352
386
|
return { filename: "L2-SDK-MAC-M1-PUBLIC.tar.gz", osFolder: "darwin", strip: strips.darwin };
|
|
353
387
|
}
|
|
354
388
|
return { filename: "ohos-sdk-mac-public.tar.gz", osFolder: "darwin", strip: strips.darwin };
|
|
355
389
|
}
|
|
356
|
-
if (
|
|
390
|
+
if (platform7 === "win32") {
|
|
357
391
|
return { filename: "ohos-sdk-windows_linux-public.tar.gz", osFolder: "windows", strip: strips.linuxWindows };
|
|
358
392
|
}
|
|
359
|
-
throw new UnsupportedPlatformError(
|
|
393
|
+
throw new UnsupportedPlatformError(platform7);
|
|
360
394
|
}
|
|
361
395
|
|
|
362
396
|
// src/sdk/paths.ts
|
|
@@ -375,6 +409,14 @@ function getCmdToolsPath(config) {
|
|
|
375
409
|
function getEmulatorDir(config) {
|
|
376
410
|
return config.get("emulatorDir", defaultPaths.emulatorDir());
|
|
377
411
|
}
|
|
412
|
+
function toLongPath(p, platform7 = os3.platform()) {
|
|
413
|
+
if (platform7 !== "win32") return p;
|
|
414
|
+
try {
|
|
415
|
+
return fs.realpathSync.native(p);
|
|
416
|
+
} catch {
|
|
417
|
+
return p;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
378
420
|
function pickExisting(candidates) {
|
|
379
421
|
for (const c of candidates) {
|
|
380
422
|
if (fs.existsSync(c)) return c;
|
|
@@ -397,6 +439,8 @@ function getOhpmPath(config) {
|
|
|
397
439
|
return getCmdToolsBin(config, "ohpm");
|
|
398
440
|
}
|
|
399
441
|
function getHdcPath(config) {
|
|
442
|
+
const override = config.get("hdcPath", "");
|
|
443
|
+
if (override) return override;
|
|
400
444
|
const base = path2.join(getCmdToolsPath(config), "sdk", "default", "openharmony", "toolchains");
|
|
401
445
|
if (os3.platform() === "win32") {
|
|
402
446
|
return pickExisting([
|
|
@@ -408,12 +452,11 @@ function getHdcPath(config) {
|
|
|
408
452
|
}
|
|
409
453
|
return path2.join(base, "hdc");
|
|
410
454
|
}
|
|
411
|
-
function getHvigorwPath(config, projectDir) {
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
]);
|
|
455
|
+
function getHvigorwPath(config, projectDir, platform7 = os3.platform()) {
|
|
456
|
+
const posixFirst = ["hvigorw", "hvigorw.bat", "hvigorw.cmd"];
|
|
457
|
+
const windowsFirst = ["hvigorw.bat", "hvigorw.cmd", "hvigorw"];
|
|
458
|
+
const names = platform7 === "win32" ? windowsFirst : posixFirst;
|
|
459
|
+
const local = pickExisting(names.map((n) => path2.join(projectDir, n)));
|
|
417
460
|
if (fs.existsSync(local) && isProjectLocalHvigorwWorking(projectDir)) {
|
|
418
461
|
return local;
|
|
419
462
|
}
|
|
@@ -447,8 +490,164 @@ function detectProjectSdkVersion(projectRoot, logger = noopLogger) {
|
|
|
447
490
|
}
|
|
448
491
|
}
|
|
449
492
|
|
|
450
|
-
// src/sdk/
|
|
493
|
+
// src/sdk/tmp.ts
|
|
451
494
|
var fs3 = __toESM(require("fs"), 1);
|
|
495
|
+
var os4 = __toESM(require("os"), 1);
|
|
496
|
+
var path4 = __toESM(require("path"), 1);
|
|
497
|
+
var INSTALL_TMP_DIRNAME = ".oniro-tmp";
|
|
498
|
+
var TMPFS_MAGIC = 16914836;
|
|
499
|
+
var RAMFS_MAGIC = 2240043254;
|
|
500
|
+
var HINT_EXAMPLE = os4.platform() === "win32" ? "D:\\oniro-tmp" : "~/.cache/oniro-tmp";
|
|
501
|
+
var TMP_DIR_HINT = `Point the scratch directory at a filesystem with more room using --tmp-dir <path> (or the ONIRO_TMP_DIR environment variable), e.g. --tmp-dir ${HINT_EXAMPLE}.`;
|
|
502
|
+
function resolveTmpRoot(config, override, installRoot) {
|
|
503
|
+
const explicit = (override ?? "").trim();
|
|
504
|
+
if (explicit) return path4.resolve(explicit);
|
|
505
|
+
const configured = config.get("tmpDir", "").trim();
|
|
506
|
+
if (configured) return path4.resolve(configured);
|
|
507
|
+
if (installRoot) return path4.join(path4.resolve(installRoot), INSTALL_TMP_DIRNAME);
|
|
508
|
+
return os4.tmpdir();
|
|
509
|
+
}
|
|
510
|
+
function createTempWorkDir(root, prefix) {
|
|
511
|
+
try {
|
|
512
|
+
fs3.mkdirSync(root, { recursive: true });
|
|
513
|
+
return fs3.mkdtempSync(path4.join(root, prefix));
|
|
514
|
+
} catch (err) {
|
|
515
|
+
if (isOutOfSpaceError(err)) throw toSpaceError(err, root, "a temporary directory");
|
|
516
|
+
throw new OniroError(
|
|
517
|
+
`Cannot create a temporary directory in '${root}': ${err instanceof Error ? err.message : String(err)}
|
|
518
|
+
${TMP_DIR_HINT}`,
|
|
519
|
+
err
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
function removeTempWorkDir(dir, root) {
|
|
524
|
+
fs3.rmSync(dir, { recursive: true, force: true });
|
|
525
|
+
if (!root || path4.basename(root) !== INSTALL_TMP_DIRNAME) return;
|
|
526
|
+
try {
|
|
527
|
+
fs3.rmdirSync(root);
|
|
528
|
+
} catch {
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
function createInstallTempDir(opts) {
|
|
532
|
+
const requested = (opts.override ?? "").trim() || opts.config.get("tmpDir", "").trim();
|
|
533
|
+
const root = resolveTmpRoot(opts.config, opts.override, opts.installRoot);
|
|
534
|
+
try {
|
|
535
|
+
return { dir: createTempWorkDir(root, opts.prefix), root };
|
|
536
|
+
} catch (err) {
|
|
537
|
+
const fallback = os4.tmpdir();
|
|
538
|
+
if (requested || isOutOfSpaceError(err) || path4.resolve(fallback) === path4.resolve(root)) throw err;
|
|
539
|
+
const reason = err instanceof Error ? err.message.split("\n")[0] : String(err);
|
|
540
|
+
(opts.logger ?? noopLogger).warn(`${reason} Falling back to '${fallback}'.`);
|
|
541
|
+
return { dir: createTempWorkDir(fallback, opts.prefix), root: fallback };
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
function nearestExisting(dir) {
|
|
545
|
+
let current = path4.resolve(dir);
|
|
546
|
+
for (; ; ) {
|
|
547
|
+
if (fs3.existsSync(current)) return current;
|
|
548
|
+
const parent = path4.dirname(current);
|
|
549
|
+
if (parent === current) return null;
|
|
550
|
+
current = parent;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
function getFreeSpaceBytes(dir) {
|
|
554
|
+
const target = nearestExisting(dir);
|
|
555
|
+
if (!target) return null;
|
|
556
|
+
try {
|
|
557
|
+
const stats = fs3.statfsSync(target);
|
|
558
|
+
return Number(stats.bsize) * Number(stats.bavail);
|
|
559
|
+
} catch {
|
|
560
|
+
return null;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
function isRamBackedPath(dir) {
|
|
564
|
+
const target = nearestExisting(dir);
|
|
565
|
+
if (!target) return false;
|
|
566
|
+
try {
|
|
567
|
+
const type = Number(fs3.statfsSync(target).type);
|
|
568
|
+
return type === TMPFS_MAGIC || type === RAMFS_MAGIC;
|
|
569
|
+
} catch {
|
|
570
|
+
return false;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
function formatBytes(bytes) {
|
|
574
|
+
const units = ["B", "KiB", "MiB", "GiB", "TiB"];
|
|
575
|
+
let value = Math.max(0, bytes);
|
|
576
|
+
let unit = 0;
|
|
577
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
578
|
+
value /= 1024;
|
|
579
|
+
unit++;
|
|
580
|
+
}
|
|
581
|
+
return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;
|
|
582
|
+
}
|
|
583
|
+
function isOutOfSpaceError(err) {
|
|
584
|
+
if (err instanceof InsufficientSpaceError) return true;
|
|
585
|
+
const seen = /* @__PURE__ */ new Set();
|
|
586
|
+
let current = err;
|
|
587
|
+
while (current && typeof current === "object" && !seen.has(current)) {
|
|
588
|
+
seen.add(current);
|
|
589
|
+
const e = current;
|
|
590
|
+
if (e.code === "ENOSPC" || e.code === "EDQUOT") return true;
|
|
591
|
+
if (typeof e.message === "string" && /ENOSPC|EDQUOT|no space left on device/i.test(e.message)) return true;
|
|
592
|
+
current = e.cause;
|
|
593
|
+
}
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
function spaceMessage(dir, what, opts) {
|
|
597
|
+
const need = typeof opts.requiredBytes === "number" ? `needs about ${formatBytes(opts.requiredBytes)}` : null;
|
|
598
|
+
const free = typeof opts.freeBytes === "number" ? `${formatBytes(opts.freeBytes)} available` : null;
|
|
599
|
+
const amounts = [need, free].filter(Boolean).join(", ");
|
|
600
|
+
const lines = [`Not enough free space in '${dir}' for ${what}${amounts ? ` (${amounts})` : ""}.`];
|
|
601
|
+
if (isRamBackedPath(dir)) {
|
|
602
|
+
lines.push(
|
|
603
|
+
`'${dir}' is on a RAM-backed filesystem (tmpfs), so its capacity is limited by free memory, not by free disk.`
|
|
604
|
+
);
|
|
605
|
+
}
|
|
606
|
+
if (opts.tmpDirHint) lines.push(TMP_DIR_HINT);
|
|
607
|
+
return lines.join("\n");
|
|
608
|
+
}
|
|
609
|
+
function ensureFreeSpace(dir, requiredBytes, what) {
|
|
610
|
+
if (!Number.isFinite(requiredBytes) || requiredBytes <= 0) return;
|
|
611
|
+
const freeBytes = getFreeSpaceBytes(dir);
|
|
612
|
+
if (freeBytes === null || freeBytes >= requiredBytes) return;
|
|
613
|
+
throw new InsufficientSpaceError(
|
|
614
|
+
spaceMessage(dir, what, { requiredBytes, freeBytes, tmpDirHint: true }),
|
|
615
|
+
dir
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
function errorPath(err) {
|
|
619
|
+
const seen = /* @__PURE__ */ new Set();
|
|
620
|
+
let current = err;
|
|
621
|
+
while (current && typeof current === "object" && !seen.has(current)) {
|
|
622
|
+
seen.add(current);
|
|
623
|
+
const e = current;
|
|
624
|
+
if (typeof e.path === "string" && e.path) return e.path;
|
|
625
|
+
if (typeof e.dest === "string" && e.dest) return e.dest;
|
|
626
|
+
current = e.cause;
|
|
627
|
+
}
|
|
628
|
+
return null;
|
|
629
|
+
}
|
|
630
|
+
function isInside(child, parent) {
|
|
631
|
+
const rel = path4.relative(path4.resolve(parent), path4.resolve(child));
|
|
632
|
+
return rel === "" || !rel.startsWith("..") && !path4.isAbsolute(rel);
|
|
633
|
+
}
|
|
634
|
+
function toSpaceError(err, tmpRoot, what) {
|
|
635
|
+
if (err instanceof InsufficientSpaceError) return err;
|
|
636
|
+
if (!isOutOfSpaceError(err)) return err;
|
|
637
|
+
const failed = errorPath(err);
|
|
638
|
+
const failedDir = failed ? path4.dirname(path4.resolve(failed)) : path4.resolve(tmpRoot);
|
|
639
|
+
const inTmp = isInside(failedDir, tmpRoot);
|
|
640
|
+
const dir = inTmp ? path4.resolve(tmpRoot) : failedDir;
|
|
641
|
+
return new InsufficientSpaceError(
|
|
642
|
+
spaceMessage(dir, what, { freeBytes: getFreeSpaceBytes(dir), tmpDirHint: inTmp }),
|
|
643
|
+
dir,
|
|
644
|
+
err
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// src/sdk/download.ts
|
|
649
|
+
var fs4 = __toESM(require("fs"), 1);
|
|
650
|
+
var path5 = __toESM(require("path"), 1);
|
|
452
651
|
var crypto = __toESM(require("crypto"), 1);
|
|
453
652
|
var import_node_stream = require("stream");
|
|
454
653
|
var import_node_util = require("util");
|
|
@@ -458,36 +657,57 @@ var pipelineAsync = (0, import_node_util.promisify)(import_node_stream.pipeline)
|
|
|
458
657
|
async function downloadFile(opts) {
|
|
459
658
|
const { url, dest, progress, abortSignal } = opts;
|
|
460
659
|
const proto = url.startsWith("https") ? https : http;
|
|
461
|
-
return new Promise((
|
|
660
|
+
return new Promise((resolve4, reject) => {
|
|
462
661
|
const s = Math.max(0, Math.min(100, opts.start ?? 0));
|
|
463
662
|
const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));
|
|
464
663
|
let settled = false;
|
|
465
664
|
const done = (err) => {
|
|
466
665
|
if (settled) return;
|
|
467
666
|
settled = true;
|
|
468
|
-
err ? reject(err) :
|
|
667
|
+
err ? reject(err) : resolve4();
|
|
469
668
|
};
|
|
470
669
|
if (abortSignal?.aborted) {
|
|
471
670
|
done(new CancelledError("Download cancelled before start."));
|
|
472
671
|
return;
|
|
473
672
|
}
|
|
474
|
-
const
|
|
673
|
+
const destDir = path5.dirname(path5.resolve(dest));
|
|
674
|
+
const what = opts.what ?? `the download of '${url}'`;
|
|
675
|
+
const writeFailed = (err) => isOutOfSpaceError(err) ? toSpaceError(err, opts.tmpRoot ?? destDir, what) : new OniroError(`Error writing '${dest}': ${err instanceof Error ? err.message : String(err)}`, err);
|
|
676
|
+
const file = fs4.createWriteStream(dest);
|
|
677
|
+
let activeResponse;
|
|
678
|
+
const failWith = (err) => {
|
|
679
|
+
file.close(() => fs4.rm(dest, { force: true }, () => done(err)));
|
|
680
|
+
};
|
|
681
|
+
file.on("error", (err) => {
|
|
682
|
+
try {
|
|
683
|
+
activeResponse?.destroy?.();
|
|
684
|
+
} catch {
|
|
685
|
+
}
|
|
686
|
+
failWith(writeFailed(err));
|
|
687
|
+
});
|
|
475
688
|
const req = proto.get(url, (response) => {
|
|
689
|
+
activeResponse = response;
|
|
476
690
|
if (response.statusCode !== 200) {
|
|
477
691
|
try {
|
|
478
692
|
response.destroy();
|
|
479
693
|
} catch {
|
|
480
694
|
}
|
|
481
|
-
|
|
482
|
-
file.close();
|
|
483
|
-
} catch {
|
|
484
|
-
}
|
|
485
|
-
fs3.unlink(dest, () => {
|
|
486
|
-
});
|
|
487
|
-
done(new OniroError(`Failed to download '${url}' (HTTP ${response.statusCode})`));
|
|
695
|
+
failWith(new OniroError(`Failed to download '${url}' (HTTP ${response.statusCode})`));
|
|
488
696
|
return;
|
|
489
697
|
}
|
|
490
698
|
const total = parseInt(response.headers["content-length"] || "0", 10);
|
|
699
|
+
if (total > 0) {
|
|
700
|
+
try {
|
|
701
|
+
ensureFreeSpace(opts.tmpRoot ?? destDir, total, what);
|
|
702
|
+
} catch (err) {
|
|
703
|
+
try {
|
|
704
|
+
response.destroy();
|
|
705
|
+
} catch {
|
|
706
|
+
}
|
|
707
|
+
failWith(err);
|
|
708
|
+
return;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
491
711
|
let downloaded = 0;
|
|
492
712
|
let lastOverall = Math.round(s);
|
|
493
713
|
response.on("data", (chunk) => {
|
|
@@ -511,38 +731,26 @@ async function downloadFile(opts) {
|
|
|
511
731
|
const inc = endOverall - lastOverall;
|
|
512
732
|
if (inc > 0) progress.report({ message: "Downloading: 100%", increment: inc });
|
|
513
733
|
}
|
|
514
|
-
file.close((err) => err ? done(err) : done());
|
|
734
|
+
file.close((err) => err ? done(writeFailed(err)) : done());
|
|
515
735
|
});
|
|
516
736
|
abortSignal?.addEventListener("abort", () => {
|
|
517
737
|
response.destroy();
|
|
518
|
-
|
|
519
|
-
fs3.unlink(dest, () => {
|
|
520
|
-
});
|
|
521
|
-
done(new CancelledError("Download cancelled."));
|
|
738
|
+
failWith(new CancelledError("Download cancelled."));
|
|
522
739
|
});
|
|
523
740
|
});
|
|
524
741
|
req.on("error", (err) => {
|
|
525
|
-
|
|
526
|
-
file.close();
|
|
527
|
-
} catch {
|
|
528
|
-
}
|
|
529
|
-
fs3.unlink(dest, () => {
|
|
530
|
-
});
|
|
531
|
-
done(new OniroError(`Error downloading '${url}': ${err.message}`, err));
|
|
742
|
+
failWith(new OniroError(`Error downloading '${url}': ${err.message}`, err));
|
|
532
743
|
});
|
|
533
744
|
abortSignal?.addEventListener("abort", () => {
|
|
534
745
|
req.destroy();
|
|
535
|
-
|
|
536
|
-
fs3.unlink(dest, () => {
|
|
537
|
-
});
|
|
538
|
-
done(new CancelledError("Download cancelled."));
|
|
746
|
+
failWith(new CancelledError("Download cancelled."));
|
|
539
747
|
});
|
|
540
748
|
});
|
|
541
749
|
}
|
|
542
750
|
async function verifySha256(filePath, sha256Path) {
|
|
543
|
-
const expected =
|
|
751
|
+
const expected = fs4.readFileSync(sha256Path, "utf8").split(/\s+/)[0];
|
|
544
752
|
const hash = crypto.createHash("sha256");
|
|
545
|
-
await pipelineAsync(
|
|
753
|
+
await pipelineAsync(fs4.createReadStream(filePath), hash);
|
|
546
754
|
const actual = hash.digest("hex");
|
|
547
755
|
if (actual !== expected) {
|
|
548
756
|
throw new ChecksumMismatchError(expected, actual);
|
|
@@ -550,9 +758,9 @@ async function verifySha256(filePath, sha256Path) {
|
|
|
550
758
|
}
|
|
551
759
|
|
|
552
760
|
// src/sdk/extract.ts
|
|
553
|
-
var
|
|
554
|
-
var
|
|
555
|
-
var
|
|
761
|
+
var fs5 = __toESM(require("fs"), 1);
|
|
762
|
+
var os5 = __toESM(require("os"), 1);
|
|
763
|
+
var path6 = __toESM(require("path"), 1);
|
|
556
764
|
var import_node_stream2 = require("stream");
|
|
557
765
|
var import_node_util2 = require("util");
|
|
558
766
|
var tar = __toESM(require("tar"), 1);
|
|
@@ -569,12 +777,12 @@ async function extractZipWithProgress(opts) {
|
|
|
569
777
|
const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));
|
|
570
778
|
let processed = 0;
|
|
571
779
|
let lastOverall = Math.round(s);
|
|
572
|
-
await
|
|
573
|
-
const destRoot =
|
|
780
|
+
await fs5.promises.mkdir(dest, { recursive: true });
|
|
781
|
+
const destRoot = path6.resolve(dest);
|
|
574
782
|
const safeResolveTarget = (entryName) => {
|
|
575
|
-
const resolved =
|
|
576
|
-
const rel =
|
|
577
|
-
if (rel.startsWith("..") ||
|
|
783
|
+
const resolved = path6.resolve(destRoot, entryName);
|
|
784
|
+
const rel = path6.relative(destRoot, resolved);
|
|
785
|
+
if (rel.startsWith("..") || path6.isAbsolute(rel)) {
|
|
578
786
|
throw new OniroError(`Blocked ZIP entry with illegal path: ${entryName}`);
|
|
579
787
|
}
|
|
580
788
|
return resolved;
|
|
@@ -586,25 +794,25 @@ async function extractZipWithProgress(opts) {
|
|
|
586
794
|
const attr = file.attr ? file.attr >>> 16 : 0;
|
|
587
795
|
const isSymlink = "isSymbolicLink" in file ? Boolean(file.isSymbolicLink) : (attr & 61440) === 40960;
|
|
588
796
|
if (file.isDirectory) {
|
|
589
|
-
await
|
|
797
|
+
await fs5.promises.mkdir(targetPath, { recursive: true });
|
|
590
798
|
} else if (isSymlink) {
|
|
591
|
-
await
|
|
799
|
+
await fs5.promises.mkdir(path6.dirname(targetPath), { recursive: true });
|
|
592
800
|
const linkTargetBuffer = await zip.entryData(file);
|
|
593
801
|
const linkTarget = linkTargetBuffer.toString("utf8");
|
|
594
802
|
try {
|
|
595
|
-
const isWin =
|
|
596
|
-
await
|
|
803
|
+
const isWin = os5.platform() === "win32";
|
|
804
|
+
await fs5.promises.symlink(linkTarget, targetPath, isWin ? "file" : void 0);
|
|
597
805
|
} catch (e) {
|
|
598
806
|
logger.warn(`Failed to create symlink at ${targetPath}: ${String(e)}`);
|
|
599
807
|
}
|
|
600
808
|
} else {
|
|
601
|
-
await
|
|
809
|
+
await fs5.promises.mkdir(path6.dirname(targetPath), { recursive: true });
|
|
602
810
|
const readStream = await zip.stream(file);
|
|
603
|
-
const writeStream =
|
|
811
|
+
const writeStream = fs5.createWriteStream(targetPath);
|
|
604
812
|
await pipelineAsync2(readStream, writeStream);
|
|
605
813
|
if (attr > 0) {
|
|
606
814
|
try {
|
|
607
|
-
await
|
|
815
|
+
await fs5.promises.chmod(targetPath, attr & 511);
|
|
608
816
|
} catch {
|
|
609
817
|
}
|
|
610
818
|
}
|
|
@@ -636,41 +844,41 @@ async function extractTarball(tarPath, dest, strip = 0) {
|
|
|
636
844
|
}
|
|
637
845
|
|
|
638
846
|
// src/sdk/list.ts
|
|
639
|
-
var
|
|
640
|
-
var
|
|
847
|
+
var fs6 = __toESM(require("fs"), 1);
|
|
848
|
+
var path7 = __toESM(require("path"), 1);
|
|
641
849
|
function getSupportedSdksForUi(config) {
|
|
642
|
-
const base =
|
|
850
|
+
const base = path7.join(getSdkRootDir(config), getOsFolder());
|
|
643
851
|
return ALL_SDKS.map((sdk) => ({
|
|
644
852
|
version: sdk.version,
|
|
645
853
|
api: sdk.api,
|
|
646
|
-
installed:
|
|
854
|
+
installed: fs6.existsSync(path7.join(base, sdk.api))
|
|
647
855
|
})).sort((a, b) => Number(b.api) - Number(a.api));
|
|
648
856
|
}
|
|
649
857
|
function getInstalledSdks(config) {
|
|
650
858
|
const sdkRoot = getSdkRootDir(config);
|
|
651
859
|
const versions = /* @__PURE__ */ new Set();
|
|
652
|
-
if (!
|
|
860
|
+
if (!fs6.existsSync(sdkRoot)) return [];
|
|
653
861
|
for (const osFolder of ["linux", "darwin", "windows"]) {
|
|
654
|
-
const osPath =
|
|
655
|
-
if (!
|
|
656
|
-
for (const api of
|
|
657
|
-
const apiPath =
|
|
658
|
-
if (
|
|
862
|
+
const osPath = path7.join(sdkRoot, osFolder);
|
|
863
|
+
if (!fs6.existsSync(osPath) || !fs6.statSync(osPath).isDirectory()) continue;
|
|
864
|
+
for (const api of fs6.readdirSync(osPath)) {
|
|
865
|
+
const apiPath = path7.join(osPath, api);
|
|
866
|
+
if (fs6.statSync(apiPath).isDirectory()) versions.add(api);
|
|
659
867
|
}
|
|
660
868
|
}
|
|
661
869
|
return ALL_SDKS.filter((sdk) => versions.has(sdk.api)).map((sdk) => sdk.version);
|
|
662
870
|
}
|
|
663
871
|
|
|
664
872
|
// src/sdk/remove.ts
|
|
665
|
-
var
|
|
666
|
-
var
|
|
873
|
+
var fs7 = __toESM(require("fs"), 1);
|
|
874
|
+
var path8 = __toESM(require("path"), 1);
|
|
667
875
|
function removeSdk(config, api) {
|
|
668
876
|
const sdkRoot = getSdkRootDir(config);
|
|
669
877
|
let removed = false;
|
|
670
878
|
for (const osFolder of ["linux", "darwin", "windows"]) {
|
|
671
|
-
const sdkPath =
|
|
672
|
-
if (
|
|
673
|
-
|
|
879
|
+
const sdkPath = path8.join(sdkRoot, osFolder, api);
|
|
880
|
+
if (fs7.existsSync(sdkPath)) {
|
|
881
|
+
fs7.rmSync(sdkPath, { recursive: true, force: true });
|
|
674
882
|
removed = true;
|
|
675
883
|
}
|
|
676
884
|
}
|
|
@@ -678,19 +886,18 @@ function removeSdk(config, api) {
|
|
|
678
886
|
}
|
|
679
887
|
|
|
680
888
|
// src/sdk/install.ts
|
|
681
|
-
var
|
|
682
|
-
var
|
|
683
|
-
var path7 = __toESM(require("path"), 1);
|
|
889
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
890
|
+
var path9 = __toESM(require("path"), 1);
|
|
684
891
|
|
|
685
892
|
// src/sdk/move.ts
|
|
686
|
-
var
|
|
893
|
+
var fs8 = __toESM(require("fs"), 1);
|
|
687
894
|
function movePath(src, dest) {
|
|
688
895
|
try {
|
|
689
|
-
|
|
896
|
+
fs8.renameSync(src, dest);
|
|
690
897
|
} catch (err) {
|
|
691
898
|
if (err.code !== "EXDEV") throw err;
|
|
692
|
-
|
|
693
|
-
|
|
899
|
+
fs8.cpSync(src, dest, { recursive: true });
|
|
900
|
+
fs8.rmSync(src, { recursive: true, force: true });
|
|
694
901
|
}
|
|
695
902
|
}
|
|
696
903
|
|
|
@@ -702,21 +909,29 @@ async function downloadAndInstallSdk(opts) {
|
|
|
702
909
|
const urlBase = config.get("sdkUrlBase", OHOS_URL_BASE);
|
|
703
910
|
const downloadUrl = `${urlBase}/${version}-Release/${filename}`;
|
|
704
911
|
const sha256Url = `${downloadUrl}.sha256`;
|
|
705
|
-
const
|
|
706
|
-
const
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
912
|
+
const what = `the SDK ${version} install`;
|
|
913
|
+
const sdkRoot = getSdkRootDir(config);
|
|
914
|
+
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
915
|
+
config,
|
|
916
|
+
override: opts.tmpDir,
|
|
917
|
+
installRoot: sdkRoot,
|
|
918
|
+
prefix: "oniro-sdk-",
|
|
919
|
+
logger
|
|
920
|
+
});
|
|
921
|
+
const tarPath = path9.join(tmpDir, filename);
|
|
922
|
+
const sha256Path = path9.join(tmpDir, `${filename}.sha256`);
|
|
923
|
+
const extractDir = path9.join(tmpDir, "extract");
|
|
924
|
+
fs9.mkdirSync(extractDir);
|
|
925
|
+
const sdkInstallDir = path9.join(sdkRoot, osFolder, api);
|
|
926
|
+
fs9.mkdirSync(path9.dirname(sdkInstallDir), { recursive: true });
|
|
712
927
|
const checkCancelled = () => {
|
|
713
928
|
if (abortSignal?.aborted) throw new CancelledError();
|
|
714
929
|
};
|
|
715
930
|
try {
|
|
716
931
|
progress?.report({ message: "Downloading SDK archive...", increment: 0 });
|
|
717
|
-
await downloadFile({ url: downloadUrl, dest: tarPath, progress, abortSignal, start: 0, range: 35 });
|
|
932
|
+
await downloadFile({ url: downloadUrl, dest: tarPath, progress, abortSignal, start: 0, range: 35, what, tmpRoot });
|
|
718
933
|
progress?.report({ message: "Downloading checksum...", increment: 0 });
|
|
719
|
-
await downloadFile({ url: sha256Url, dest: sha256Path, progress, abortSignal, start: 35, range: 10 });
|
|
934
|
+
await downloadFile({ url: sha256Url, dest: sha256Path, progress, abortSignal, start: 35, range: 10, what, tmpRoot });
|
|
720
935
|
progress?.report({ message: "Verifying checksum...", increment: 0 });
|
|
721
936
|
await verifySha256(tarPath, sha256Path);
|
|
722
937
|
progress?.report({ message: "Verifying checksum...", increment: 5 });
|
|
@@ -725,13 +940,13 @@ async function downloadAndInstallSdk(opts) {
|
|
|
725
940
|
await extractTarball(tarPath, extractDir, strip);
|
|
726
941
|
progress?.report({ message: "Extracting SDK (this may take a while)...", increment: 10 });
|
|
727
942
|
checkCancelled();
|
|
728
|
-
const osContentPath =
|
|
729
|
-
if (!
|
|
943
|
+
const osContentPath = path9.join(extractDir, osFolder);
|
|
944
|
+
if (!fs9.existsSync(osContentPath)) {
|
|
730
945
|
throw new OniroError(
|
|
731
946
|
`Expected folder '${osFolder}' not found in extracted SDK. Tarball layout may have changed.`
|
|
732
947
|
);
|
|
733
948
|
}
|
|
734
|
-
const zipFiles =
|
|
949
|
+
const zipFiles = fs9.readdirSync(osContentPath).filter((n2) => n2.endsWith(".zip"));
|
|
735
950
|
const componentsStart = 60;
|
|
736
951
|
const componentsBudget = 35;
|
|
737
952
|
const n = zipFiles.length;
|
|
@@ -746,39 +961,114 @@ async function downloadAndInstallSdk(opts) {
|
|
|
746
961
|
for (const zipFile of zipFiles) {
|
|
747
962
|
checkCancelled();
|
|
748
963
|
logger.info(`Extracting component ${zipFile}`);
|
|
749
|
-
const zipPath =
|
|
964
|
+
const zipPath = path9.join(osContentPath, zipFile);
|
|
750
965
|
const thisBudget = base + (rem > 0 ? 1 : 0);
|
|
751
966
|
if (rem > 0) rem--;
|
|
752
967
|
await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });
|
|
753
968
|
cursor += thisBudget;
|
|
754
|
-
|
|
969
|
+
fs9.unlinkSync(zipPath);
|
|
755
970
|
}
|
|
756
971
|
progress?.report({ message: "Finalizing installation...", increment: 0 });
|
|
757
|
-
if (
|
|
758
|
-
|
|
972
|
+
if (fs9.existsSync(sdkInstallDir)) {
|
|
973
|
+
fs9.rmSync(sdkInstallDir, { recursive: true, force: true });
|
|
759
974
|
}
|
|
760
975
|
movePath(osContentPath, sdkInstallDir);
|
|
761
976
|
progress?.report({ message: "Finalizing installation...", increment: 3 });
|
|
762
977
|
progress?.report({ message: "Cleaning up...", increment: 0 });
|
|
763
|
-
|
|
978
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
764
979
|
progress?.report({ message: "Cleaning up...", increment: 2 });
|
|
765
980
|
} catch (err) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
981
|
+
const wrapped = toSpaceError(err, tmpRoot, what);
|
|
982
|
+
logger.error(`SDK install failed: ${wrapped instanceof Error ? wrapped.message : String(wrapped)}`);
|
|
983
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
984
|
+
throw wrapped;
|
|
769
985
|
}
|
|
770
986
|
}
|
|
771
987
|
|
|
772
988
|
// src/cmdTools/install.ts
|
|
773
|
-
var
|
|
989
|
+
var fs10 = __toESM(require("fs"), 1);
|
|
774
990
|
var os6 = __toESM(require("os"), 1);
|
|
775
|
-
var
|
|
991
|
+
var path11 = __toESM(require("path"), 1);
|
|
992
|
+
var import_node_child_process2 = require("child_process");
|
|
993
|
+
|
|
994
|
+
// src/hdc/spawnCompat.ts
|
|
995
|
+
var path10 = __toESM(require("path"), 1);
|
|
776
996
|
var import_node_child_process = require("child_process");
|
|
777
|
-
|
|
778
|
-
|
|
997
|
+
var WINDOWS_BATCH_RE = /\.(bat|cmd)$/i;
|
|
998
|
+
var CMD_META_RE = /([()[\]%!^"`<>&|;, *?])/g;
|
|
999
|
+
var CMD_SHIM_RE = /node_modules[\\/]\.bin[\\/][^\\/]+\.cmd$/i;
|
|
1000
|
+
var UNSAFE_CMD_CHARS_RE = /["\r\n\0]/;
|
|
1001
|
+
function needsCmdWrapper(command, platform7 = process.platform) {
|
|
1002
|
+
return platform7 === "win32" && WINDOWS_BATCH_RE.test(command);
|
|
1003
|
+
}
|
|
1004
|
+
function escapeCmdArgument(arg, doubleEscapeMetaChars = false) {
|
|
1005
|
+
let out = String(arg);
|
|
1006
|
+
out = out.replace(/(\\*)"/g, '$1$1\\"');
|
|
1007
|
+
out = out.replace(/(\\*)$/, "$1$1");
|
|
1008
|
+
out = `"${out}"`;
|
|
1009
|
+
out = out.replace(CMD_META_RE, "^$1");
|
|
1010
|
+
if (doubleEscapeMetaChars) out = out.replace(CMD_META_RE, "^$1");
|
|
1011
|
+
return out;
|
|
1012
|
+
}
|
|
1013
|
+
function escapeCmdCommand(command) {
|
|
1014
|
+
return command.replace(CMD_META_RE, "^$1");
|
|
1015
|
+
}
|
|
1016
|
+
function buildCmdWrapper(command, args) {
|
|
1017
|
+
assertCmdSafe(command, `command ${command}`);
|
|
1018
|
+
args.forEach((a, i) => assertCmdSafe(a, `argument ${i} (${a})`));
|
|
1019
|
+
const normalized = path10.normalize(command);
|
|
1020
|
+
const double = CMD_SHIM_RE.test(normalized);
|
|
1021
|
+
const line = [escapeCmdCommand(normalized), ...args.map((a) => escapeCmdArgument(a, double))].join(" ");
|
|
1022
|
+
return {
|
|
1023
|
+
command: process.env.ComSpec ?? process.env.COMSPEC ?? "cmd.exe",
|
|
1024
|
+
args: ["/d", "/s", "/c", `"${line}"`]
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
function assertCmdSafe(value, label) {
|
|
1028
|
+
if (UNSAFE_CMD_CHARS_RE.test(value)) {
|
|
1029
|
+
throw new OniroError(
|
|
1030
|
+
`Cannot run a Windows batch wrapper with a quote, newline or NUL in the ${label}: cmd.exe cannot pass it through unambiguously.`
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
function spawnCompat(command, args, options = {}) {
|
|
1035
|
+
if (!needsCmdWrapper(command)) {
|
|
1036
|
+
return (0, import_node_child_process.spawn)(command, [...args], { ...options, shell: false });
|
|
1037
|
+
}
|
|
1038
|
+
const wrapped = buildCmdWrapper(command, args);
|
|
1039
|
+
return (0, import_node_child_process.spawn)(wrapped.command, wrapped.args, {
|
|
1040
|
+
...options,
|
|
1041
|
+
shell: false,
|
|
1042
|
+
// The line is already escaped; stop Node from re-quoting it.
|
|
1043
|
+
windowsVerbatimArguments: true
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
function killProcessTree(child) {
|
|
1047
|
+
if (process.platform === "win32" && typeof child.pid === "number") {
|
|
1048
|
+
try {
|
|
1049
|
+
const killer = (0, import_node_child_process.spawn)("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore" });
|
|
1050
|
+
killer.on("error", () => {
|
|
1051
|
+
try {
|
|
1052
|
+
child.kill("SIGKILL");
|
|
1053
|
+
} catch {
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
return;
|
|
1057
|
+
} catch {
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
try {
|
|
1061
|
+
child.kill("SIGKILL");
|
|
1062
|
+
} catch {
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
// src/cmdTools/install.ts
|
|
1067
|
+
function getCmdToolsDownloadUrl(config, platform7 = os6.platform()) {
|
|
1068
|
+
if (platform7 === "linux") {
|
|
779
1069
|
return config.get("cmdToolsUrlLinux", defaultPaths.cmdToolsUrlLinux);
|
|
780
1070
|
}
|
|
781
|
-
if (
|
|
1071
|
+
if (platform7 === "win32") {
|
|
782
1072
|
const url = config.get("cmdToolsUrlWindows", "");
|
|
783
1073
|
if (!url) {
|
|
784
1074
|
throw new OniroError(
|
|
@@ -787,7 +1077,7 @@ function getCmdToolsDownloadUrl(config, platform6 = os6.platform()) {
|
|
|
787
1077
|
}
|
|
788
1078
|
return url;
|
|
789
1079
|
}
|
|
790
|
-
if (
|
|
1080
|
+
if (platform7 === "darwin") {
|
|
791
1081
|
const url = config.get("cmdToolsUrlMac", "");
|
|
792
1082
|
if (!url) {
|
|
793
1083
|
throw new OniroError(
|
|
@@ -796,20 +1086,20 @@ function getCmdToolsDownloadUrl(config, platform6 = os6.platform()) {
|
|
|
796
1086
|
}
|
|
797
1087
|
return url;
|
|
798
1088
|
}
|
|
799
|
-
throw new UnsupportedPlatformError(
|
|
1089
|
+
throw new UnsupportedPlatformError(platform7);
|
|
800
1090
|
}
|
|
801
1091
|
function findCmdToolsSourceDir(extractPath) {
|
|
802
1092
|
const known = [
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
1093
|
+
path11.join(extractPath, "command-line-tools"),
|
|
1094
|
+
path11.join(extractPath, "oh-command-line-tools"),
|
|
1095
|
+
path11.join(extractPath, "commandline-tools")
|
|
806
1096
|
];
|
|
807
1097
|
for (const c of known) {
|
|
808
|
-
if (
|
|
1098
|
+
if (fs10.existsSync(c)) return c;
|
|
809
1099
|
}
|
|
810
|
-
const entries =
|
|
1100
|
+
const entries = fs10.readdirSync(extractPath, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path11.join(extractPath, e.name));
|
|
811
1101
|
for (const dir of entries) {
|
|
812
|
-
if (
|
|
1102
|
+
if (fs10.existsSync(path11.join(dir, "bin"))) return dir;
|
|
813
1103
|
}
|
|
814
1104
|
throw new OniroError("Could not locate command line tools folder in the extracted archive.");
|
|
815
1105
|
}
|
|
@@ -817,53 +1107,62 @@ async function installCmdTools(opts) {
|
|
|
817
1107
|
const { config, progress, abortSignal } = opts;
|
|
818
1108
|
const logger = opts.logger ?? noopLogger;
|
|
819
1109
|
const CMD_PATH = getCmdToolsPath(config);
|
|
820
|
-
const
|
|
821
|
-
const
|
|
822
|
-
|
|
1110
|
+
const what = "the command-line tools install";
|
|
1111
|
+
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
1112
|
+
config,
|
|
1113
|
+
override: opts.tmpDir,
|
|
1114
|
+
installRoot: path11.dirname(CMD_PATH),
|
|
1115
|
+
prefix: "oniro-cmdtools-",
|
|
1116
|
+
logger
|
|
1117
|
+
});
|
|
1118
|
+
const zipPath = opts.localZipPath ?? path11.join(tmpDir, "oh-command-line-tools.zip");
|
|
1119
|
+
const extractPath = path11.join(tmpDir, "oh-command-line-tools");
|
|
823
1120
|
try {
|
|
824
1121
|
if (!opts.localZipPath) {
|
|
825
1122
|
const url = getCmdToolsDownloadUrl(config);
|
|
826
1123
|
progress?.report({ message: "Downloading command line tools...", increment: 0 });
|
|
827
|
-
await downloadFile({ url, dest: zipPath, progress, abortSignal, start: 0, range: 50 });
|
|
1124
|
+
await downloadFile({ url, dest: zipPath, progress, abortSignal, start: 0, range: 50, what, tmpRoot });
|
|
828
1125
|
}
|
|
829
1126
|
progress?.report({ message: "Extracting tools...", increment: 0 });
|
|
830
1127
|
await extractZipWithProgress({ zipPath, dest: extractPath, progress, start: 50, range: 45, logger });
|
|
831
|
-
|
|
1128
|
+
fs10.mkdirSync(CMD_PATH, { recursive: true });
|
|
832
1129
|
const srcDir = findCmdToolsSourceDir(extractPath);
|
|
833
|
-
for (const entry of
|
|
834
|
-
const src =
|
|
835
|
-
const dest =
|
|
836
|
-
if (
|
|
837
|
-
if (
|
|
1130
|
+
for (const entry of fs10.readdirSync(srcDir)) {
|
|
1131
|
+
const src = path11.join(srcDir, entry);
|
|
1132
|
+
const dest = path11.join(CMD_PATH, entry);
|
|
1133
|
+
if (fs10.statSync(src).isDirectory()) {
|
|
1134
|
+
if (fs10.existsSync(dest)) fs10.rmSync(dest, { recursive: true, force: true });
|
|
838
1135
|
movePath(src, dest);
|
|
839
1136
|
} else {
|
|
840
|
-
|
|
1137
|
+
fs10.copyFileSync(src, dest);
|
|
841
1138
|
}
|
|
842
1139
|
}
|
|
843
|
-
const binDir =
|
|
844
|
-
if (
|
|
845
|
-
for (const file of
|
|
846
|
-
|
|
1140
|
+
const binDir = path11.join(CMD_PATH, "bin");
|
|
1141
|
+
if (fs10.existsSync(binDir) && os6.platform() !== "win32") {
|
|
1142
|
+
for (const file of fs10.readdirSync(binDir)) {
|
|
1143
|
+
fs10.chmodSync(path11.join(binDir, file), 493);
|
|
847
1144
|
}
|
|
848
1145
|
}
|
|
849
1146
|
progress?.report({ message: "Finalizing installation...", increment: 5 });
|
|
850
1147
|
progress?.report({ message: "Cleaning up...", increment: 0 });
|
|
1148
|
+
} catch (err) {
|
|
1149
|
+
throw toSpaceError(err, tmpRoot, what);
|
|
851
1150
|
} finally {
|
|
852
|
-
|
|
1151
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
853
1152
|
}
|
|
854
1153
|
}
|
|
855
1154
|
function getCmdToolsStatus(config) {
|
|
856
1155
|
const cmdPath = getCmdToolsPath(config);
|
|
857
|
-
const binDir =
|
|
1156
|
+
const binDir = path11.join(cmdPath, "bin");
|
|
858
1157
|
const candidates = os6.platform() === "win32" ? ["ohpm.exe", "ohpm.cmd", "ohpm.bat", "ohpm"] : ["ohpm"];
|
|
859
|
-
const bin = candidates.map((c) =>
|
|
1158
|
+
const bin = candidates.map((c) => path11.join(binDir, c)).find((p) => fs10.existsSync(p));
|
|
860
1159
|
if (!bin) {
|
|
861
1160
|
return { installed: false, status: "Not installed" };
|
|
862
1161
|
}
|
|
863
1162
|
try {
|
|
864
|
-
const versionFile =
|
|
865
|
-
if (
|
|
866
|
-
const content =
|
|
1163
|
+
const versionFile = path11.join(cmdPath, "version.txt");
|
|
1164
|
+
if (fs10.existsSync(versionFile)) {
|
|
1165
|
+
const content = fs10.readFileSync(versionFile, "utf8");
|
|
867
1166
|
for (const line of content.split(/\r?\n/)) {
|
|
868
1167
|
const m = line.match(/^\s*#\s*Version:\s*(.+)$/);
|
|
869
1168
|
if (m?.[1]) return { installed: true, status: `Installed (${m[1].trim()})` };
|
|
@@ -872,7 +1171,14 @@ function getCmdToolsStatus(config) {
|
|
|
872
1171
|
} catch {
|
|
873
1172
|
}
|
|
874
1173
|
try {
|
|
875
|
-
const
|
|
1174
|
+
const wrapped = needsCmdWrapper(bin);
|
|
1175
|
+
const probe = wrapped ? buildCmdWrapper(bin, ["-v"]) : { command: bin, args: ["-v"] };
|
|
1176
|
+
const res = (0, import_node_child_process2.spawnSync)(probe.command, probe.args, {
|
|
1177
|
+
encoding: "utf8",
|
|
1178
|
+
windowsVerbatimArguments: wrapped
|
|
1179
|
+
});
|
|
1180
|
+
if (res.error || res.status !== 0) throw res.error ?? new Error(`exit ${String(res.status)}`);
|
|
1181
|
+
const version = res.stdout.trim();
|
|
876
1182
|
return { installed: true, status: `Installed (${version})` };
|
|
877
1183
|
} catch {
|
|
878
1184
|
return { installed: true, status: "Installed (version unknown)" };
|
|
@@ -883,14 +1189,14 @@ function isCmdToolsInstalled(config) {
|
|
|
883
1189
|
}
|
|
884
1190
|
function removeCmdTools(config) {
|
|
885
1191
|
const cmdPath = getCmdToolsPath(config);
|
|
886
|
-
if (
|
|
887
|
-
|
|
1192
|
+
if (fs10.existsSync(cmdPath)) {
|
|
1193
|
+
fs10.rmSync(cmdPath, { recursive: true, force: true });
|
|
888
1194
|
}
|
|
889
1195
|
}
|
|
890
1196
|
|
|
891
1197
|
// src/sign/encryptKey.ts
|
|
892
|
-
var
|
|
893
|
-
var
|
|
1198
|
+
var fs11 = __toESM(require("fs"), 1);
|
|
1199
|
+
var path12 = __toESM(require("path"), 1);
|
|
894
1200
|
var crypto2 = __toESM(require("crypto"), 1);
|
|
895
1201
|
var DAEMON_ROOT_KEY_COMPONENT_LENGTH = 16;
|
|
896
1202
|
var DAEMON_SALT_KEY_LENGTH = 16;
|
|
@@ -962,33 +1268,33 @@ function getRootKey(fdComponents, salt) {
|
|
|
962
1268
|
function createAndStoreKey(dir, keyLength) {
|
|
963
1269
|
const key = crypto2.randomBytes(keyLength);
|
|
964
1270
|
const hash = crypto2.createHash("sha256").update(key).digest("hex");
|
|
965
|
-
const filePath =
|
|
966
|
-
|
|
967
|
-
|
|
1271
|
+
const filePath = path12.join(dir, hash);
|
|
1272
|
+
fs11.writeFileSync(filePath, key);
|
|
1273
|
+
fs11.chmodSync(filePath, KEY_FILE_PERMISSIONS);
|
|
968
1274
|
return key;
|
|
969
1275
|
}
|
|
970
1276
|
function createAndStoreEnKey(rootKey, ceDir) {
|
|
971
1277
|
const workKey = crypto2.randomBytes(DAEMON_WORK_KEY_LENGTH);
|
|
972
1278
|
const encrypted = encrypt(rootKey, workKey);
|
|
973
1279
|
const hash = crypto2.createHash("sha256").update(encrypted).digest("hex");
|
|
974
|
-
const filePath =
|
|
975
|
-
|
|
976
|
-
|
|
1280
|
+
const filePath = path12.join(ceDir, hash);
|
|
1281
|
+
fs11.writeFileSync(filePath, encrypted);
|
|
1282
|
+
fs11.chmodSync(filePath, KEY_FILE_PERMISSIONS);
|
|
977
1283
|
}
|
|
978
1284
|
function createMaterial(materialPath) {
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
const fdDir =
|
|
982
|
-
const acDir =
|
|
983
|
-
const ceDir =
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1285
|
+
fs11.mkdirSync(materialPath, { recursive: true });
|
|
1286
|
+
fs11.chmodSync(materialPath, KEY_FILE_DIRECTORY_PERMISSIONS);
|
|
1287
|
+
const fdDir = path12.join(materialPath, "fd");
|
|
1288
|
+
const acDir = path12.join(materialPath, "ac");
|
|
1289
|
+
const ceDir = path12.join(materialPath, "ce");
|
|
1290
|
+
fs11.mkdirSync(fdDir, { recursive: true });
|
|
1291
|
+
fs11.mkdirSync(acDir, { recursive: true });
|
|
1292
|
+
fs11.mkdirSync(ceDir, { recursive: true });
|
|
987
1293
|
const fdSubDirs = ["0", "1", "2"];
|
|
988
1294
|
const fdComponents = [];
|
|
989
1295
|
for (const sub of fdSubDirs) {
|
|
990
|
-
const subDir =
|
|
991
|
-
|
|
1296
|
+
const subDir = path12.join(fdDir, sub);
|
|
1297
|
+
fs11.mkdirSync(subDir, { recursive: true });
|
|
992
1298
|
const comp = createAndStoreKey(subDir, DAEMON_ROOT_KEY_COMPONENT_LENGTH);
|
|
993
1299
|
fdComponents.push(comp);
|
|
994
1300
|
}
|
|
@@ -997,24 +1303,24 @@ function createMaterial(materialPath) {
|
|
|
997
1303
|
createAndStoreEnKey(rootKey, ceDir);
|
|
998
1304
|
}
|
|
999
1305
|
function readSingleFile(dir) {
|
|
1000
|
-
if (!
|
|
1306
|
+
if (!fs11.existsSync(dir) || !fs11.statSync(dir).isDirectory()) {
|
|
1001
1307
|
throw new Error(`Missing signing material directory: ${dir}`);
|
|
1002
1308
|
}
|
|
1003
|
-
const files =
|
|
1309
|
+
const files = fs11.readdirSync(dir).filter((f) => f !== ".DS_Store");
|
|
1004
1310
|
if (files.length !== 1) {
|
|
1005
1311
|
throw new Error(`Signing material in ${dir} is illegal (expected exactly one file).`);
|
|
1006
1312
|
}
|
|
1007
|
-
return
|
|
1313
|
+
return fs11.readFileSync(path12.join(dir, files[0]));
|
|
1008
1314
|
}
|
|
1009
1315
|
function getKey(materialPath) {
|
|
1010
|
-
if (!
|
|
1316
|
+
if (!fs11.existsSync(materialPath) || !fs11.statSync(materialPath).isDirectory()) {
|
|
1011
1317
|
throw new Error("Material directory does not exist.");
|
|
1012
1318
|
}
|
|
1013
|
-
const fdDir =
|
|
1014
|
-
const fdComponents = ["0", "1", "2"].map((sub) => readSingleFile(
|
|
1015
|
-
const salt = readSingleFile(
|
|
1319
|
+
const fdDir = path12.join(materialPath, "fd");
|
|
1320
|
+
const fdComponents = ["0", "1", "2"].map((sub) => readSingleFile(path12.join(fdDir, sub)));
|
|
1321
|
+
const salt = readSingleFile(path12.join(materialPath, "ac"));
|
|
1016
1322
|
const rootKey = getRootKey(fdComponents, salt);
|
|
1017
|
-
const workMaterial = readSingleFile(
|
|
1323
|
+
const workMaterial = readSingleFile(path12.join(materialPath, "ce"));
|
|
1018
1324
|
return decrypt(rootKey, workMaterial);
|
|
1019
1325
|
}
|
|
1020
1326
|
function encryptPwd(password, materialPath) {
|
|
@@ -1029,9 +1335,9 @@ function decryptPwd(encryptedHex, materialPath) {
|
|
|
1029
1335
|
}
|
|
1030
1336
|
|
|
1031
1337
|
// src/sign/generateSigningConfigs.ts
|
|
1032
|
-
var
|
|
1033
|
-
var
|
|
1034
|
-
var
|
|
1338
|
+
var fs12 = __toESM(require("fs"), 1);
|
|
1339
|
+
var path13 = __toESM(require("path"), 1);
|
|
1340
|
+
var import_node_child_process3 = require("child_process");
|
|
1035
1341
|
var import_json52 = __toESM(require("json5"), 1);
|
|
1036
1342
|
|
|
1037
1343
|
// src/sign/applicationCert.ts
|
|
@@ -1100,17 +1406,17 @@ var SIGNING_KIND_CONFIG = {
|
|
|
1100
1406
|
};
|
|
1101
1407
|
function copyFilesToProject(projectDir, paths, kind, logger, applicationCertPath) {
|
|
1102
1408
|
logger.info("[sign] Copying signing material into project...");
|
|
1103
|
-
const signaturesDir =
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1409
|
+
const signaturesDir = path13.join(projectDir, "signatures");
|
|
1410
|
+
fs12.mkdirSync(signaturesDir, { recursive: true });
|
|
1411
|
+
fs12.copyFileSync(paths.keystore, path13.join(signaturesDir, "OpenHarmony.p12"));
|
|
1412
|
+
fs12.copyFileSync(paths.profileCert, path13.join(signaturesDir, "OpenHarmonyProfileRelease.pem"));
|
|
1413
|
+
fs12.copyFileSync(paths.unsignedProfileTemplate, path13.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json"));
|
|
1108
1414
|
if (kind === "application-release") {
|
|
1109
|
-
const dest =
|
|
1415
|
+
const dest = path13.join(signaturesDir, "OpenHarmonyApplication.cer");
|
|
1110
1416
|
if (applicationCertPath) {
|
|
1111
|
-
|
|
1417
|
+
fs12.copyFileSync(applicationCertPath, dest);
|
|
1112
1418
|
} else {
|
|
1113
|
-
|
|
1419
|
+
fs12.writeFileSync(dest, OPEN_HARMONY_APPLICATION_CERT);
|
|
1114
1420
|
}
|
|
1115
1421
|
}
|
|
1116
1422
|
}
|
|
@@ -1119,7 +1425,7 @@ function resolveAppFeature(apl, override) {
|
|
|
1119
1425
|
return apl === "normal" ? "hos_normal_app" : "hos_system_app";
|
|
1120
1426
|
}
|
|
1121
1427
|
function extractLeafCertificate(chainPath) {
|
|
1122
|
-
const certContent =
|
|
1428
|
+
const certContent = fs12.readFileSync(chainPath, "utf-8");
|
|
1123
1429
|
const parts = certContent.split("-----END CERTIFICATE-----");
|
|
1124
1430
|
if (parts.length < 3) {
|
|
1125
1431
|
throw new OniroError(`${chainPath} does not contain enough certificates.`);
|
|
@@ -1129,20 +1435,20 @@ function extractLeafCertificate(chainPath) {
|
|
|
1129
1435
|
function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}) {
|
|
1130
1436
|
const kind = options.kind ?? pickSigningKind(apl);
|
|
1131
1437
|
logger.info(`[sign] Modifying profile template (apl=${apl}, app-feature=${appFeature}, kind=${kind})...`);
|
|
1132
|
-
const appJsonPath =
|
|
1133
|
-
const profileTemplatePath =
|
|
1134
|
-
if (!
|
|
1438
|
+
const appJsonPath = path13.join(projectDir, "AppScope/app.json5");
|
|
1439
|
+
const profileTemplatePath = path13.join(projectDir, "signatures/UnsgnedReleasedProfileTemplate.json");
|
|
1440
|
+
if (!fs12.existsSync(appJsonPath)) {
|
|
1135
1441
|
throw new OniroError(`${appJsonPath} does not exist.`);
|
|
1136
1442
|
}
|
|
1137
1443
|
let appJson;
|
|
1138
1444
|
try {
|
|
1139
|
-
appJson = import_json52.default.parse(
|
|
1445
|
+
appJson = import_json52.default.parse(fs12.readFileSync(appJsonPath, "utf-8"));
|
|
1140
1446
|
} catch (e) {
|
|
1141
1447
|
throw new OniroError(`Error parsing ${appJsonPath}: ${e.message}`, e);
|
|
1142
1448
|
}
|
|
1143
1449
|
let profileTemplate;
|
|
1144
1450
|
try {
|
|
1145
|
-
profileTemplate = JSON.parse(
|
|
1451
|
+
profileTemplate = JSON.parse(fs12.readFileSync(profileTemplatePath, "utf-8"));
|
|
1146
1452
|
} catch (e) {
|
|
1147
1453
|
throw new OniroError(`Error parsing ${profileTemplatePath}: ${e.message}`, e);
|
|
1148
1454
|
}
|
|
@@ -1155,7 +1461,7 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
|
|
|
1155
1461
|
profileTemplate["bundle-info"]["bundle-name"] = appJson.app.bundleName;
|
|
1156
1462
|
profileTemplate["bundle-info"]["apl"] = apl;
|
|
1157
1463
|
profileTemplate["bundle-info"]["app-feature"] = appFeature;
|
|
1158
|
-
const distCertChainPath =
|
|
1464
|
+
const distCertChainPath = path13.join(
|
|
1159
1465
|
projectDir,
|
|
1160
1466
|
"signatures",
|
|
1161
1467
|
SIGNING_KIND_CONFIG[kind].certBasename
|
|
@@ -1165,13 +1471,13 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
|
|
|
1165
1471
|
profileTemplate.acls = profileTemplate.acls ?? {};
|
|
1166
1472
|
profileTemplate.acls["allowed-acls"] = options.acls;
|
|
1167
1473
|
}
|
|
1168
|
-
|
|
1474
|
+
fs12.writeFileSync(profileTemplatePath, JSON.stringify(profileTemplate, null, 2));
|
|
1169
1475
|
}
|
|
1170
1476
|
function generateP7bFile(projectDir, paths, logger, passwords) {
|
|
1171
1477
|
logger.info("[sign] Generating P7b profile via hap-sign-tool...");
|
|
1172
|
-
const signaturesDir =
|
|
1173
|
-
const profileTemplatePath =
|
|
1174
|
-
const outputProfilePath =
|
|
1478
|
+
const signaturesDir = path13.join(projectDir, "signatures");
|
|
1479
|
+
const profileTemplatePath = path13.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json");
|
|
1480
|
+
const outputProfilePath = path13.join(signaturesDir, "app1-profile.p7b");
|
|
1175
1481
|
const args = [
|
|
1176
1482
|
"-jar",
|
|
1177
1483
|
paths.signTool,
|
|
@@ -1196,7 +1502,7 @@ function generateP7bFile(projectDir, paths, logger, passwords) {
|
|
|
1196
1502
|
passwords.store
|
|
1197
1503
|
];
|
|
1198
1504
|
try {
|
|
1199
|
-
(0,
|
|
1505
|
+
(0, import_node_child_process3.execFileSync)("java", args, { stdio: "inherit" });
|
|
1200
1506
|
} catch (e) {
|
|
1201
1507
|
throw new OniroError(
|
|
1202
1508
|
`hap-sign-tool failed. Ensure a JDK (with keytool/java) is on PATH. Underlying error: ${e.message}`,
|
|
@@ -1205,11 +1511,11 @@ function generateP7bFile(projectDir, paths, logger, passwords) {
|
|
|
1205
1511
|
}
|
|
1206
1512
|
}
|
|
1207
1513
|
function detectSigningConfigNames(projectDir) {
|
|
1208
|
-
const buildProfilePath =
|
|
1209
|
-
if (!
|
|
1514
|
+
const buildProfilePath = path13.join(projectDir, "build-profile.json5");
|
|
1515
|
+
if (!fs12.existsSync(buildProfilePath)) return ["default"];
|
|
1210
1516
|
let parsed;
|
|
1211
1517
|
try {
|
|
1212
|
-
parsed = import_json52.default.parse(
|
|
1518
|
+
parsed = import_json52.default.parse(fs12.readFileSync(buildProfilePath, "utf-8"));
|
|
1213
1519
|
} catch {
|
|
1214
1520
|
return ["default"];
|
|
1215
1521
|
}
|
|
@@ -1226,14 +1532,14 @@ function detectSigningConfigNames(projectDir) {
|
|
|
1226
1532
|
}
|
|
1227
1533
|
function updateBuildProfile(projectDir, kind, logger, passwords) {
|
|
1228
1534
|
logger.info("[sign] Writing signing configs into build-profile.json5...");
|
|
1229
|
-
const materialDir =
|
|
1230
|
-
const buildProfilePath =
|
|
1535
|
+
const materialDir = path13.join(projectDir, "signatures", "material");
|
|
1536
|
+
const buildProfilePath = path13.join(projectDir, "build-profile.json5");
|
|
1231
1537
|
const encryptedStorePassword = encryptPwd(passwords.store, materialDir);
|
|
1232
1538
|
const encryptedKeyPassword = encryptPwd(passwords.key, materialDir);
|
|
1233
1539
|
let buildProfile = { app: {} };
|
|
1234
|
-
if (
|
|
1540
|
+
if (fs12.existsSync(buildProfilePath)) {
|
|
1235
1541
|
try {
|
|
1236
|
-
buildProfile = import_json52.default.parse(
|
|
1542
|
+
buildProfile = import_json52.default.parse(fs12.readFileSync(buildProfilePath, "utf-8"));
|
|
1237
1543
|
} catch (e) {
|
|
1238
1544
|
throw new OniroError(`Error parsing ${buildProfilePath}: ${e.message}`, e);
|
|
1239
1545
|
}
|
|
@@ -1254,13 +1560,13 @@ function updateBuildProfile(projectDir, kind, logger, passwords) {
|
|
|
1254
1560
|
storeFile: "./signatures/OpenHarmony.p12"
|
|
1255
1561
|
}
|
|
1256
1562
|
}));
|
|
1257
|
-
|
|
1563
|
+
fs12.writeFileSync(buildProfilePath, JSON.stringify(buildProfile, null, 2));
|
|
1258
1564
|
}
|
|
1259
1565
|
function prepareMaterialDirectory(projectDir, logger) {
|
|
1260
1566
|
logger.info("[sign] Generating fresh signing material...");
|
|
1261
|
-
const materialDir =
|
|
1262
|
-
if (
|
|
1263
|
-
|
|
1567
|
+
const materialDir = path13.join(projectDir, "signatures", "material");
|
|
1568
|
+
if (fs12.existsSync(materialDir)) {
|
|
1569
|
+
fs12.rmSync(materialDir, { recursive: true, force: true });
|
|
1264
1570
|
}
|
|
1265
1571
|
createMaterial(materialDir);
|
|
1266
1572
|
}
|
|
@@ -1283,15 +1589,15 @@ function generateSigningConfigs(options) {
|
|
|
1283
1589
|
"Could not detect project SDK version (compileSdkVersion missing in build-profile.json5)."
|
|
1284
1590
|
);
|
|
1285
1591
|
}
|
|
1286
|
-
const sdkPath =
|
|
1287
|
-
if (!
|
|
1592
|
+
const sdkPath = path13.join(sdkHome, String(sdkVersion));
|
|
1593
|
+
if (!fs12.existsSync(sdkPath)) {
|
|
1288
1594
|
throw new OniroError(`SDK path does not exist: ${sdkPath}`);
|
|
1289
1595
|
}
|
|
1290
1596
|
const paths = {
|
|
1291
|
-
signTool:
|
|
1292
|
-
keystore:
|
|
1293
|
-
profileCert:
|
|
1294
|
-
unsignedProfileTemplate:
|
|
1597
|
+
signTool: path13.join(sdkPath, "toolchains/lib/hap-sign-tool.jar"),
|
|
1598
|
+
keystore: path13.join(sdkPath, "toolchains/lib/OpenHarmony.p12"),
|
|
1599
|
+
profileCert: path13.join(sdkPath, "toolchains/lib/OpenHarmonyProfileRelease.pem"),
|
|
1600
|
+
unsignedProfileTemplate: path13.join(sdkPath, "toolchains/lib/UnsgnedReleasedProfileTemplate.json")
|
|
1295
1601
|
};
|
|
1296
1602
|
const kind = pickSigningKind(apl);
|
|
1297
1603
|
const passwords = options.passwords ?? DEFAULT_PASSWORDS;
|
|
@@ -1305,60 +1611,81 @@ function generateSigningConfigs(options) {
|
|
|
1305
1611
|
}
|
|
1306
1612
|
|
|
1307
1613
|
// src/emulator/install.ts
|
|
1308
|
-
var
|
|
1309
|
-
var
|
|
1310
|
-
var path11 = __toESM(require("path"), 1);
|
|
1614
|
+
var fs13 = __toESM(require("fs"), 1);
|
|
1615
|
+
var path14 = __toESM(require("path"), 1);
|
|
1311
1616
|
async function installEmulator(opts) {
|
|
1312
1617
|
const { config, progress, abortSignal } = opts;
|
|
1313
1618
|
const logger = opts.logger ?? noopLogger;
|
|
1314
1619
|
const url = config.get("emulatorUrl", defaultPaths.emulatorUrl);
|
|
1315
1620
|
const emulatorDir = getEmulatorDir(config);
|
|
1316
|
-
const
|
|
1317
|
-
const
|
|
1621
|
+
const what = "the emulator install";
|
|
1622
|
+
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
1623
|
+
config,
|
|
1624
|
+
override: opts.tmpDir,
|
|
1625
|
+
installRoot: path14.dirname(emulatorDir),
|
|
1626
|
+
prefix: "oniro-emulator-",
|
|
1627
|
+
logger
|
|
1628
|
+
});
|
|
1629
|
+
const tmpZip = path14.join(tmpDir, "oniro_emulator.zip");
|
|
1318
1630
|
try {
|
|
1319
|
-
|
|
1631
|
+
fs13.mkdirSync(emulatorDir, { recursive: true });
|
|
1320
1632
|
progress?.report({ message: "Downloading emulator...", increment: 0 });
|
|
1321
|
-
await downloadFile({ url, dest: tmpZip, progress, abortSignal, start: 0, range: 50 });
|
|
1633
|
+
await downloadFile({ url, dest: tmpZip, progress, abortSignal, start: 0, range: 50, what, tmpRoot });
|
|
1322
1634
|
progress?.report({ message: "Extracting emulator...", increment: 0 });
|
|
1323
1635
|
await extractZipWithProgress({ zipPath: tmpZip, dest: emulatorDir, progress, start: 50, range: 45, logger });
|
|
1324
|
-
const runSh =
|
|
1325
|
-
if (
|
|
1326
|
-
|
|
1636
|
+
const runSh = path14.join(emulatorDir, "images", "run.sh");
|
|
1637
|
+
if (fs13.existsSync(runSh)) {
|
|
1638
|
+
fs13.chmodSync(runSh, 493);
|
|
1327
1639
|
}
|
|
1328
1640
|
progress?.report({ message: "Finalizing installation...", increment: 5 });
|
|
1641
|
+
} catch (err) {
|
|
1642
|
+
throw toSpaceError(err, tmpRoot, what);
|
|
1329
1643
|
} finally {
|
|
1330
|
-
|
|
1644
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
1331
1645
|
}
|
|
1332
1646
|
}
|
|
1333
1647
|
function isEmulatorInstalled(config) {
|
|
1334
|
-
const imagesDir =
|
|
1335
|
-
return
|
|
1648
|
+
const imagesDir = path14.join(getEmulatorDir(config), "images");
|
|
1649
|
+
return fs13.existsSync(path14.join(imagesDir, "run.sh")) || fs13.existsSync(path14.join(imagesDir, "run.bat"));
|
|
1336
1650
|
}
|
|
1337
1651
|
function removeEmulator(config) {
|
|
1338
1652
|
const emulatorDir = getEmulatorDir(config);
|
|
1339
|
-
if (
|
|
1340
|
-
|
|
1653
|
+
if (fs13.existsSync(emulatorDir)) {
|
|
1654
|
+
fs13.rmSync(emulatorDir, { recursive: true, force: true });
|
|
1341
1655
|
}
|
|
1342
1656
|
}
|
|
1343
1657
|
|
|
1344
1658
|
// src/emulator/lifecycle.ts
|
|
1345
|
-
var
|
|
1346
|
-
var
|
|
1347
|
-
var
|
|
1659
|
+
var fs15 = __toESM(require("fs"), 1);
|
|
1660
|
+
var os7 = __toESM(require("os"), 1);
|
|
1661
|
+
var path15 = __toESM(require("path"), 1);
|
|
1348
1662
|
var import_node_child_process4 = require("child_process");
|
|
1349
1663
|
|
|
1350
1664
|
// src/hdc/exec.ts
|
|
1351
|
-
var
|
|
1665
|
+
var fs14 = __toESM(require("fs"), 1);
|
|
1666
|
+
function errorMessage(err) {
|
|
1667
|
+
return err instanceof Error ? err.message : String(err);
|
|
1668
|
+
}
|
|
1352
1669
|
function runProcess(opts) {
|
|
1353
1670
|
const { command, args, cwd, env, onOutput } = opts;
|
|
1354
1671
|
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
1355
1672
|
const { abortSignal } = opts;
|
|
1356
|
-
return new Promise((
|
|
1673
|
+
return new Promise((resolve4, reject) => {
|
|
1357
1674
|
if (abortSignal?.aborted) {
|
|
1358
1675
|
reject(new CancelledError(`Command aborted before start: ${command}`));
|
|
1359
1676
|
return;
|
|
1360
1677
|
}
|
|
1361
|
-
|
|
1678
|
+
if (needsCmdWrapper(command) && !fs14.existsSync(command)) {
|
|
1679
|
+
reject(new OniroError(`Failed to spawn ${command}: ENOENT (no such file)`));
|
|
1680
|
+
return;
|
|
1681
|
+
}
|
|
1682
|
+
let child;
|
|
1683
|
+
try {
|
|
1684
|
+
child = spawnCompat(command, args, { cwd, env });
|
|
1685
|
+
} catch (err) {
|
|
1686
|
+
reject(new OniroError(`Failed to spawn ${command}: ${errorMessage(err)}`, err));
|
|
1687
|
+
return;
|
|
1688
|
+
}
|
|
1362
1689
|
let stdout = "";
|
|
1363
1690
|
let stderr = "";
|
|
1364
1691
|
let settled = false;
|
|
@@ -1371,26 +1698,20 @@ function runProcess(opts) {
|
|
|
1371
1698
|
if (settled) return;
|
|
1372
1699
|
settled = true;
|
|
1373
1700
|
cleanup();
|
|
1374
|
-
|
|
1375
|
-
child.kill("SIGKILL");
|
|
1376
|
-
} catch {
|
|
1377
|
-
}
|
|
1701
|
+
killProcessTree(child);
|
|
1378
1702
|
reject(new CancelledError(`Command aborted: ${command} ${args.join(" ")}`));
|
|
1379
1703
|
};
|
|
1380
1704
|
const timer = setTimeout(() => {
|
|
1381
1705
|
timedOut = true;
|
|
1382
|
-
|
|
1383
|
-
child.kill("SIGKILL");
|
|
1384
|
-
} catch {
|
|
1385
|
-
}
|
|
1706
|
+
killProcessTree(child);
|
|
1386
1707
|
}, timeoutMs);
|
|
1387
1708
|
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
1388
|
-
child.stdout
|
|
1709
|
+
child.stdout?.on("data", (d) => {
|
|
1389
1710
|
const s = d.toString();
|
|
1390
1711
|
stdout += s;
|
|
1391
1712
|
onOutput?.(s, "stdout");
|
|
1392
1713
|
});
|
|
1393
|
-
child.stderr
|
|
1714
|
+
child.stderr?.on("data", (d) => {
|
|
1394
1715
|
const s = d.toString();
|
|
1395
1716
|
stderr += s;
|
|
1396
1717
|
onOutput?.(s, "stderr");
|
|
@@ -1414,7 +1735,7 @@ ${stderr.trim()}` : "")
|
|
|
1414
1735
|
);
|
|
1415
1736
|
return;
|
|
1416
1737
|
}
|
|
1417
|
-
|
|
1738
|
+
resolve4({ code: code ?? -1, stdout, stderr });
|
|
1418
1739
|
});
|
|
1419
1740
|
});
|
|
1420
1741
|
}
|
|
@@ -1440,9 +1761,29 @@ function ensureOk(result, command) {
|
|
|
1440
1761
|
}
|
|
1441
1762
|
return result;
|
|
1442
1763
|
}
|
|
1764
|
+
var REMOTE_RC_RE = /__ONIRO_RC=(-?\d+)__/g;
|
|
1765
|
+
function parseRemoteExit(stdout) {
|
|
1766
|
+
let code = null;
|
|
1767
|
+
for (const m of stdout.matchAll(REMOTE_RC_RE)) code = Number(m[1]);
|
|
1768
|
+
if (code === null) return null;
|
|
1769
|
+
return { code, stdout: stdout.replace(REMOTE_RC_RE, "").replace(/[ \t\r\n]+$/, "") };
|
|
1770
|
+
}
|
|
1771
|
+
async function shellChecked(opts) {
|
|
1772
|
+
const { command, ...rest } = opts;
|
|
1773
|
+
const res = await hdcExec({ ...rest, args: ["shell", `${command}; echo "__ONIRO_RC=$?__"`] });
|
|
1774
|
+
const parsed = parseRemoteExit(res.stdout);
|
|
1775
|
+
if (!parsed) return res;
|
|
1776
|
+
return { code: parsed.code, stdout: parsed.stdout, stderr: res.stderr };
|
|
1777
|
+
}
|
|
1778
|
+
function ensureRemoteOk(result, command) {
|
|
1779
|
+
if (result.code !== 0) {
|
|
1780
|
+
throw new CommandFailedError(command, result.code, result.stderr.trim() || result.stdout.trim());
|
|
1781
|
+
}
|
|
1782
|
+
return result;
|
|
1783
|
+
}
|
|
1443
1784
|
|
|
1444
1785
|
// src/emulator/lifecycle.ts
|
|
1445
|
-
var PID_FILE =
|
|
1786
|
+
var PID_FILE = path15.join(os7.tmpdir(), "oniro_emulator.pid");
|
|
1446
1787
|
async function attemptHdcConnection(config, address = "127.0.0.1:55555", logger = noopLogger) {
|
|
1447
1788
|
try {
|
|
1448
1789
|
await hdcExec({ config, args: ["start", "-r"], logger });
|
|
@@ -1455,24 +1796,24 @@ async function attemptHdcConnection(config, address = "127.0.0.1:55555", logger
|
|
|
1455
1796
|
}
|
|
1456
1797
|
}
|
|
1457
1798
|
function resolveLauncher(imagesPath, headless, connect) {
|
|
1458
|
-
const runSh =
|
|
1459
|
-
const runBat =
|
|
1799
|
+
const runSh = path15.join(imagesPath, "run.sh");
|
|
1800
|
+
const runBat = path15.join(imagesPath, "run.bat");
|
|
1460
1801
|
const extra = [];
|
|
1461
1802
|
if (headless) extra.push("--headless");
|
|
1462
1803
|
if (connect) extra.push("--connect", connect);
|
|
1463
|
-
if (
|
|
1464
|
-
if (
|
|
1804
|
+
if (os7.platform() === "win32") {
|
|
1805
|
+
if (fs15.existsSync(runBat)) {
|
|
1465
1806
|
return { command: "cmd.exe", args: ["/c", runBat, ...extra], cwd: imagesPath };
|
|
1466
1807
|
}
|
|
1467
|
-
if (
|
|
1808
|
+
if (fs15.existsSync(runSh)) {
|
|
1468
1809
|
return { command: "bash", args: [runSh, ...extra], cwd: imagesPath };
|
|
1469
1810
|
}
|
|
1470
1811
|
throw new OniroError(`No emulator launcher (run.bat or run.sh) found in ${imagesPath}.`);
|
|
1471
1812
|
}
|
|
1472
|
-
if (
|
|
1813
|
+
if (fs15.existsSync(runSh)) {
|
|
1473
1814
|
return { command: "bash", args: [runSh, ...extra], cwd: imagesPath };
|
|
1474
1815
|
}
|
|
1475
|
-
if (
|
|
1816
|
+
if (fs15.existsSync(runBat)) {
|
|
1476
1817
|
return { command: "bash", args: [runBat, ...extra], cwd: imagesPath };
|
|
1477
1818
|
}
|
|
1478
1819
|
throw new OniroError(`No emulator launcher (run.sh or run.bat) found in ${imagesPath}.`);
|
|
@@ -1480,9 +1821,9 @@ function resolveLauncher(imagesPath, headless, connect) {
|
|
|
1480
1821
|
async function startEmulator(opts) {
|
|
1481
1822
|
const { config } = opts;
|
|
1482
1823
|
const logger = opts.logger ?? noopLogger;
|
|
1483
|
-
if (
|
|
1824
|
+
if (os7.platform() !== "win32" && fs15.existsSync(PID_FILE)) {
|
|
1484
1825
|
try {
|
|
1485
|
-
const pid = Number(
|
|
1826
|
+
const pid = Number(fs15.readFileSync(PID_FILE, "utf8").trim());
|
|
1486
1827
|
if (Number.isFinite(pid) && pid > 0) {
|
|
1487
1828
|
try {
|
|
1488
1829
|
process.kill(pid, 0);
|
|
@@ -1498,13 +1839,13 @@ async function startEmulator(opts) {
|
|
|
1498
1839
|
logger.warn(`Could not read PID file: ${err.message}`);
|
|
1499
1840
|
}
|
|
1500
1841
|
}
|
|
1501
|
-
const imagesPath =
|
|
1502
|
-
if (!
|
|
1842
|
+
const imagesPath = path15.join(getEmulatorDir(config), "images");
|
|
1843
|
+
if (!fs15.existsSync(imagesPath)) {
|
|
1503
1844
|
throw new OniroError(`Emulator images directory not found at ${imagesPath}. Run \`oniro-app emulator install\` first.`);
|
|
1504
1845
|
}
|
|
1505
1846
|
const launcher = resolveLauncher(imagesPath, opts.headless === true, opts.connect);
|
|
1506
|
-
const logPath = opts.logFile ?? (
|
|
1507
|
-
const logFd =
|
|
1847
|
+
const logPath = opts.logFile ?? (os7.platform() === "win32" ? "NUL" : "/dev/null");
|
|
1848
|
+
const logFd = fs15.openSync(logPath, "a");
|
|
1508
1849
|
let child;
|
|
1509
1850
|
try {
|
|
1510
1851
|
child = (0, import_node_child_process4.spawn)(launcher.command, [...launcher.args], {
|
|
@@ -1514,19 +1855,19 @@ async function startEmulator(opts) {
|
|
|
1514
1855
|
windowsHide: true
|
|
1515
1856
|
});
|
|
1516
1857
|
} finally {
|
|
1517
|
-
|
|
1858
|
+
fs15.closeSync(logFd);
|
|
1518
1859
|
}
|
|
1519
1860
|
if (!child.pid) {
|
|
1520
1861
|
throw new OniroError(`Failed to spawn launcher (${launcher.command} ${launcher.args.join(" ")}).`);
|
|
1521
1862
|
}
|
|
1522
|
-
|
|
1863
|
+
fs15.writeFileSync(PID_FILE, String(child.pid));
|
|
1523
1864
|
child.unref();
|
|
1524
1865
|
logger.info(`Emulator launched (PID ${child.pid}). Logs: ${logPath}`);
|
|
1525
|
-
const earlyExit = new Promise((
|
|
1526
|
-
child.once("exit", (code) =>
|
|
1527
|
-
child.once("error", () =>
|
|
1866
|
+
const earlyExit = new Promise((resolve4) => {
|
|
1867
|
+
child.once("exit", (code) => resolve4(code));
|
|
1868
|
+
child.once("error", () => resolve4(-1));
|
|
1528
1869
|
});
|
|
1529
|
-
const liveness = new Promise((
|
|
1870
|
+
const liveness = new Promise((resolve4) => setTimeout(() => resolve4("alive"), 2e3));
|
|
1530
1871
|
const outcome = await Promise.race([earlyExit, liveness]);
|
|
1531
1872
|
if (outcome !== "alive") {
|
|
1532
1873
|
const tail = readTail(logPath, 4e3);
|
|
@@ -1566,24 +1907,24 @@ ${tail}` : ""}`);
|
|
|
1566
1907
|
}
|
|
1567
1908
|
function readTail(filePath, bytes) {
|
|
1568
1909
|
try {
|
|
1569
|
-
const stat =
|
|
1910
|
+
const stat = fs15.statSync(filePath);
|
|
1570
1911
|
const start = Math.max(0, stat.size - bytes);
|
|
1571
|
-
const fd =
|
|
1912
|
+
const fd = fs15.openSync(filePath, "r");
|
|
1572
1913
|
try {
|
|
1573
1914
|
const buf = Buffer.alloc(stat.size - start);
|
|
1574
|
-
|
|
1915
|
+
fs15.readSync(fd, buf, 0, buf.length, start);
|
|
1575
1916
|
return buf.toString("utf8");
|
|
1576
1917
|
} finally {
|
|
1577
|
-
|
|
1918
|
+
fs15.closeSync(fd);
|
|
1578
1919
|
}
|
|
1579
1920
|
} catch {
|
|
1580
1921
|
return "";
|
|
1581
1922
|
}
|
|
1582
1923
|
}
|
|
1583
1924
|
async function stopEmulator(logger = noopLogger) {
|
|
1584
|
-
if (
|
|
1925
|
+
if (fs15.existsSync(PID_FILE)) {
|
|
1585
1926
|
try {
|
|
1586
|
-
const pid = Number(
|
|
1927
|
+
const pid = Number(fs15.readFileSync(PID_FILE, "utf8").trim());
|
|
1587
1928
|
if (Number.isFinite(pid) && pid > 0) {
|
|
1588
1929
|
try {
|
|
1589
1930
|
process.kill(pid, "SIGTERM");
|
|
@@ -1596,13 +1937,13 @@ async function stopEmulator(logger = noopLogger) {
|
|
|
1596
1937
|
logger.warn(`Could not read PID file: ${err.message}`);
|
|
1597
1938
|
}
|
|
1598
1939
|
}
|
|
1599
|
-
const [killCmd, ...killArgs] =
|
|
1940
|
+
const [killCmd, ...killArgs] = os7.platform() === "win32" ? ["taskkill", "/IM", "qemu-system-x86_64.exe", "/F"] : ["pkill", "-f", "qemu-system-x86_64"];
|
|
1600
1941
|
try {
|
|
1601
1942
|
await runProcess({ command: killCmd, args: killArgs, logger });
|
|
1602
1943
|
} catch (err) {
|
|
1603
1944
|
logger.warn(`[emulator] could not run ${killCmd}: ${err.message}`);
|
|
1604
1945
|
}
|
|
1605
|
-
|
|
1946
|
+
fs15.rm(PID_FILE, { force: true }, (err) => {
|
|
1606
1947
|
if (err) logger.warn(`Could not remove PID file: ${err.message}`);
|
|
1607
1948
|
});
|
|
1608
1949
|
}
|
|
@@ -1725,7 +2066,7 @@ async function getDisplaySize(config, opts = {}) {
|
|
|
1725
2066
|
|
|
1726
2067
|
// src/hdc/wait.ts
|
|
1727
2068
|
function delay(ms, signal) {
|
|
1728
|
-
return new Promise((
|
|
2069
|
+
return new Promise((resolve4, reject) => {
|
|
1729
2070
|
if (signal?.aborted) {
|
|
1730
2071
|
reject(new CancelledError("Wait cancelled."));
|
|
1731
2072
|
return;
|
|
@@ -1740,7 +2081,7 @@ function delay(ms, signal) {
|
|
|
1740
2081
|
};
|
|
1741
2082
|
const timer = setTimeout(() => {
|
|
1742
2083
|
cleanup();
|
|
1743
|
-
|
|
2084
|
+
resolve4();
|
|
1744
2085
|
}, ms);
|
|
1745
2086
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1746
2087
|
});
|
|
@@ -1769,21 +2110,20 @@ async function waitForCondition(opts) {
|
|
|
1769
2110
|
}
|
|
1770
2111
|
|
|
1771
2112
|
// src/hdc/app.ts
|
|
1772
|
-
var
|
|
1773
|
-
var
|
|
1774
|
-
var import_node_child_process5 = require("child_process");
|
|
2113
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
2114
|
+
var path17 = __toESM(require("path"), 1);
|
|
1775
2115
|
|
|
1776
2116
|
// src/hdc/project.ts
|
|
1777
|
-
var
|
|
1778
|
-
var
|
|
2117
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
2118
|
+
var path16 = __toESM(require("path"), 1);
|
|
1779
2119
|
var import_json53 = __toESM(require("json5"), 1);
|
|
1780
2120
|
function readJson5(filePath) {
|
|
1781
|
-
const content =
|
|
2121
|
+
const content = fs16.readFileSync(filePath, "utf-8");
|
|
1782
2122
|
return import_json53.default.parse(content);
|
|
1783
2123
|
}
|
|
1784
2124
|
function getBundleName(projectDir) {
|
|
1785
|
-
const appJsonPath =
|
|
1786
|
-
if (!
|
|
2125
|
+
const appJsonPath = path16.join(projectDir, "AppScope", "app.json5");
|
|
2126
|
+
if (!fs16.existsSync(appJsonPath)) {
|
|
1787
2127
|
throw new OniroError(`Could not find app.json5 at ${appJsonPath}`);
|
|
1788
2128
|
}
|
|
1789
2129
|
const appJson = readJson5(appJsonPath);
|
|
@@ -1793,8 +2133,8 @@ function getBundleName(projectDir) {
|
|
|
1793
2133
|
return appJson.app.bundleName;
|
|
1794
2134
|
}
|
|
1795
2135
|
function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
1796
|
-
const moduleJsonPath =
|
|
1797
|
-
if (!
|
|
2136
|
+
const moduleJsonPath = path16.join(projectDir, moduleName, "src", "main", "module.json5");
|
|
2137
|
+
if (!fs16.existsSync(moduleJsonPath)) {
|
|
1798
2138
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
1799
2139
|
}
|
|
1800
2140
|
const moduleJson = readJson5(moduleJsonPath);
|
|
@@ -1817,8 +2157,8 @@ function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
|
1817
2157
|
async function installApp(opts) {
|
|
1818
2158
|
const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
|
|
1819
2159
|
const relativeHapPath = opts.hapPath ?? opts.config.get("hapPath", defaultPaths.hapPath);
|
|
1820
|
-
const hapPath =
|
|
1821
|
-
if (!
|
|
2160
|
+
const hapPath = path17.isAbsolute(relativeHapPath) ? relativeHapPath : path17.join(opts.projectDir, relativeHapPath);
|
|
2161
|
+
if (!fs17.existsSync(hapPath)) {
|
|
1822
2162
|
throw new OniroError(`HAP file not found at: ${hapPath}. Build and sign the app first.`);
|
|
1823
2163
|
}
|
|
1824
2164
|
const result = await hdcExec({ config: opts.config, args: ["install", hapPath], timeoutMs: 3e5 });
|
|
@@ -1835,13 +2175,59 @@ async function installApp(opts) {
|
|
|
1835
2175
|
function detectAaStartFailure(output) {
|
|
1836
2176
|
return /failed to start ability|Error Code:\s*\d|Error Message:/i.test(output) ? output.trim() : null;
|
|
1837
2177
|
}
|
|
2178
|
+
function parseMainAbilityFromBmDump(stdout) {
|
|
2179
|
+
const start = stdout.indexOf("{");
|
|
2180
|
+
if (start < 0) return null;
|
|
2181
|
+
let info;
|
|
2182
|
+
try {
|
|
2183
|
+
info = JSON.parse(stdout.slice(start));
|
|
2184
|
+
} catch {
|
|
2185
|
+
return null;
|
|
2186
|
+
}
|
|
2187
|
+
const mods = Array.isArray(info?.hapModuleInfos) ? info.hapModuleInfos : [];
|
|
2188
|
+
const abilityOf = (m) => m?.mainElementName || m?.mainAbility || void 0;
|
|
2189
|
+
const isEntry = (m) => m?.moduleType === 1 || m?.moduleType === "1" || m?.moduleType === "entry";
|
|
2190
|
+
const entry = mods.find((m) => isEntry(m) && abilityOf(m));
|
|
2191
|
+
const any = mods.find((m) => abilityOf(m));
|
|
2192
|
+
return entry && abilityOf(entry) || any && abilityOf(any) || null;
|
|
2193
|
+
}
|
|
2194
|
+
async function resolveInstalledMainAbility(opts) {
|
|
2195
|
+
const res = await shell({
|
|
2196
|
+
config: opts.config,
|
|
2197
|
+
command: `bm dump -n ${opts.bundle}`,
|
|
2198
|
+
deviceSerial: opts.deviceSerial,
|
|
2199
|
+
timeoutMs: 15e3,
|
|
2200
|
+
logger: opts.logger
|
|
2201
|
+
});
|
|
2202
|
+
const ability = parseMainAbilityFromBmDump(res.stdout);
|
|
2203
|
+
if (!ability) {
|
|
2204
|
+
throw new OniroError(
|
|
2205
|
+
`Could not determine the main ability for installed bundle ${opts.bundle} (is it installed?). Pass an explicit ability instead.`
|
|
2206
|
+
);
|
|
2207
|
+
}
|
|
2208
|
+
return ability;
|
|
2209
|
+
}
|
|
1838
2210
|
async function launchApp(opts) {
|
|
1839
2211
|
const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
|
|
1840
|
-
|
|
1841
|
-
|
|
2212
|
+
let bundleName;
|
|
2213
|
+
let mainAbility;
|
|
2214
|
+
if (opts.bundleName) {
|
|
2215
|
+
bundleName = opts.bundleName;
|
|
2216
|
+
mainAbility = opts.abilityName ?? await resolveInstalledMainAbility({
|
|
2217
|
+
config: opts.config,
|
|
2218
|
+
bundle: bundleName,
|
|
2219
|
+
deviceSerial: opts.deviceSerial,
|
|
2220
|
+
logger: opts.logger
|
|
2221
|
+
});
|
|
2222
|
+
} else {
|
|
2223
|
+
if (!opts.projectDir) throw new OniroError("launchApp requires either bundleName or projectDir.");
|
|
2224
|
+
bundleName = getBundleName(opts.projectDir);
|
|
2225
|
+
mainAbility = getMainAbility(opts.projectDir, opts.moduleName, opts.abilityName);
|
|
2226
|
+
}
|
|
1842
2227
|
const result = await hdcExec({
|
|
1843
2228
|
config: opts.config,
|
|
1844
|
-
args: ["shell", "aa", "start", "-a", mainAbility, "-b", bundleName]
|
|
2229
|
+
args: ["shell", "aa", "start", "-a", mainAbility, "-b", bundleName],
|
|
2230
|
+
deviceSerial: opts.deviceSerial
|
|
1845
2231
|
});
|
|
1846
2232
|
if (result.stdout.trim()) logger.info(result.stdout.trim());
|
|
1847
2233
|
if (result.stderr.trim()) logger.warn(result.stderr.trim());
|
|
@@ -1856,11 +2242,17 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1856
2242
|
const logger = options.logger ?? noopLogger;
|
|
1857
2243
|
const timeoutMs = options.timeoutMs ?? 1e3;
|
|
1858
2244
|
const hdc = getHdcPath(config);
|
|
1859
|
-
return new Promise((
|
|
1860
|
-
|
|
2245
|
+
return new Promise((resolve4, reject) => {
|
|
2246
|
+
let proc;
|
|
2247
|
+
try {
|
|
2248
|
+
proc = spawnCompat(hdc, ["track-jpid"]);
|
|
2249
|
+
} catch (err) {
|
|
2250
|
+
reject(new OniroError(`Failed to spawn ${hdc}: ${err instanceof Error ? err.message : String(err)}`, err));
|
|
2251
|
+
return;
|
|
2252
|
+
}
|
|
1861
2253
|
const processes = [];
|
|
1862
2254
|
let resolved = false;
|
|
1863
|
-
proc.stdout
|
|
2255
|
+
proc.stdout?.on("data", (data) => {
|
|
1864
2256
|
for (const line of data.toString().split("\n").filter(Boolean)) {
|
|
1865
2257
|
const match = line.match(/^(\d+)\s+(.+)$/);
|
|
1866
2258
|
if (!match) continue;
|
|
@@ -1869,13 +2261,13 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1869
2261
|
processes.push({ pid, name });
|
|
1870
2262
|
if (options.targetProcessName && name === options.targetProcessName && !resolved) {
|
|
1871
2263
|
resolved = true;
|
|
1872
|
-
proc
|
|
1873
|
-
|
|
2264
|
+
killProcessTree(proc);
|
|
2265
|
+
resolve4(pid);
|
|
1874
2266
|
return;
|
|
1875
2267
|
}
|
|
1876
2268
|
}
|
|
1877
2269
|
});
|
|
1878
|
-
proc.stderr
|
|
2270
|
+
proc.stderr?.on("data", (data) => {
|
|
1879
2271
|
logger.warn(`[hdc track-jpid] ${data.toString()}`);
|
|
1880
2272
|
});
|
|
1881
2273
|
proc.on("error", (err) => {
|
|
@@ -1887,11 +2279,11 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1887
2279
|
const timeout = setTimeout(() => {
|
|
1888
2280
|
if (resolved) return;
|
|
1889
2281
|
resolved = true;
|
|
1890
|
-
proc
|
|
2282
|
+
killProcessTree(proc);
|
|
1891
2283
|
if (options.targetProcessName) {
|
|
1892
2284
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
1893
2285
|
} else {
|
|
1894
|
-
|
|
2286
|
+
resolve4(processes);
|
|
1895
2287
|
}
|
|
1896
2288
|
}, timeoutMs);
|
|
1897
2289
|
proc.on("close", () => {
|
|
@@ -1901,7 +2293,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1901
2293
|
if (options.targetProcessName) {
|
|
1902
2294
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
1903
2295
|
} else {
|
|
1904
|
-
|
|
2296
|
+
resolve4(processes);
|
|
1905
2297
|
}
|
|
1906
2298
|
});
|
|
1907
2299
|
});
|
|
@@ -1921,8 +2313,17 @@ async function findRunningProcess(opts) {
|
|
|
1921
2313
|
logger: opts.logger
|
|
1922
2314
|
});
|
|
1923
2315
|
const pid = res.stdout.trim().split(/\s+/).filter(Boolean)[0];
|
|
1924
|
-
if (res.code
|
|
1925
|
-
|
|
2316
|
+
if (res.code === 0 && pid && /^\d+$/.test(pid)) return { pid, name: opts.bundle };
|
|
2317
|
+
try {
|
|
2318
|
+
const list = await listRunningProcesses(opts.config, { timeoutMs: 1200, logger: opts.logger });
|
|
2319
|
+
if (Array.isArray(list)) {
|
|
2320
|
+
const mine = (name) => name === opts.bundle || name.startsWith(`${opts.bundle}/`) || name.startsWith(`${opts.bundle}:`);
|
|
2321
|
+
const match = list.find((p) => p.name === opts.bundle) ?? list.find((p) => mine(p.name));
|
|
2322
|
+
if (match) return match;
|
|
2323
|
+
}
|
|
2324
|
+
} catch {
|
|
2325
|
+
}
|
|
2326
|
+
return null;
|
|
1926
2327
|
}
|
|
1927
2328
|
async function uninstallApp(opts) {
|
|
1928
2329
|
const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
|
|
@@ -2036,12 +2437,12 @@ async function reboot(opts) {
|
|
|
2036
2437
|
}
|
|
2037
2438
|
|
|
2038
2439
|
// src/hdc/screen.ts
|
|
2039
|
-
var
|
|
2040
|
-
var
|
|
2041
|
-
var
|
|
2440
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
2441
|
+
var os8 = __toESM(require("os"), 1);
|
|
2442
|
+
var path18 = __toESM(require("path"), 1);
|
|
2042
2443
|
var import_node_crypto = require("crypto");
|
|
2043
2444
|
function tmpName(ext) {
|
|
2044
|
-
return
|
|
2445
|
+
return path18.join(os8.tmpdir(), `oniro_screen_${(0, import_node_crypto.randomBytes)(6).toString("hex")}.${ext}`);
|
|
2045
2446
|
}
|
|
2046
2447
|
async function takeScreenshot(opts) {
|
|
2047
2448
|
const remote = "/data/local/tmp/oniro_screenshot.jpeg";
|
|
@@ -2051,11 +2452,11 @@ async function takeScreenshot(opts) {
|
|
|
2051
2452
|
const local = tmpName("jpeg");
|
|
2052
2453
|
try {
|
|
2053
2454
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
2054
|
-
const pixels = await
|
|
2455
|
+
const pixels = await fs18.promises.readFile(local);
|
|
2055
2456
|
const size = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial }) ?? { width: 0, height: 0 };
|
|
2056
2457
|
return { pixels, width: size.width, height: size.height };
|
|
2057
2458
|
} finally {
|
|
2058
|
-
|
|
2459
|
+
fs18.promises.unlink(local).catch(() => {
|
|
2059
2460
|
});
|
|
2060
2461
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
2061
2462
|
});
|
|
@@ -2074,9 +2475,9 @@ async function captureBurst(opts) {
|
|
|
2074
2475
|
const local = tmpName(`burst_${i}.jpeg`);
|
|
2075
2476
|
try {
|
|
2076
2477
|
await recvFile({ config: opts.config, remote: `${remoteDir}/f${i}.jpeg`, local, deviceSerial: opts.deviceSerial });
|
|
2077
|
-
frames.push(await
|
|
2478
|
+
frames.push(await fs18.promises.readFile(local));
|
|
2078
2479
|
} finally {
|
|
2079
|
-
|
|
2480
|
+
fs18.promises.unlink(local).catch(() => {
|
|
2080
2481
|
});
|
|
2081
2482
|
}
|
|
2082
2483
|
}
|
|
@@ -2120,8 +2521,8 @@ function buildInputCommand(opts) {
|
|
|
2120
2521
|
}
|
|
2121
2522
|
async function sendInput(opts) {
|
|
2122
2523
|
const cmd = buildInputCommand(opts);
|
|
2123
|
-
const res = await
|
|
2124
|
-
|
|
2524
|
+
const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
|
|
2525
|
+
ensureRemoteOk(res, `hdc shell ${cmd}`);
|
|
2125
2526
|
}
|
|
2126
2527
|
function buildGestureCommands(waypoints) {
|
|
2127
2528
|
if (waypoints.length < 2) {
|
|
@@ -2164,32 +2565,47 @@ function waypointsToRawEvents(waypoints, holdStartMs = 0, holdEndMs = 0) {
|
|
|
2164
2565
|
events.push({ type: "up", x: last.x, y: last.y, t: last.t + holdStartMs + holdEndMs });
|
|
2165
2566
|
return events;
|
|
2166
2567
|
}
|
|
2568
|
+
var UITEST_VELOCITY_MIN = 200;
|
|
2569
|
+
var UITEST_VELOCITY_MAX = 4e4;
|
|
2570
|
+
function buildGestureUitestCommand(waypoints, opts = {}) {
|
|
2571
|
+
if (waypoints.length < 2) throw new OniroError("sendGesture requires at least two waypoints.");
|
|
2572
|
+
const a = waypoints[0];
|
|
2573
|
+
const b = waypoints[waypoints.length - 1];
|
|
2574
|
+
const dist = Math.hypot(b.x - a.x, b.y - a.y);
|
|
2575
|
+
const dtMs = b.t - a.t;
|
|
2576
|
+
const op = (opts.holdStartMs ?? 0) > 0 ? "drag" : "swipe";
|
|
2577
|
+
let cmd = `uitest uiInput ${op} ${a.x} ${a.y} ${b.x} ${b.y}`;
|
|
2578
|
+
if (dtMs > 0 && dist > 0) {
|
|
2579
|
+
const v = Math.round(dist / (dtMs / 1e3));
|
|
2580
|
+
cmd += ` ${Math.max(UITEST_VELOCITY_MIN, Math.min(UITEST_VELOCITY_MAX, v))}`;
|
|
2581
|
+
}
|
|
2582
|
+
return cmd;
|
|
2583
|
+
}
|
|
2167
2584
|
async function sendGesture(opts) {
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
events: waypointsToRawEvents(opts.waypoints, opts.holdStartMs, opts.holdEndMs),
|
|
2173
|
-
deviceSerial: opts.deviceSerial,
|
|
2174
|
-
logger: opts.logger
|
|
2175
|
-
});
|
|
2176
|
-
return;
|
|
2585
|
+
if ((opts.holdEndMs ?? 0) > 0) {
|
|
2586
|
+
opts.logger?.warn(
|
|
2587
|
+
"sendGesture: hold-end has no uitest equivalent and is ignored; use sendRawTouch for a trailing hold."
|
|
2588
|
+
);
|
|
2177
2589
|
}
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2590
|
+
if (opts.waypoints.length > 2) {
|
|
2591
|
+
opts.logger?.debug(
|
|
2592
|
+
`sendGesture: ${opts.waypoints.length} waypoints collapsed to first\u2192last (uitest has no polyline path).`
|
|
2593
|
+
);
|
|
2181
2594
|
}
|
|
2595
|
+
const cmd = buildGestureUitestCommand(opts.waypoints, { holdStartMs: opts.holdStartMs });
|
|
2596
|
+
const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
|
|
2597
|
+
ensureRemoteOk(res, `hdc shell ${cmd}`);
|
|
2182
2598
|
}
|
|
2183
2599
|
async function sendRawTouch(opts) {
|
|
2184
2600
|
const cmd = buildRawTouchCommand(opts.events);
|
|
2185
|
-
const res = await
|
|
2186
|
-
|
|
2601
|
+
const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
|
|
2602
|
+
ensureRemoteOk(res, `hdc shell ${cmd}`);
|
|
2187
2603
|
}
|
|
2188
2604
|
|
|
2189
2605
|
// src/hdc/dump.ts
|
|
2190
|
-
var
|
|
2191
|
-
var
|
|
2192
|
-
var
|
|
2606
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
2607
|
+
var os9 = __toESM(require("os"), 1);
|
|
2608
|
+
var path19 = __toESM(require("path"), 1);
|
|
2193
2609
|
var import_node_crypto2 = require("crypto");
|
|
2194
2610
|
function parseBounds(s) {
|
|
2195
2611
|
const m = /^\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]$/.exec(s ?? "");
|
|
@@ -2274,10 +2690,10 @@ async function dumpLayout(opts) {
|
|
|
2274
2690
|
if (!m) throw new OniroError(`Could not parse dumpLayout output:
|
|
2275
2691
|
${dump.stdout}`);
|
|
2276
2692
|
const remote = m[1];
|
|
2277
|
-
const local =
|
|
2693
|
+
const local = path19.join(os9.tmpdir(), `oniro_layout_${(0, import_node_crypto2.randomBytes)(6).toString("hex")}.json`);
|
|
2278
2694
|
try {
|
|
2279
2695
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
2280
|
-
const parsed = JSON.parse(await
|
|
2696
|
+
const parsed = JSON.parse(await fs19.promises.readFile(local, "utf8"));
|
|
2281
2697
|
const display = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial });
|
|
2282
2698
|
if (opts.prune === false) {
|
|
2283
2699
|
return { display, tree: parsed };
|
|
@@ -2286,7 +2702,7 @@ ${dump.stdout}`);
|
|
|
2286
2702
|
const tree = Array.isArray(prunedRaw) ? { children: prunedRaw } : prunedRaw ?? { children: [] };
|
|
2287
2703
|
return { display, tree };
|
|
2288
2704
|
} finally {
|
|
2289
|
-
|
|
2705
|
+
fs19.promises.unlink(local).catch(() => {
|
|
2290
2706
|
});
|
|
2291
2707
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
2292
2708
|
});
|
|
@@ -2294,14 +2710,21 @@ ${dump.stdout}`);
|
|
|
2294
2710
|
}
|
|
2295
2711
|
|
|
2296
2712
|
// src/hdc/hilog.ts
|
|
2297
|
-
var import_node_child_process6 = require("child_process");
|
|
2298
2713
|
function setHilogLevel(opts) {
|
|
2299
2714
|
const logger = opts.logger ?? noopLogger;
|
|
2300
2715
|
const hdc = getHdcPath(opts.config);
|
|
2301
|
-
return new Promise((
|
|
2302
|
-
|
|
2716
|
+
return new Promise((resolve4, reject) => {
|
|
2717
|
+
let child;
|
|
2718
|
+
try {
|
|
2719
|
+
child = spawnCompat(hdc, ["shell", "hilog", "-b", opts.level]);
|
|
2720
|
+
} catch (err) {
|
|
2721
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2722
|
+
logger.error(`[hilog] failed to spawn hdc: ${msg}`);
|
|
2723
|
+
reject(err instanceof Error ? err : new Error(msg));
|
|
2724
|
+
return;
|
|
2725
|
+
}
|
|
2303
2726
|
let stderr = "";
|
|
2304
|
-
child.stderr
|
|
2727
|
+
child.stderr?.on("data", (chunk) => {
|
|
2305
2728
|
stderr += chunk.toString();
|
|
2306
2729
|
});
|
|
2307
2730
|
child.once("error", (err) => {
|
|
@@ -2310,7 +2733,7 @@ function setHilogLevel(opts) {
|
|
|
2310
2733
|
});
|
|
2311
2734
|
child.once("close", (code) => {
|
|
2312
2735
|
if (code === 0) {
|
|
2313
|
-
|
|
2736
|
+
resolve4();
|
|
2314
2737
|
} else {
|
|
2315
2738
|
const msg = stderr.trim() || `hdc shell hilog -b ${opts.level} exited with code ${code}`;
|
|
2316
2739
|
logger.error(`[hilog] ${msg}`);
|
|
@@ -2330,7 +2753,7 @@ function streamHilog(opts) {
|
|
|
2330
2753
|
if (opts.domain !== void 0 && `${opts.domain}` !== "") {
|
|
2331
2754
|
args.push("-D", `${opts.domain}`);
|
|
2332
2755
|
}
|
|
2333
|
-
return (
|
|
2756
|
+
return spawnCompat(hdc, args);
|
|
2334
2757
|
}
|
|
2335
2758
|
var HILOG_LINE_RE = /^(\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\s+(\d+)\s+(\d+)\s+([DIWEF])\s+(\S+):\s+(.*)$/;
|
|
2336
2759
|
function parseHilogLine(line) {
|
|
@@ -2365,7 +2788,7 @@ async function resolveProcessId(config, bundle, deviceSerial) {
|
|
|
2365
2788
|
return proc?.pid;
|
|
2366
2789
|
}
|
|
2367
2790
|
function waitForLog(opts) {
|
|
2368
|
-
return new Promise((
|
|
2791
|
+
return new Promise((resolve4, reject) => {
|
|
2369
2792
|
const deadline = Date.now() + opts.timeoutMs;
|
|
2370
2793
|
let settled = false;
|
|
2371
2794
|
let child = null;
|
|
@@ -2376,10 +2799,7 @@ function waitForLog(opts) {
|
|
|
2376
2799
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
2377
2800
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
2378
2801
|
if (child) {
|
|
2379
|
-
|
|
2380
|
-
child.kill("SIGKILL");
|
|
2381
|
-
} catch {
|
|
2382
|
-
}
|
|
2802
|
+
killProcessTree(child);
|
|
2383
2803
|
child = null;
|
|
2384
2804
|
}
|
|
2385
2805
|
};
|
|
@@ -2387,7 +2807,7 @@ function waitForLog(opts) {
|
|
|
2387
2807
|
if (settled) return;
|
|
2388
2808
|
settled = true;
|
|
2389
2809
|
cleanup();
|
|
2390
|
-
|
|
2810
|
+
resolve4(entry);
|
|
2391
2811
|
};
|
|
2392
2812
|
const fail = (err) => {
|
|
2393
2813
|
if (settled) return;
|
|
@@ -2395,6 +2815,7 @@ function waitForLog(opts) {
|
|
|
2395
2815
|
cleanup();
|
|
2396
2816
|
reject(err);
|
|
2397
2817
|
};
|
|
2818
|
+
const failWith = (err) => fail(err instanceof Error ? err : new Error(String(err)));
|
|
2398
2819
|
const onAbort = () => fail(new CancelledError("waitForLog cancelled."));
|
|
2399
2820
|
const timer = setTimeout(
|
|
2400
2821
|
() => fail(new OniroError(`No log line matched ${String(opts.pattern)} within ${opts.timeoutMs}ms.`)),
|
|
@@ -2424,17 +2845,17 @@ function waitForLog(opts) {
|
|
|
2424
2845
|
if (settled || child !== stream) return;
|
|
2425
2846
|
child = null;
|
|
2426
2847
|
if (Date.now() < deadline) {
|
|
2427
|
-
reconnectTimer = setTimeout(() => void spawnStream(), 1e3);
|
|
2848
|
+
reconnectTimer = setTimeout(() => void spawnStream().catch(failWith), 1e3);
|
|
2428
2849
|
}
|
|
2429
2850
|
};
|
|
2430
2851
|
stream.once("close", onEnd);
|
|
2431
2852
|
stream.once("error", onEnd);
|
|
2432
2853
|
};
|
|
2433
|
-
void spawnStream();
|
|
2854
|
+
void spawnStream().catch(failWith);
|
|
2434
2855
|
});
|
|
2435
2856
|
}
|
|
2436
2857
|
function watchLog(opts) {
|
|
2437
|
-
return new Promise((
|
|
2858
|
+
return new Promise((resolve4, reject) => {
|
|
2438
2859
|
const matches = [];
|
|
2439
2860
|
let settled = false;
|
|
2440
2861
|
let child = null;
|
|
@@ -2443,10 +2864,7 @@ function watchLog(opts) {
|
|
|
2443
2864
|
clearTimeout(timer);
|
|
2444
2865
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
2445
2866
|
if (child) {
|
|
2446
|
-
|
|
2447
|
-
child.kill("SIGKILL");
|
|
2448
|
-
} catch {
|
|
2449
|
-
}
|
|
2867
|
+
killProcessTree(child);
|
|
2450
2868
|
child = null;
|
|
2451
2869
|
}
|
|
2452
2870
|
};
|
|
@@ -2454,7 +2872,7 @@ function watchLog(opts) {
|
|
|
2454
2872
|
if (settled) return;
|
|
2455
2873
|
settled = true;
|
|
2456
2874
|
cleanup();
|
|
2457
|
-
|
|
2875
|
+
resolve4(opts.dedup === false ? matches : dedupEntries(matches));
|
|
2458
2876
|
};
|
|
2459
2877
|
const onAbort = () => {
|
|
2460
2878
|
if (settled) return;
|
|
@@ -2479,7 +2897,12 @@ function watchLog(opts) {
|
|
|
2479
2897
|
if (entry && opts.pattern.test(entryText(entry))) matches.push(entry);
|
|
2480
2898
|
}
|
|
2481
2899
|
});
|
|
2482
|
-
})()
|
|
2900
|
+
})().catch((err) => {
|
|
2901
|
+
if (settled) return;
|
|
2902
|
+
settled = true;
|
|
2903
|
+
cleanup();
|
|
2904
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
2905
|
+
});
|
|
2483
2906
|
});
|
|
2484
2907
|
}
|
|
2485
2908
|
async function dumpLog(opts) {
|
|
@@ -2506,9 +2929,8 @@ async function dumpLog(opts) {
|
|
|
2506
2929
|
}
|
|
2507
2930
|
|
|
2508
2931
|
// src/build/runHvigorw.ts
|
|
2509
|
-
var
|
|
2510
|
-
var
|
|
2511
|
-
var import_node_child_process7 = require("child_process");
|
|
2932
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
2933
|
+
var path20 = __toESM(require("path"), 1);
|
|
2512
2934
|
function buildHvigorwArgs(opts) {
|
|
2513
2935
|
const args = [opts.task ?? "assembleHap", "--mode", "module"];
|
|
2514
2936
|
args.push("-p", `product=${opts.product ?? "default"}`);
|
|
@@ -2520,19 +2942,23 @@ function buildHvigorwArgs(opts) {
|
|
|
2520
2942
|
return args;
|
|
2521
2943
|
}
|
|
2522
2944
|
function runHvigorw(opts) {
|
|
2523
|
-
const { config
|
|
2945
|
+
const { config } = opts;
|
|
2946
|
+
const projectDir = toLongPath(opts.projectDir);
|
|
2524
2947
|
const logger = opts.logger ?? noopLogger;
|
|
2525
|
-
if (!
|
|
2948
|
+
if (!fs20.existsSync(path20.join(projectDir, "build-profile.json5"))) {
|
|
2526
2949
|
throw new OniroError(`Not an OpenHarmony project: ${projectDir} (build-profile.json5 not found).`);
|
|
2527
2950
|
}
|
|
2528
|
-
if (!
|
|
2951
|
+
if (!fs20.existsSync(getCmdToolsPath(config))) {
|
|
2529
2952
|
throw new CmdToolsNotInstalledError(getCmdToolsPath(config));
|
|
2530
2953
|
}
|
|
2531
2954
|
const hvigorw = getHvigorwPath(config, projectDir);
|
|
2955
|
+
if (!fs20.existsSync(hvigorw)) {
|
|
2956
|
+
throw new OniroError(`hvigorw wrapper not found at ${hvigorw}.`);
|
|
2957
|
+
}
|
|
2532
2958
|
const args = buildHvigorwArgs(opts);
|
|
2533
2959
|
if (process.platform !== "win32") {
|
|
2534
2960
|
try {
|
|
2535
|
-
|
|
2961
|
+
fs20.chmodSync(hvigorw, 493);
|
|
2536
2962
|
} catch {
|
|
2537
2963
|
}
|
|
2538
2964
|
}
|
|
@@ -2540,32 +2966,35 @@ function runHvigorw(opts) {
|
|
|
2540
2966
|
...process.env,
|
|
2541
2967
|
OHOS_BASE_SDK_HOME: getOhosBaseSdkHome(config)
|
|
2542
2968
|
};
|
|
2543
|
-
return new Promise((
|
|
2969
|
+
return new Promise((resolve4, reject) => {
|
|
2544
2970
|
if (opts.abortSignal?.aborted) {
|
|
2545
2971
|
reject(new CancelledError("hvigorw build cancelled."));
|
|
2546
2972
|
return;
|
|
2547
2973
|
}
|
|
2548
2974
|
logger.info(`[build] ${hvigorw} ${args.join(" ")}`);
|
|
2549
|
-
|
|
2975
|
+
let child;
|
|
2976
|
+
try {
|
|
2977
|
+
child = spawnCompat(hvigorw, args, { cwd: projectDir, env });
|
|
2978
|
+
} catch (err) {
|
|
2979
|
+
reject(new OniroError(`Failed to start hvigorw: ${err instanceof Error ? err.message : String(err)}`, err));
|
|
2980
|
+
return;
|
|
2981
|
+
}
|
|
2550
2982
|
let settled = false;
|
|
2551
2983
|
const cleanup = () => opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
2552
2984
|
const onAbort = () => {
|
|
2553
2985
|
if (settled) return;
|
|
2554
2986
|
settled = true;
|
|
2555
2987
|
cleanup();
|
|
2556
|
-
|
|
2557
|
-
child.kill("SIGKILL");
|
|
2558
|
-
} catch {
|
|
2559
|
-
}
|
|
2988
|
+
killProcessTree(child);
|
|
2560
2989
|
reject(new CancelledError("hvigorw build cancelled."));
|
|
2561
2990
|
};
|
|
2562
2991
|
opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
2563
|
-
child.stdout
|
|
2992
|
+
child.stdout?.on("data", (chunk) => {
|
|
2564
2993
|
const text = chunk.toString();
|
|
2565
2994
|
opts.onOutput?.(text, "stdout");
|
|
2566
2995
|
logger.info(text.trimEnd());
|
|
2567
2996
|
});
|
|
2568
|
-
child.stderr
|
|
2997
|
+
child.stderr?.on("data", (chunk) => {
|
|
2569
2998
|
const text = chunk.toString();
|
|
2570
2999
|
opts.onOutput?.(text, "stderr");
|
|
2571
3000
|
logger.warn(text.trimEnd());
|
|
@@ -2581,19 +3010,18 @@ function runHvigorw(opts) {
|
|
|
2581
3010
|
settled = true;
|
|
2582
3011
|
cleanup();
|
|
2583
3012
|
const exitCode = code ?? 1;
|
|
2584
|
-
if (exitCode === 0)
|
|
3013
|
+
if (exitCode === 0) resolve4({ exitCode });
|
|
2585
3014
|
else reject(new OniroError(`hvigorw exited with code ${exitCode}`));
|
|
2586
3015
|
});
|
|
2587
3016
|
});
|
|
2588
3017
|
}
|
|
2589
3018
|
|
|
2590
3019
|
// src/build/discoverHaps.ts
|
|
2591
|
-
var
|
|
2592
|
-
var
|
|
2593
|
-
function
|
|
2594
|
-
const
|
|
2595
|
-
|
|
2596
|
-
return first && first !== ".." ? first : "(root)";
|
|
3020
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
3021
|
+
var path21 = __toESM(require("path"), 1);
|
|
3022
|
+
function moduleOfHap(hapFileName) {
|
|
3023
|
+
const dash = hapFileName.indexOf("-");
|
|
3024
|
+
return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
|
|
2597
3025
|
}
|
|
2598
3026
|
async function discoverHaps(opts) {
|
|
2599
3027
|
const { projectDir } = opts;
|
|
@@ -2601,14 +3029,14 @@ async function discoverHaps(opts) {
|
|
|
2601
3029
|
const result = {};
|
|
2602
3030
|
const walk = async (dir, depth) => {
|
|
2603
3031
|
if (depth > maxDepth) return;
|
|
2604
|
-
const entries = await
|
|
3032
|
+
const entries = await fs21.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
2605
3033
|
for (const e of entries) {
|
|
2606
|
-
const full =
|
|
3034
|
+
const full = path21.join(dir, e.name);
|
|
2607
3035
|
if (e.isDirectory()) {
|
|
2608
3036
|
if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
|
|
2609
3037
|
await walk(full, depth + 1);
|
|
2610
3038
|
} else if (e.isFile() && e.name.endsWith(".hap")) {
|
|
2611
|
-
const moduleName =
|
|
3039
|
+
const moduleName = moduleOfHap(e.name);
|
|
2612
3040
|
const bucket = result[moduleName] ??= { signed: [], unsigned: [] };
|
|
2613
3041
|
if (e.name.includes("unsigned")) bucket.unsigned.push(full);
|
|
2614
3042
|
else if (e.name.includes("signed")) bucket.signed.push(full);
|
|
@@ -2620,8 +3048,8 @@ async function discoverHaps(opts) {
|
|
|
2620
3048
|
}
|
|
2621
3049
|
|
|
2622
3050
|
// src/build/ohpm.ts
|
|
2623
|
-
var
|
|
2624
|
-
var
|
|
3051
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
3052
|
+
var path22 = __toESM(require("path"), 1);
|
|
2625
3053
|
function runOhpm(opts) {
|
|
2626
3054
|
return runProcess({
|
|
2627
3055
|
command: getOhpmPath(opts.config),
|
|
@@ -2634,7 +3062,7 @@ function runOhpm(opts) {
|
|
|
2634
3062
|
});
|
|
2635
3063
|
}
|
|
2636
3064
|
async function ensureOhModules(opts) {
|
|
2637
|
-
if (
|
|
3065
|
+
if (fs22.existsSync(path22.join(opts.projectDir, "oh_modules"))) {
|
|
2638
3066
|
return { installed: false };
|
|
2639
3067
|
}
|
|
2640
3068
|
const res = await runOhpm({
|
|
@@ -2686,10 +3114,11 @@ async function buildHap(opts) {
|
|
|
2686
3114
|
const logger = scopedLogger(opts.logger ?? noopLogger, "build");
|
|
2687
3115
|
const warnings = [];
|
|
2688
3116
|
const start = Date.now();
|
|
3117
|
+
const projectDir = toLongPath(opts.projectDir);
|
|
2689
3118
|
if (opts.autoInstallDeps !== false) {
|
|
2690
3119
|
const r = await ensureOhModules({
|
|
2691
3120
|
config: opts.config,
|
|
2692
|
-
projectDir
|
|
3121
|
+
projectDir,
|
|
2693
3122
|
abortSignal: opts.abortSignal,
|
|
2694
3123
|
onOutput: opts.onOutput,
|
|
2695
3124
|
logger: opts.logger
|
|
@@ -2698,7 +3127,7 @@ async function buildHap(opts) {
|
|
|
2698
3127
|
}
|
|
2699
3128
|
const { exitCode } = await runHvigorw({
|
|
2700
3129
|
config: opts.config,
|
|
2701
|
-
projectDir
|
|
3130
|
+
projectDir,
|
|
2702
3131
|
product: opts.product,
|
|
2703
3132
|
module: opts.module,
|
|
2704
3133
|
buildMode: opts.mode,
|
|
@@ -2708,7 +3137,7 @@ async function buildHap(opts) {
|
|
|
2708
3137
|
onOutput: opts.onOutput,
|
|
2709
3138
|
logger: opts.logger
|
|
2710
3139
|
});
|
|
2711
|
-
const discoveredHaps = await discoverHaps({ projectDir
|
|
3140
|
+
const discoveredHaps = await discoverHaps({ projectDir });
|
|
2712
3141
|
const anySigned = Object.values(discoveredHaps).some((m) => m.signed.length > 0);
|
|
2713
3142
|
if (!anySigned) {
|
|
2714
3143
|
warnings.push(
|
|
@@ -2729,21 +3158,21 @@ function isValidBundleName(bundleName) {
|
|
|
2729
3158
|
}
|
|
2730
3159
|
|
|
2731
3160
|
// src/project/templates.ts
|
|
2732
|
-
var
|
|
2733
|
-
var
|
|
3161
|
+
var fs23 = __toESM(require("fs"), 1);
|
|
3162
|
+
var path23 = __toESM(require("path"), 1);
|
|
2734
3163
|
function toHumanTemplateName(folderName) {
|
|
2735
3164
|
return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
2736
3165
|
}
|
|
2737
3166
|
function listTemplates(templateRoot) {
|
|
2738
|
-
if (!
|
|
2739
|
-
const entries =
|
|
3167
|
+
if (!fs23.existsSync(templateRoot)) return [];
|
|
3168
|
+
const entries = fs23.readdirSync(templateRoot, { withFileTypes: true });
|
|
2740
3169
|
return entries.filter((e) => e.isDirectory()).map((e) => {
|
|
2741
|
-
const dir =
|
|
2742
|
-
const metaPath =
|
|
3170
|
+
const dir = path23.join(templateRoot, e.name);
|
|
3171
|
+
const metaPath = path23.join(dir, "template.json");
|
|
2743
3172
|
let meta = {};
|
|
2744
|
-
if (
|
|
3173
|
+
if (fs23.existsSync(metaPath)) {
|
|
2745
3174
|
try {
|
|
2746
|
-
meta = JSON.parse(
|
|
3175
|
+
meta = JSON.parse(fs23.readFileSync(metaPath, "utf8"));
|
|
2747
3176
|
} catch {
|
|
2748
3177
|
}
|
|
2749
3178
|
}
|
|
@@ -2758,57 +3187,57 @@ function listTemplates(templateRoot) {
|
|
|
2758
3187
|
function validateTemplateLayout(templateDir, defaultModuleName) {
|
|
2759
3188
|
const required = [
|
|
2760
3189
|
"build-profile.json5",
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
3190
|
+
path23.join("AppScope", "app.json5"),
|
|
3191
|
+
path23.join(defaultModuleName, "src", "main", "module.json5"),
|
|
3192
|
+
path23.join(defaultModuleName, "oh-package.json5"),
|
|
2764
3193
|
"hvigorfile.ts"
|
|
2765
3194
|
];
|
|
2766
|
-
return required.filter((rel) => !
|
|
3195
|
+
return required.filter((rel) => !fs23.existsSync(path23.join(templateDir, rel)));
|
|
2767
3196
|
}
|
|
2768
3197
|
|
|
2769
3198
|
// src/project/createScaffold.ts
|
|
2770
|
-
var
|
|
2771
|
-
var
|
|
3199
|
+
var fs25 = __toESM(require("fs"), 1);
|
|
3200
|
+
var path24 = __toESM(require("path"), 1);
|
|
2772
3201
|
|
|
2773
3202
|
// src/project/jsonHelpers.ts
|
|
2774
|
-
var
|
|
3203
|
+
var fs24 = __toESM(require("fs"), 1);
|
|
2775
3204
|
var import_json54 = __toESM(require("json5"), 1);
|
|
2776
3205
|
function readJson5File(filePath) {
|
|
2777
|
-
return import_json54.default.parse(
|
|
3206
|
+
return import_json54.default.parse(fs24.readFileSync(filePath, "utf8"));
|
|
2778
3207
|
}
|
|
2779
3208
|
function writeJson5File(filePath, value) {
|
|
2780
|
-
|
|
3209
|
+
fs24.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
2781
3210
|
}
|
|
2782
3211
|
function readJsonFile(filePath) {
|
|
2783
|
-
return JSON.parse(
|
|
3212
|
+
return JSON.parse(fs24.readFileSync(filePath, "utf8"));
|
|
2784
3213
|
}
|
|
2785
3214
|
function writeJsonFile(filePath, value) {
|
|
2786
|
-
|
|
3215
|
+
fs24.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
2787
3216
|
}
|
|
2788
3217
|
|
|
2789
3218
|
// src/project/createScaffold.ts
|
|
2790
3219
|
var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
|
|
2791
3220
|
async function pathExists(p) {
|
|
2792
3221
|
try {
|
|
2793
|
-
await
|
|
3222
|
+
await fs25.promises.access(p);
|
|
2794
3223
|
return true;
|
|
2795
3224
|
} catch {
|
|
2796
3225
|
return false;
|
|
2797
3226
|
}
|
|
2798
3227
|
}
|
|
2799
3228
|
async function copyDirRecursive(srcDir, destDir) {
|
|
2800
|
-
await
|
|
2801
|
-
const entries = await
|
|
3229
|
+
await fs25.promises.mkdir(destDir, { recursive: true });
|
|
3230
|
+
const entries = await fs25.promises.readdir(srcDir, { withFileTypes: true });
|
|
2802
3231
|
for (const entry of entries) {
|
|
2803
|
-
const src =
|
|
2804
|
-
const dest =
|
|
3232
|
+
const src = path24.join(srcDir, entry.name);
|
|
3233
|
+
const dest = path24.join(destDir, entry.name);
|
|
2805
3234
|
if (entry.isDirectory()) {
|
|
2806
3235
|
await copyDirRecursive(src, dest);
|
|
2807
3236
|
} else if (entry.isSymbolicLink()) {
|
|
2808
3237
|
continue;
|
|
2809
3238
|
} else if (entry.isFile()) {
|
|
2810
3239
|
if (entry.name === "template.json") continue;
|
|
2811
|
-
await
|
|
3240
|
+
await fs25.promises.copyFile(src, dest);
|
|
2812
3241
|
}
|
|
2813
3242
|
}
|
|
2814
3243
|
}
|
|
@@ -2816,9 +3245,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
|
|
|
2816
3245
|
const stack = [projectDir];
|
|
2817
3246
|
while (stack.length > 0) {
|
|
2818
3247
|
const currentDir = stack.pop();
|
|
2819
|
-
const entries = await
|
|
3248
|
+
const entries = await fs25.promises.readdir(currentDir, { withFileTypes: true });
|
|
2820
3249
|
for (const entry of entries) {
|
|
2821
|
-
const fullPath =
|
|
3250
|
+
const fullPath = path24.join(currentDir, entry.name);
|
|
2822
3251
|
if (entry.isDirectory()) {
|
|
2823
3252
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
2824
3253
|
stack.push(fullPath);
|
|
@@ -2840,23 +3269,23 @@ function toJavaPropertiesPath(p) {
|
|
|
2840
3269
|
function createOrUpdateLocalProperties(projectDir, sdkDir) {
|
|
2841
3270
|
const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
|
|
2842
3271
|
`;
|
|
2843
|
-
|
|
3272
|
+
fs25.writeFileSync(path24.join(projectDir, "local.properties"), content, "utf8");
|
|
2844
3273
|
}
|
|
2845
3274
|
function renameIfExists(fromPath, toPath) {
|
|
2846
|
-
if (
|
|
2847
|
-
|
|
3275
|
+
if (fs25.existsSync(fromPath) && fromPath !== toPath) {
|
|
3276
|
+
fs25.renameSync(fromPath, toPath);
|
|
2848
3277
|
}
|
|
2849
3278
|
}
|
|
2850
3279
|
function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
2851
|
-
const appJsonPath =
|
|
2852
|
-
if (
|
|
3280
|
+
const appJsonPath = path24.join(projectDir, "AppScope", "app.json5");
|
|
3281
|
+
if (fs25.existsSync(appJsonPath)) {
|
|
2853
3282
|
const appJson = readJson5File(appJsonPath);
|
|
2854
3283
|
appJson.app = appJson.app ?? {};
|
|
2855
3284
|
appJson.app.bundleName = args.bundleName;
|
|
2856
3285
|
writeJson5File(appJsonPath, appJson);
|
|
2857
3286
|
}
|
|
2858
|
-
const stringsPath =
|
|
2859
|
-
if (
|
|
3287
|
+
const stringsPath = path24.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
|
|
3288
|
+
if (fs25.existsSync(stringsPath)) {
|
|
2860
3289
|
const strings = readJsonFile(stringsPath);
|
|
2861
3290
|
if (Array.isArray(strings.string)) {
|
|
2862
3291
|
const appName = strings.string.find((s) => s.name === "app_name");
|
|
@@ -2864,8 +3293,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
2864
3293
|
}
|
|
2865
3294
|
writeJsonFile(stringsPath, strings);
|
|
2866
3295
|
}
|
|
2867
|
-
const buildProfilePath =
|
|
2868
|
-
if (
|
|
3296
|
+
const buildProfilePath = path24.join(projectDir, "build-profile.json5");
|
|
3297
|
+
if (fs25.existsSync(buildProfilePath)) {
|
|
2869
3298
|
const buildProfile = readJson5File(buildProfilePath);
|
|
2870
3299
|
buildProfile.app = buildProfile.app ?? {};
|
|
2871
3300
|
if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
|
|
@@ -2878,23 +3307,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
2878
3307
|
}
|
|
2879
3308
|
writeJson5File(buildProfilePath, buildProfile);
|
|
2880
3309
|
}
|
|
2881
|
-
const moduleJsonPath =
|
|
2882
|
-
if (
|
|
3310
|
+
const moduleJsonPath = path24.join(projectDir, args.moduleName, "src", "main", "module.json5");
|
|
3311
|
+
if (fs25.existsSync(moduleJsonPath)) {
|
|
2883
3312
|
const moduleJson = readJson5File(moduleJsonPath);
|
|
2884
3313
|
moduleJson.module = moduleJson.module ?? {};
|
|
2885
3314
|
moduleJson.module.name = args.moduleName;
|
|
2886
3315
|
writeJson5File(moduleJsonPath, moduleJson);
|
|
2887
3316
|
}
|
|
2888
|
-
const moduleOhPackagePath =
|
|
2889
|
-
if (
|
|
3317
|
+
const moduleOhPackagePath = path24.join(projectDir, args.moduleName, "oh-package.json5");
|
|
3318
|
+
if (fs25.existsSync(moduleOhPackagePath)) {
|
|
2890
3319
|
const pkg = readJson5File(moduleOhPackagePath);
|
|
2891
3320
|
pkg.name = args.moduleName;
|
|
2892
3321
|
writeJson5File(moduleOhPackagePath, pkg);
|
|
2893
3322
|
}
|
|
2894
|
-
const vscodeDir =
|
|
2895
|
-
|
|
3323
|
+
const vscodeDir = path24.join(projectDir, ".vscode");
|
|
3324
|
+
fs25.mkdirSync(vscodeDir, { recursive: true });
|
|
2896
3325
|
const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
|
|
2897
|
-
writeJsonFile(
|
|
3326
|
+
writeJsonFile(path24.join(vscodeDir, "settings.json"), {
|
|
2898
3327
|
"oniro.hapPath": hapPath,
|
|
2899
3328
|
"files.associations": { "*.json5": "jsonc" }
|
|
2900
3329
|
});
|
|
@@ -2911,7 +3340,7 @@ async function createScaffold(opts) {
|
|
|
2911
3340
|
if (!opts.location || !await pathExists(opts.location)) {
|
|
2912
3341
|
throw new OniroError(`Location does not exist: ${opts.location}`);
|
|
2913
3342
|
}
|
|
2914
|
-
const templateDir =
|
|
3343
|
+
const templateDir = path24.join(opts.templateRoot, opts.templateId);
|
|
2915
3344
|
if (!await pathExists(templateDir)) {
|
|
2916
3345
|
throw new OniroError(`Template not found: ${templateDir}`);
|
|
2917
3346
|
}
|
|
@@ -2924,17 +3353,17 @@ async function createScaffold(opts) {
|
|
|
2924
3353
|
throw new OniroError(`Template '${opts.templateId}' is missing required files:
|
|
2925
3354
|
- ${missing.join("\n- ")}`);
|
|
2926
3355
|
}
|
|
2927
|
-
const projectDir =
|
|
3356
|
+
const projectDir = path24.join(opts.location, opts.projectName);
|
|
2928
3357
|
if (await pathExists(projectDir)) {
|
|
2929
3358
|
if (!opts.overwrite) {
|
|
2930
3359
|
throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
|
|
2931
3360
|
}
|
|
2932
|
-
await
|
|
3361
|
+
await fs25.promises.rm(projectDir, { recursive: true, force: true });
|
|
2933
3362
|
}
|
|
2934
3363
|
logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
|
|
2935
3364
|
await copyDirRecursive(templateDir, projectDir);
|
|
2936
3365
|
if (moduleName !== defaultModuleName) {
|
|
2937
|
-
renameIfExists(
|
|
3366
|
+
renameIfExists(path24.join(projectDir, defaultModuleName), path24.join(projectDir, moduleName));
|
|
2938
3367
|
}
|
|
2939
3368
|
updateTemplateConfigs(
|
|
2940
3369
|
projectDir,
|
|
@@ -2951,11 +3380,11 @@ async function createScaffold(opts) {
|
|
|
2951
3380
|
}
|
|
2952
3381
|
|
|
2953
3382
|
// src/project/listModules.ts
|
|
2954
|
-
var
|
|
2955
|
-
var
|
|
3383
|
+
var fs26 = __toESM(require("fs"), 1);
|
|
3384
|
+
var path25 = __toESM(require("path"), 1);
|
|
2956
3385
|
function listModules(opts) {
|
|
2957
|
-
const buildProfile =
|
|
2958
|
-
if (!
|
|
3386
|
+
const buildProfile = path25.join(opts.projectDir, "build-profile.json5");
|
|
3387
|
+
if (!fs26.existsSync(buildProfile)) {
|
|
2959
3388
|
throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
|
|
2960
3389
|
}
|
|
2961
3390
|
const parsed = readJson5File(buildProfile);
|
|
@@ -2967,12 +3396,12 @@ function listModules(opts) {
|
|
|
2967
3396
|
}
|
|
2968
3397
|
|
|
2969
3398
|
// src/project/abilities.ts
|
|
2970
|
-
var
|
|
2971
|
-
var
|
|
3399
|
+
var fs27 = __toESM(require("fs"), 1);
|
|
3400
|
+
var path26 = __toESM(require("path"), 1);
|
|
2972
3401
|
function listAbilities(opts) {
|
|
2973
3402
|
const moduleName = opts.moduleName ?? "entry";
|
|
2974
|
-
const moduleJsonPath =
|
|
2975
|
-
if (!
|
|
3403
|
+
const moduleJsonPath = path26.join(opts.projectDir, moduleName, "src", "main", "module.json5");
|
|
3404
|
+
if (!fs27.existsSync(moduleJsonPath)) {
|
|
2976
3405
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
2977
3406
|
}
|
|
2978
3407
|
const parsed = readJson5File(moduleJsonPath);
|
|
@@ -2980,12 +3409,12 @@ function listAbilities(opts) {
|
|
|
2980
3409
|
}
|
|
2981
3410
|
|
|
2982
3411
|
// src/project/prepareSigning.ts
|
|
2983
|
-
var
|
|
2984
|
-
var
|
|
3412
|
+
var fs28 = __toESM(require("fs"), 1);
|
|
3413
|
+
var path27 = __toESM(require("path"), 1);
|
|
2985
3414
|
function hasSigningArtifacts(dir) {
|
|
2986
|
-
if (!
|
|
2987
|
-
const buildProfile =
|
|
2988
|
-
if (!
|
|
3415
|
+
if (!fs28.existsSync(path27.join(dir, "signatures"))) return false;
|
|
3416
|
+
const buildProfile = path27.join(dir, "build-profile.json5");
|
|
3417
|
+
if (!fs28.existsSync(buildProfile)) return false;
|
|
2989
3418
|
try {
|
|
2990
3419
|
const parsed = readJson5File(buildProfile);
|
|
2991
3420
|
return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
|
|
@@ -3075,8 +3504,8 @@ async function diffHapAssets(opts) {
|
|
|
3075
3504
|
}
|
|
3076
3505
|
|
|
3077
3506
|
// src/install/apply.ts
|
|
3078
|
-
var
|
|
3079
|
-
var
|
|
3507
|
+
var fs29 = __toESM(require("fs"), 1);
|
|
3508
|
+
var path28 = __toESM(require("path"), 1);
|
|
3080
3509
|
function decideInstallMethod(s) {
|
|
3081
3510
|
if (!s.signInfoInconsistent) return "replace";
|
|
3082
3511
|
if (s.isSystemBundle && !s.allowUninstall) return "refuse";
|
|
@@ -3097,7 +3526,7 @@ async function pidOf(config, bundle, deviceSerial) {
|
|
|
3097
3526
|
async function resolveHapPath(opts) {
|
|
3098
3527
|
let hapPath = opts.hapPath;
|
|
3099
3528
|
if (hapPath) {
|
|
3100
|
-
if (!
|
|
3529
|
+
if (!path28.isAbsolute(hapPath) && opts.projectDir) hapPath = path28.join(opts.projectDir, hapPath);
|
|
3101
3530
|
} else {
|
|
3102
3531
|
if (!opts.projectDir) throw new OniroError("applyChanges requires hapPath or projectDir.");
|
|
3103
3532
|
const haps = await discoverHaps({ projectDir: opts.projectDir });
|
|
@@ -3116,7 +3545,7 @@ async function resolveHapPath(opts) {
|
|
|
3116
3545
|
hapPath = withSigned[0][1].signed[0];
|
|
3117
3546
|
}
|
|
3118
3547
|
}
|
|
3119
|
-
if (!
|
|
3548
|
+
if (!fs29.existsSync(hapPath)) throw new OniroError(`HAP not found at ${hapPath}.`);
|
|
3120
3549
|
return hapPath;
|
|
3121
3550
|
}
|
|
3122
3551
|
async function applyChanges(opts) {
|
|
@@ -3126,7 +3555,7 @@ async function applyChanges(opts) {
|
|
|
3126
3555
|
const allowUninstall = opts.allowUninstall ?? false;
|
|
3127
3556
|
const hapPath = await resolveHapPath(opts);
|
|
3128
3557
|
let assetsChanged = false;
|
|
3129
|
-
if (opts.installedHapPath &&
|
|
3558
|
+
if (opts.installedHapPath && fs29.existsSync(opts.installedHapPath)) {
|
|
3130
3559
|
try {
|
|
3131
3560
|
const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
|
|
3132
3561
|
assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
|
|
@@ -3168,7 +3597,7 @@ async function applyChanges(opts) {
|
|
|
3168
3597
|
}
|
|
3169
3598
|
|
|
3170
3599
|
// src/index.ts
|
|
3171
|
-
var VERSION = "0.
|
|
3600
|
+
var VERSION = "0.9.0";
|
|
3172
3601
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3173
3602
|
0 && (module.exports = {
|
|
3174
3603
|
ALL_SDKS,
|
|
@@ -3178,22 +3607,29 @@ var VERSION = "0.7.0";
|
|
|
3178
3607
|
ChecksumMismatchError,
|
|
3179
3608
|
CmdToolsNotInstalledError,
|
|
3180
3609
|
CommandFailedError,
|
|
3610
|
+
INSTALL_TMP_DIRNAME,
|
|
3611
|
+
InsufficientSpaceError,
|
|
3181
3612
|
OHOS_URL_BASE,
|
|
3182
3613
|
OniroError,
|
|
3183
3614
|
SdkNotInstalledError,
|
|
3615
|
+
TMP_DIR_HINT,
|
|
3184
3616
|
UnsupportedPlatformError,
|
|
3185
3617
|
VERSION,
|
|
3186
3618
|
applyChanges,
|
|
3187
3619
|
attemptHdcConnection,
|
|
3620
|
+
buildCmdWrapper,
|
|
3188
3621
|
buildGestureCommands,
|
|
3622
|
+
buildGestureUitestCommand,
|
|
3189
3623
|
buildHap,
|
|
3190
3624
|
buildHvigorwArgs,
|
|
3191
3625
|
buildInputCommand,
|
|
3192
3626
|
buildRawTouchCommand,
|
|
3193
3627
|
captureBurst,
|
|
3194
3628
|
consoleLogger,
|
|
3629
|
+
createInstallTempDir,
|
|
3195
3630
|
createMaterial,
|
|
3196
3631
|
createScaffold,
|
|
3632
|
+
createTempWorkDir,
|
|
3197
3633
|
decideInstallMethod,
|
|
3198
3634
|
decideReboot,
|
|
3199
3635
|
decryptPwd,
|
|
@@ -3214,14 +3650,19 @@ var VERSION = "0.7.0";
|
|
|
3214
3650
|
dumpScreen,
|
|
3215
3651
|
dumpWindow,
|
|
3216
3652
|
encryptPwd,
|
|
3653
|
+
ensureFreeSpace,
|
|
3217
3654
|
ensureOhModules,
|
|
3218
3655
|
ensureOk,
|
|
3656
|
+
ensureRemoteOk,
|
|
3657
|
+
escapeCmdArgument,
|
|
3658
|
+
escapeCmdCommand,
|
|
3219
3659
|
extractTarball,
|
|
3220
3660
|
extractZipWithProgress,
|
|
3221
3661
|
findAppProcessId,
|
|
3222
3662
|
findCmdToolsSourceDir,
|
|
3223
3663
|
findRunningProcess,
|
|
3224
3664
|
forceStop,
|
|
3665
|
+
formatBytes,
|
|
3225
3666
|
generateSigningConfigs,
|
|
3226
3667
|
getBundleName,
|
|
3227
3668
|
getCmdToolsBin,
|
|
@@ -3231,6 +3672,7 @@ var VERSION = "0.7.0";
|
|
|
3231
3672
|
getDeviceInfo,
|
|
3232
3673
|
getDisplaySize,
|
|
3233
3674
|
getEmulatorDir,
|
|
3675
|
+
getFreeSpaceBytes,
|
|
3234
3676
|
getHdcPath,
|
|
3235
3677
|
getHvigorwPath,
|
|
3236
3678
|
getInstalledSdks,
|
|
@@ -3248,14 +3690,18 @@ var VERSION = "0.7.0";
|
|
|
3248
3690
|
installEmulator,
|
|
3249
3691
|
isCmdToolsInstalled,
|
|
3250
3692
|
isEmulatorInstalled,
|
|
3693
|
+
isOutOfSpaceError,
|
|
3694
|
+
isRamBackedPath,
|
|
3251
3695
|
isValidBundleName,
|
|
3252
3696
|
isValidProjectName,
|
|
3697
|
+
killProcessTree,
|
|
3253
3698
|
launchApp,
|
|
3254
3699
|
listAbilities,
|
|
3255
3700
|
listDevices,
|
|
3256
3701
|
listModules,
|
|
3257
3702
|
listRunningProcesses,
|
|
3258
3703
|
listTemplates,
|
|
3704
|
+
needsCmdWrapper,
|
|
3259
3705
|
nonInteractivePrompter,
|
|
3260
3706
|
noopLogger,
|
|
3261
3707
|
noopProgress,
|
|
@@ -3265,6 +3711,8 @@ var VERSION = "0.7.0";
|
|
|
3265
3711
|
parseCodelinterFindings,
|
|
3266
3712
|
parseDeviceList,
|
|
3267
3713
|
parseHilogLine,
|
|
3714
|
+
parseMainAbilityFromBmDump,
|
|
3715
|
+
parseRemoteExit,
|
|
3268
3716
|
pickSigningKind,
|
|
3269
3717
|
prepareSigning,
|
|
3270
3718
|
pruneLayout,
|
|
@@ -3275,6 +3723,8 @@ var VERSION = "0.7.0";
|
|
|
3275
3723
|
removeCmdTools,
|
|
3276
3724
|
removeEmulator,
|
|
3277
3725
|
removeSdk,
|
|
3726
|
+
removeTempWorkDir,
|
|
3727
|
+
resolveTmpRoot,
|
|
3278
3728
|
runCodelinter,
|
|
3279
3729
|
runHvigorw,
|
|
3280
3730
|
runOhpm,
|
|
@@ -3287,11 +3737,15 @@ var VERSION = "0.7.0";
|
|
|
3287
3737
|
sendRawTouch,
|
|
3288
3738
|
setHilogLevel,
|
|
3289
3739
|
shell,
|
|
3740
|
+
shellChecked,
|
|
3741
|
+
spawnCompat,
|
|
3290
3742
|
startEmulator,
|
|
3291
3743
|
staticConfig,
|
|
3292
3744
|
stopEmulator,
|
|
3293
3745
|
streamHilog,
|
|
3294
3746
|
takeScreenshot,
|
|
3747
|
+
toLongPath,
|
|
3748
|
+
toSpaceError,
|
|
3295
3749
|
uninstallApp,
|
|
3296
3750
|
validateTemplateLayout,
|
|
3297
3751
|
verifySha256,
|
|
@@ -3300,6 +3754,7 @@ var VERSION = "0.7.0";
|
|
|
3300
3754
|
waitForCondition,
|
|
3301
3755
|
waitForLog,
|
|
3302
3756
|
watchLog,
|
|
3757
|
+
waypointsToRawEvents,
|
|
3303
3758
|
writeJson5File,
|
|
3304
3759
|
writeJsonFile
|
|
3305
3760
|
});
|