@oniroproject/core 0.7.0 → 0.8.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 +717 -390
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +211 -16
- package/dist/index.d.ts +211 -16
- package/dist/index.js +698 -390
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -37,22 +37,28 @@ __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,
|
|
47
50
|
buildGestureCommands: () => buildGestureCommands,
|
|
51
|
+
buildGestureUitestCommand: () => buildGestureUitestCommand,
|
|
48
52
|
buildHap: () => buildHap,
|
|
49
53
|
buildHvigorwArgs: () => buildHvigorwArgs,
|
|
50
54
|
buildInputCommand: () => buildInputCommand,
|
|
51
55
|
buildRawTouchCommand: () => buildRawTouchCommand,
|
|
52
56
|
captureBurst: () => captureBurst,
|
|
53
57
|
consoleLogger: () => consoleLogger,
|
|
58
|
+
createInstallTempDir: () => createInstallTempDir,
|
|
54
59
|
createMaterial: () => createMaterial,
|
|
55
60
|
createScaffold: () => createScaffold,
|
|
61
|
+
createTempWorkDir: () => createTempWorkDir,
|
|
56
62
|
decideInstallMethod: () => decideInstallMethod,
|
|
57
63
|
decideReboot: () => decideReboot,
|
|
58
64
|
decryptPwd: () => decryptPwd,
|
|
@@ -73,14 +79,17 @@ __export(index_exports, {
|
|
|
73
79
|
dumpScreen: () => dumpScreen,
|
|
74
80
|
dumpWindow: () => dumpWindow,
|
|
75
81
|
encryptPwd: () => encryptPwd,
|
|
82
|
+
ensureFreeSpace: () => ensureFreeSpace,
|
|
76
83
|
ensureOhModules: () => ensureOhModules,
|
|
77
84
|
ensureOk: () => ensureOk,
|
|
85
|
+
ensureRemoteOk: () => ensureRemoteOk,
|
|
78
86
|
extractTarball: () => extractTarball,
|
|
79
87
|
extractZipWithProgress: () => extractZipWithProgress,
|
|
80
88
|
findAppProcessId: () => findAppProcessId,
|
|
81
89
|
findCmdToolsSourceDir: () => findCmdToolsSourceDir,
|
|
82
90
|
findRunningProcess: () => findRunningProcess,
|
|
83
91
|
forceStop: () => forceStop,
|
|
92
|
+
formatBytes: () => formatBytes,
|
|
84
93
|
generateSigningConfigs: () => generateSigningConfigs,
|
|
85
94
|
getBundleName: () => getBundleName,
|
|
86
95
|
getCmdToolsBin: () => getCmdToolsBin,
|
|
@@ -90,6 +99,7 @@ __export(index_exports, {
|
|
|
90
99
|
getDeviceInfo: () => getDeviceInfo,
|
|
91
100
|
getDisplaySize: () => getDisplaySize,
|
|
92
101
|
getEmulatorDir: () => getEmulatorDir,
|
|
102
|
+
getFreeSpaceBytes: () => getFreeSpaceBytes,
|
|
93
103
|
getHdcPath: () => getHdcPath,
|
|
94
104
|
getHvigorwPath: () => getHvigorwPath,
|
|
95
105
|
getInstalledSdks: () => getInstalledSdks,
|
|
@@ -107,6 +117,8 @@ __export(index_exports, {
|
|
|
107
117
|
installEmulator: () => installEmulator,
|
|
108
118
|
isCmdToolsInstalled: () => isCmdToolsInstalled,
|
|
109
119
|
isEmulatorInstalled: () => isEmulatorInstalled,
|
|
120
|
+
isOutOfSpaceError: () => isOutOfSpaceError,
|
|
121
|
+
isRamBackedPath: () => isRamBackedPath,
|
|
110
122
|
isValidBundleName: () => isValidBundleName,
|
|
111
123
|
isValidProjectName: () => isValidProjectName,
|
|
112
124
|
launchApp: () => launchApp,
|
|
@@ -124,6 +136,8 @@ __export(index_exports, {
|
|
|
124
136
|
parseCodelinterFindings: () => parseCodelinterFindings,
|
|
125
137
|
parseDeviceList: () => parseDeviceList,
|
|
126
138
|
parseHilogLine: () => parseHilogLine,
|
|
139
|
+
parseMainAbilityFromBmDump: () => parseMainAbilityFromBmDump,
|
|
140
|
+
parseRemoteExit: () => parseRemoteExit,
|
|
127
141
|
pickSigningKind: () => pickSigningKind,
|
|
128
142
|
prepareSigning: () => prepareSigning,
|
|
129
143
|
pruneLayout: () => pruneLayout,
|
|
@@ -134,6 +148,8 @@ __export(index_exports, {
|
|
|
134
148
|
removeCmdTools: () => removeCmdTools,
|
|
135
149
|
removeEmulator: () => removeEmulator,
|
|
136
150
|
removeSdk: () => removeSdk,
|
|
151
|
+
removeTempWorkDir: () => removeTempWorkDir,
|
|
152
|
+
resolveTmpRoot: () => resolveTmpRoot,
|
|
137
153
|
runCodelinter: () => runCodelinter,
|
|
138
154
|
runHvigorw: () => runHvigorw,
|
|
139
155
|
runOhpm: () => runOhpm,
|
|
@@ -146,11 +162,13 @@ __export(index_exports, {
|
|
|
146
162
|
sendRawTouch: () => sendRawTouch,
|
|
147
163
|
setHilogLevel: () => setHilogLevel,
|
|
148
164
|
shell: () => shell,
|
|
165
|
+
shellChecked: () => shellChecked,
|
|
149
166
|
startEmulator: () => startEmulator,
|
|
150
167
|
staticConfig: () => staticConfig,
|
|
151
168
|
stopEmulator: () => stopEmulator,
|
|
152
169
|
streamHilog: () => streamHilog,
|
|
153
170
|
takeScreenshot: () => takeScreenshot,
|
|
171
|
+
toSpaceError: () => toSpaceError,
|
|
154
172
|
uninstallApp: () => uninstallApp,
|
|
155
173
|
validateTemplateLayout: () => validateTemplateLayout,
|
|
156
174
|
verifySha256: () => verifySha256,
|
|
@@ -159,6 +177,7 @@ __export(index_exports, {
|
|
|
159
177
|
waitForCondition: () => waitForCondition,
|
|
160
178
|
waitForLog: () => waitForLog,
|
|
161
179
|
watchLog: () => watchLog,
|
|
180
|
+
waypointsToRawEvents: () => waypointsToRawEvents,
|
|
162
181
|
writeJson5File: () => writeJson5File,
|
|
163
182
|
writeJsonFile: () => writeJsonFile
|
|
164
183
|
});
|
|
@@ -271,9 +290,9 @@ var CmdToolsNotInstalledError = class extends OniroError {
|
|
|
271
290
|
expectedPath;
|
|
272
291
|
};
|
|
273
292
|
var UnsupportedPlatformError = class extends OniroError {
|
|
274
|
-
constructor(
|
|
275
|
-
super(`Unsupported platform: ${
|
|
276
|
-
this.platform =
|
|
293
|
+
constructor(platform7) {
|
|
294
|
+
super(`Unsupported platform: ${platform7}.`);
|
|
295
|
+
this.platform = platform7;
|
|
277
296
|
this.name = "UnsupportedPlatformError";
|
|
278
297
|
}
|
|
279
298
|
platform;
|
|
@@ -288,6 +307,14 @@ var ChecksumMismatchError = class extends OniroError {
|
|
|
288
307
|
expected;
|
|
289
308
|
actual;
|
|
290
309
|
};
|
|
310
|
+
var InsufficientSpaceError = class extends OniroError {
|
|
311
|
+
constructor(message, dir, cause) {
|
|
312
|
+
super(message, cause);
|
|
313
|
+
this.dir = dir;
|
|
314
|
+
this.name = "InsufficientSpaceError";
|
|
315
|
+
}
|
|
316
|
+
dir;
|
|
317
|
+
};
|
|
291
318
|
var CancelledError = class extends OniroError {
|
|
292
319
|
constructor(message = "Operation cancelled.") {
|
|
293
320
|
super(message);
|
|
@@ -334,29 +361,29 @@ var OHOS_URL_BASE = "https://repo.huaweicloud.com/openharmony/os";
|
|
|
334
361
|
// src/sdk/platform.ts
|
|
335
362
|
var os2 = __toESM(require("os"), 1);
|
|
336
363
|
function getOsFolder() {
|
|
337
|
-
const
|
|
338
|
-
if (
|
|
339
|
-
if (
|
|
340
|
-
if (
|
|
341
|
-
throw new UnsupportedPlatformError(
|
|
364
|
+
const platform7 = os2.platform();
|
|
365
|
+
if (platform7 === "linux") return "linux";
|
|
366
|
+
if (platform7 === "darwin") return "darwin";
|
|
367
|
+
if (platform7 === "win32") return "windows";
|
|
368
|
+
throw new UnsupportedPlatformError(platform7);
|
|
342
369
|
}
|
|
343
370
|
function getSdkFilename(version) {
|
|
344
|
-
const
|
|
371
|
+
const platform7 = os2.platform();
|
|
345
372
|
const v = version ?? ALL_SDKS[ALL_SDKS.length - 1].version;
|
|
346
373
|
const strips = ALL_SDKS.find((r) => r.version === v)?.tarballStrip ?? { linuxWindows: 1, darwin: 3 };
|
|
347
|
-
if (
|
|
374
|
+
if (platform7 === "linux") {
|
|
348
375
|
return { filename: "ohos-sdk-windows_linux-public.tar.gz", osFolder: "linux", strip: strips.linuxWindows };
|
|
349
376
|
}
|
|
350
|
-
if (
|
|
377
|
+
if (platform7 === "darwin") {
|
|
351
378
|
if (os2.arch() === "arm64") {
|
|
352
379
|
return { filename: "L2-SDK-MAC-M1-PUBLIC.tar.gz", osFolder: "darwin", strip: strips.darwin };
|
|
353
380
|
}
|
|
354
381
|
return { filename: "ohos-sdk-mac-public.tar.gz", osFolder: "darwin", strip: strips.darwin };
|
|
355
382
|
}
|
|
356
|
-
if (
|
|
383
|
+
if (platform7 === "win32") {
|
|
357
384
|
return { filename: "ohos-sdk-windows_linux-public.tar.gz", osFolder: "windows", strip: strips.linuxWindows };
|
|
358
385
|
}
|
|
359
|
-
throw new UnsupportedPlatformError(
|
|
386
|
+
throw new UnsupportedPlatformError(platform7);
|
|
360
387
|
}
|
|
361
388
|
|
|
362
389
|
// src/sdk/paths.ts
|
|
@@ -397,6 +424,8 @@ function getOhpmPath(config) {
|
|
|
397
424
|
return getCmdToolsBin(config, "ohpm");
|
|
398
425
|
}
|
|
399
426
|
function getHdcPath(config) {
|
|
427
|
+
const override = config.get("hdcPath", "");
|
|
428
|
+
if (override) return override;
|
|
400
429
|
const base = path2.join(getCmdToolsPath(config), "sdk", "default", "openharmony", "toolchains");
|
|
401
430
|
if (os3.platform() === "win32") {
|
|
402
431
|
return pickExisting([
|
|
@@ -447,8 +476,164 @@ function detectProjectSdkVersion(projectRoot, logger = noopLogger) {
|
|
|
447
476
|
}
|
|
448
477
|
}
|
|
449
478
|
|
|
450
|
-
// src/sdk/
|
|
479
|
+
// src/sdk/tmp.ts
|
|
451
480
|
var fs3 = __toESM(require("fs"), 1);
|
|
481
|
+
var os4 = __toESM(require("os"), 1);
|
|
482
|
+
var path4 = __toESM(require("path"), 1);
|
|
483
|
+
var INSTALL_TMP_DIRNAME = ".oniro-tmp";
|
|
484
|
+
var TMPFS_MAGIC = 16914836;
|
|
485
|
+
var RAMFS_MAGIC = 2240043254;
|
|
486
|
+
var HINT_EXAMPLE = os4.platform() === "win32" ? "D:\\oniro-tmp" : "~/.cache/oniro-tmp";
|
|
487
|
+
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}.`;
|
|
488
|
+
function resolveTmpRoot(config, override, installRoot) {
|
|
489
|
+
const explicit = (override ?? "").trim();
|
|
490
|
+
if (explicit) return path4.resolve(explicit);
|
|
491
|
+
const configured = config.get("tmpDir", "").trim();
|
|
492
|
+
if (configured) return path4.resolve(configured);
|
|
493
|
+
if (installRoot) return path4.join(path4.resolve(installRoot), INSTALL_TMP_DIRNAME);
|
|
494
|
+
return os4.tmpdir();
|
|
495
|
+
}
|
|
496
|
+
function createTempWorkDir(root, prefix) {
|
|
497
|
+
try {
|
|
498
|
+
fs3.mkdirSync(root, { recursive: true });
|
|
499
|
+
return fs3.mkdtempSync(path4.join(root, prefix));
|
|
500
|
+
} catch (err) {
|
|
501
|
+
if (isOutOfSpaceError(err)) throw toSpaceError(err, root, "a temporary directory");
|
|
502
|
+
throw new OniroError(
|
|
503
|
+
`Cannot create a temporary directory in '${root}': ${err instanceof Error ? err.message : String(err)}
|
|
504
|
+
${TMP_DIR_HINT}`,
|
|
505
|
+
err
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
function removeTempWorkDir(dir, root) {
|
|
510
|
+
fs3.rmSync(dir, { recursive: true, force: true });
|
|
511
|
+
if (!root || path4.basename(root) !== INSTALL_TMP_DIRNAME) return;
|
|
512
|
+
try {
|
|
513
|
+
fs3.rmdirSync(root);
|
|
514
|
+
} catch {
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
function createInstallTempDir(opts) {
|
|
518
|
+
const requested = (opts.override ?? "").trim() || opts.config.get("tmpDir", "").trim();
|
|
519
|
+
const root = resolveTmpRoot(opts.config, opts.override, opts.installRoot);
|
|
520
|
+
try {
|
|
521
|
+
return { dir: createTempWorkDir(root, opts.prefix), root };
|
|
522
|
+
} catch (err) {
|
|
523
|
+
const fallback = os4.tmpdir();
|
|
524
|
+
if (requested || isOutOfSpaceError(err) || path4.resolve(fallback) === path4.resolve(root)) throw err;
|
|
525
|
+
const reason = err instanceof Error ? err.message.split("\n")[0] : String(err);
|
|
526
|
+
(opts.logger ?? noopLogger).warn(`${reason} Falling back to '${fallback}'.`);
|
|
527
|
+
return { dir: createTempWorkDir(fallback, opts.prefix), root: fallback };
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
function nearestExisting(dir) {
|
|
531
|
+
let current = path4.resolve(dir);
|
|
532
|
+
for (; ; ) {
|
|
533
|
+
if (fs3.existsSync(current)) return current;
|
|
534
|
+
const parent = path4.dirname(current);
|
|
535
|
+
if (parent === current) return null;
|
|
536
|
+
current = parent;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
function getFreeSpaceBytes(dir) {
|
|
540
|
+
const target = nearestExisting(dir);
|
|
541
|
+
if (!target) return null;
|
|
542
|
+
try {
|
|
543
|
+
const stats = fs3.statfsSync(target);
|
|
544
|
+
return Number(stats.bsize) * Number(stats.bavail);
|
|
545
|
+
} catch {
|
|
546
|
+
return null;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
function isRamBackedPath(dir) {
|
|
550
|
+
const target = nearestExisting(dir);
|
|
551
|
+
if (!target) return false;
|
|
552
|
+
try {
|
|
553
|
+
const type = Number(fs3.statfsSync(target).type);
|
|
554
|
+
return type === TMPFS_MAGIC || type === RAMFS_MAGIC;
|
|
555
|
+
} catch {
|
|
556
|
+
return false;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
function formatBytes(bytes) {
|
|
560
|
+
const units = ["B", "KiB", "MiB", "GiB", "TiB"];
|
|
561
|
+
let value = Math.max(0, bytes);
|
|
562
|
+
let unit = 0;
|
|
563
|
+
while (value >= 1024 && unit < units.length - 1) {
|
|
564
|
+
value /= 1024;
|
|
565
|
+
unit++;
|
|
566
|
+
}
|
|
567
|
+
return `${value >= 10 || unit === 0 ? Math.round(value) : value.toFixed(1)} ${units[unit]}`;
|
|
568
|
+
}
|
|
569
|
+
function isOutOfSpaceError(err) {
|
|
570
|
+
if (err instanceof InsufficientSpaceError) return true;
|
|
571
|
+
const seen = /* @__PURE__ */ new Set();
|
|
572
|
+
let current = err;
|
|
573
|
+
while (current && typeof current === "object" && !seen.has(current)) {
|
|
574
|
+
seen.add(current);
|
|
575
|
+
const e = current;
|
|
576
|
+
if (e.code === "ENOSPC" || e.code === "EDQUOT") return true;
|
|
577
|
+
if (typeof e.message === "string" && /ENOSPC|EDQUOT|no space left on device/i.test(e.message)) return true;
|
|
578
|
+
current = e.cause;
|
|
579
|
+
}
|
|
580
|
+
return false;
|
|
581
|
+
}
|
|
582
|
+
function spaceMessage(dir, what, opts) {
|
|
583
|
+
const need = typeof opts.requiredBytes === "number" ? `needs about ${formatBytes(opts.requiredBytes)}` : null;
|
|
584
|
+
const free = typeof opts.freeBytes === "number" ? `${formatBytes(opts.freeBytes)} available` : null;
|
|
585
|
+
const amounts = [need, free].filter(Boolean).join(", ");
|
|
586
|
+
const lines = [`Not enough free space in '${dir}' for ${what}${amounts ? ` (${amounts})` : ""}.`];
|
|
587
|
+
if (isRamBackedPath(dir)) {
|
|
588
|
+
lines.push(
|
|
589
|
+
`'${dir}' is on a RAM-backed filesystem (tmpfs), so its capacity is limited by free memory, not by free disk.`
|
|
590
|
+
);
|
|
591
|
+
}
|
|
592
|
+
if (opts.tmpDirHint) lines.push(TMP_DIR_HINT);
|
|
593
|
+
return lines.join("\n");
|
|
594
|
+
}
|
|
595
|
+
function ensureFreeSpace(dir, requiredBytes, what) {
|
|
596
|
+
if (!Number.isFinite(requiredBytes) || requiredBytes <= 0) return;
|
|
597
|
+
const freeBytes = getFreeSpaceBytes(dir);
|
|
598
|
+
if (freeBytes === null || freeBytes >= requiredBytes) return;
|
|
599
|
+
throw new InsufficientSpaceError(
|
|
600
|
+
spaceMessage(dir, what, { requiredBytes, freeBytes, tmpDirHint: true }),
|
|
601
|
+
dir
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
function errorPath(err) {
|
|
605
|
+
const seen = /* @__PURE__ */ new Set();
|
|
606
|
+
let current = err;
|
|
607
|
+
while (current && typeof current === "object" && !seen.has(current)) {
|
|
608
|
+
seen.add(current);
|
|
609
|
+
const e = current;
|
|
610
|
+
if (typeof e.path === "string" && e.path) return e.path;
|
|
611
|
+
if (typeof e.dest === "string" && e.dest) return e.dest;
|
|
612
|
+
current = e.cause;
|
|
613
|
+
}
|
|
614
|
+
return null;
|
|
615
|
+
}
|
|
616
|
+
function isInside(child, parent) {
|
|
617
|
+
const rel = path4.relative(path4.resolve(parent), path4.resolve(child));
|
|
618
|
+
return rel === "" || !rel.startsWith("..") && !path4.isAbsolute(rel);
|
|
619
|
+
}
|
|
620
|
+
function toSpaceError(err, tmpRoot, what) {
|
|
621
|
+
if (err instanceof InsufficientSpaceError) return err;
|
|
622
|
+
if (!isOutOfSpaceError(err)) return err;
|
|
623
|
+
const failed = errorPath(err);
|
|
624
|
+
const failedDir = failed ? path4.dirname(path4.resolve(failed)) : path4.resolve(tmpRoot);
|
|
625
|
+
const inTmp = isInside(failedDir, tmpRoot);
|
|
626
|
+
const dir = inTmp ? path4.resolve(tmpRoot) : failedDir;
|
|
627
|
+
return new InsufficientSpaceError(
|
|
628
|
+
spaceMessage(dir, what, { freeBytes: getFreeSpaceBytes(dir), tmpDirHint: inTmp }),
|
|
629
|
+
dir,
|
|
630
|
+
err
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
// src/sdk/download.ts
|
|
635
|
+
var fs4 = __toESM(require("fs"), 1);
|
|
636
|
+
var path5 = __toESM(require("path"), 1);
|
|
452
637
|
var crypto = __toESM(require("crypto"), 1);
|
|
453
638
|
var import_node_stream = require("stream");
|
|
454
639
|
var import_node_util = require("util");
|
|
@@ -458,36 +643,57 @@ var pipelineAsync = (0, import_node_util.promisify)(import_node_stream.pipeline)
|
|
|
458
643
|
async function downloadFile(opts) {
|
|
459
644
|
const { url, dest, progress, abortSignal } = opts;
|
|
460
645
|
const proto = url.startsWith("https") ? https : http;
|
|
461
|
-
return new Promise((
|
|
646
|
+
return new Promise((resolve4, reject) => {
|
|
462
647
|
const s = Math.max(0, Math.min(100, opts.start ?? 0));
|
|
463
648
|
const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));
|
|
464
649
|
let settled = false;
|
|
465
650
|
const done = (err) => {
|
|
466
651
|
if (settled) return;
|
|
467
652
|
settled = true;
|
|
468
|
-
err ? reject(err) :
|
|
653
|
+
err ? reject(err) : resolve4();
|
|
469
654
|
};
|
|
470
655
|
if (abortSignal?.aborted) {
|
|
471
656
|
done(new CancelledError("Download cancelled before start."));
|
|
472
657
|
return;
|
|
473
658
|
}
|
|
474
|
-
const
|
|
659
|
+
const destDir = path5.dirname(path5.resolve(dest));
|
|
660
|
+
const what = opts.what ?? `the download of '${url}'`;
|
|
661
|
+
const writeFailed = (err) => isOutOfSpaceError(err) ? toSpaceError(err, opts.tmpRoot ?? destDir, what) : new OniroError(`Error writing '${dest}': ${err instanceof Error ? err.message : String(err)}`, err);
|
|
662
|
+
const file = fs4.createWriteStream(dest);
|
|
663
|
+
let activeResponse;
|
|
664
|
+
const failWith = (err) => {
|
|
665
|
+
file.close(() => fs4.rm(dest, { force: true }, () => done(err)));
|
|
666
|
+
};
|
|
667
|
+
file.on("error", (err) => {
|
|
668
|
+
try {
|
|
669
|
+
activeResponse?.destroy?.();
|
|
670
|
+
} catch {
|
|
671
|
+
}
|
|
672
|
+
failWith(writeFailed(err));
|
|
673
|
+
});
|
|
475
674
|
const req = proto.get(url, (response) => {
|
|
675
|
+
activeResponse = response;
|
|
476
676
|
if (response.statusCode !== 200) {
|
|
477
677
|
try {
|
|
478
678
|
response.destroy();
|
|
479
679
|
} catch {
|
|
480
680
|
}
|
|
481
|
-
|
|
482
|
-
file.close();
|
|
483
|
-
} catch {
|
|
484
|
-
}
|
|
485
|
-
fs3.unlink(dest, () => {
|
|
486
|
-
});
|
|
487
|
-
done(new OniroError(`Failed to download '${url}' (HTTP ${response.statusCode})`));
|
|
681
|
+
failWith(new OniroError(`Failed to download '${url}' (HTTP ${response.statusCode})`));
|
|
488
682
|
return;
|
|
489
683
|
}
|
|
490
684
|
const total = parseInt(response.headers["content-length"] || "0", 10);
|
|
685
|
+
if (total > 0) {
|
|
686
|
+
try {
|
|
687
|
+
ensureFreeSpace(opts.tmpRoot ?? destDir, total, what);
|
|
688
|
+
} catch (err) {
|
|
689
|
+
try {
|
|
690
|
+
response.destroy();
|
|
691
|
+
} catch {
|
|
692
|
+
}
|
|
693
|
+
failWith(err);
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
491
697
|
let downloaded = 0;
|
|
492
698
|
let lastOverall = Math.round(s);
|
|
493
699
|
response.on("data", (chunk) => {
|
|
@@ -511,38 +717,26 @@ async function downloadFile(opts) {
|
|
|
511
717
|
const inc = endOverall - lastOverall;
|
|
512
718
|
if (inc > 0) progress.report({ message: "Downloading: 100%", increment: inc });
|
|
513
719
|
}
|
|
514
|
-
file.close((err) => err ? done(err) : done());
|
|
720
|
+
file.close((err) => err ? done(writeFailed(err)) : done());
|
|
515
721
|
});
|
|
516
722
|
abortSignal?.addEventListener("abort", () => {
|
|
517
723
|
response.destroy();
|
|
518
|
-
|
|
519
|
-
fs3.unlink(dest, () => {
|
|
520
|
-
});
|
|
521
|
-
done(new CancelledError("Download cancelled."));
|
|
724
|
+
failWith(new CancelledError("Download cancelled."));
|
|
522
725
|
});
|
|
523
726
|
});
|
|
524
727
|
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));
|
|
728
|
+
failWith(new OniroError(`Error downloading '${url}': ${err.message}`, err));
|
|
532
729
|
});
|
|
533
730
|
abortSignal?.addEventListener("abort", () => {
|
|
534
731
|
req.destroy();
|
|
535
|
-
|
|
536
|
-
fs3.unlink(dest, () => {
|
|
537
|
-
});
|
|
538
|
-
done(new CancelledError("Download cancelled."));
|
|
732
|
+
failWith(new CancelledError("Download cancelled."));
|
|
539
733
|
});
|
|
540
734
|
});
|
|
541
735
|
}
|
|
542
736
|
async function verifySha256(filePath, sha256Path) {
|
|
543
|
-
const expected =
|
|
737
|
+
const expected = fs4.readFileSync(sha256Path, "utf8").split(/\s+/)[0];
|
|
544
738
|
const hash = crypto.createHash("sha256");
|
|
545
|
-
await pipelineAsync(
|
|
739
|
+
await pipelineAsync(fs4.createReadStream(filePath), hash);
|
|
546
740
|
const actual = hash.digest("hex");
|
|
547
741
|
if (actual !== expected) {
|
|
548
742
|
throw new ChecksumMismatchError(expected, actual);
|
|
@@ -550,9 +744,9 @@ async function verifySha256(filePath, sha256Path) {
|
|
|
550
744
|
}
|
|
551
745
|
|
|
552
746
|
// src/sdk/extract.ts
|
|
553
|
-
var
|
|
554
|
-
var
|
|
555
|
-
var
|
|
747
|
+
var fs5 = __toESM(require("fs"), 1);
|
|
748
|
+
var os5 = __toESM(require("os"), 1);
|
|
749
|
+
var path6 = __toESM(require("path"), 1);
|
|
556
750
|
var import_node_stream2 = require("stream");
|
|
557
751
|
var import_node_util2 = require("util");
|
|
558
752
|
var tar = __toESM(require("tar"), 1);
|
|
@@ -569,12 +763,12 @@ async function extractZipWithProgress(opts) {
|
|
|
569
763
|
const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));
|
|
570
764
|
let processed = 0;
|
|
571
765
|
let lastOverall = Math.round(s);
|
|
572
|
-
await
|
|
573
|
-
const destRoot =
|
|
766
|
+
await fs5.promises.mkdir(dest, { recursive: true });
|
|
767
|
+
const destRoot = path6.resolve(dest);
|
|
574
768
|
const safeResolveTarget = (entryName) => {
|
|
575
|
-
const resolved =
|
|
576
|
-
const rel =
|
|
577
|
-
if (rel.startsWith("..") ||
|
|
769
|
+
const resolved = path6.resolve(destRoot, entryName);
|
|
770
|
+
const rel = path6.relative(destRoot, resolved);
|
|
771
|
+
if (rel.startsWith("..") || path6.isAbsolute(rel)) {
|
|
578
772
|
throw new OniroError(`Blocked ZIP entry with illegal path: ${entryName}`);
|
|
579
773
|
}
|
|
580
774
|
return resolved;
|
|
@@ -586,25 +780,25 @@ async function extractZipWithProgress(opts) {
|
|
|
586
780
|
const attr = file.attr ? file.attr >>> 16 : 0;
|
|
587
781
|
const isSymlink = "isSymbolicLink" in file ? Boolean(file.isSymbolicLink) : (attr & 61440) === 40960;
|
|
588
782
|
if (file.isDirectory) {
|
|
589
|
-
await
|
|
783
|
+
await fs5.promises.mkdir(targetPath, { recursive: true });
|
|
590
784
|
} else if (isSymlink) {
|
|
591
|
-
await
|
|
785
|
+
await fs5.promises.mkdir(path6.dirname(targetPath), { recursive: true });
|
|
592
786
|
const linkTargetBuffer = await zip.entryData(file);
|
|
593
787
|
const linkTarget = linkTargetBuffer.toString("utf8");
|
|
594
788
|
try {
|
|
595
|
-
const isWin =
|
|
596
|
-
await
|
|
789
|
+
const isWin = os5.platform() === "win32";
|
|
790
|
+
await fs5.promises.symlink(linkTarget, targetPath, isWin ? "file" : void 0);
|
|
597
791
|
} catch (e) {
|
|
598
792
|
logger.warn(`Failed to create symlink at ${targetPath}: ${String(e)}`);
|
|
599
793
|
}
|
|
600
794
|
} else {
|
|
601
|
-
await
|
|
795
|
+
await fs5.promises.mkdir(path6.dirname(targetPath), { recursive: true });
|
|
602
796
|
const readStream = await zip.stream(file);
|
|
603
|
-
const writeStream =
|
|
797
|
+
const writeStream = fs5.createWriteStream(targetPath);
|
|
604
798
|
await pipelineAsync2(readStream, writeStream);
|
|
605
799
|
if (attr > 0) {
|
|
606
800
|
try {
|
|
607
|
-
await
|
|
801
|
+
await fs5.promises.chmod(targetPath, attr & 511);
|
|
608
802
|
} catch {
|
|
609
803
|
}
|
|
610
804
|
}
|
|
@@ -636,41 +830,41 @@ async function extractTarball(tarPath, dest, strip = 0) {
|
|
|
636
830
|
}
|
|
637
831
|
|
|
638
832
|
// src/sdk/list.ts
|
|
639
|
-
var
|
|
640
|
-
var
|
|
833
|
+
var fs6 = __toESM(require("fs"), 1);
|
|
834
|
+
var path7 = __toESM(require("path"), 1);
|
|
641
835
|
function getSupportedSdksForUi(config) {
|
|
642
|
-
const base =
|
|
836
|
+
const base = path7.join(getSdkRootDir(config), getOsFolder());
|
|
643
837
|
return ALL_SDKS.map((sdk) => ({
|
|
644
838
|
version: sdk.version,
|
|
645
839
|
api: sdk.api,
|
|
646
|
-
installed:
|
|
840
|
+
installed: fs6.existsSync(path7.join(base, sdk.api))
|
|
647
841
|
})).sort((a, b) => Number(b.api) - Number(a.api));
|
|
648
842
|
}
|
|
649
843
|
function getInstalledSdks(config) {
|
|
650
844
|
const sdkRoot = getSdkRootDir(config);
|
|
651
845
|
const versions = /* @__PURE__ */ new Set();
|
|
652
|
-
if (!
|
|
846
|
+
if (!fs6.existsSync(sdkRoot)) return [];
|
|
653
847
|
for (const osFolder of ["linux", "darwin", "windows"]) {
|
|
654
|
-
const osPath =
|
|
655
|
-
if (!
|
|
656
|
-
for (const api of
|
|
657
|
-
const apiPath =
|
|
658
|
-
if (
|
|
848
|
+
const osPath = path7.join(sdkRoot, osFolder);
|
|
849
|
+
if (!fs6.existsSync(osPath) || !fs6.statSync(osPath).isDirectory()) continue;
|
|
850
|
+
for (const api of fs6.readdirSync(osPath)) {
|
|
851
|
+
const apiPath = path7.join(osPath, api);
|
|
852
|
+
if (fs6.statSync(apiPath).isDirectory()) versions.add(api);
|
|
659
853
|
}
|
|
660
854
|
}
|
|
661
855
|
return ALL_SDKS.filter((sdk) => versions.has(sdk.api)).map((sdk) => sdk.version);
|
|
662
856
|
}
|
|
663
857
|
|
|
664
858
|
// src/sdk/remove.ts
|
|
665
|
-
var
|
|
666
|
-
var
|
|
859
|
+
var fs7 = __toESM(require("fs"), 1);
|
|
860
|
+
var path8 = __toESM(require("path"), 1);
|
|
667
861
|
function removeSdk(config, api) {
|
|
668
862
|
const sdkRoot = getSdkRootDir(config);
|
|
669
863
|
let removed = false;
|
|
670
864
|
for (const osFolder of ["linux", "darwin", "windows"]) {
|
|
671
|
-
const sdkPath =
|
|
672
|
-
if (
|
|
673
|
-
|
|
865
|
+
const sdkPath = path8.join(sdkRoot, osFolder, api);
|
|
866
|
+
if (fs7.existsSync(sdkPath)) {
|
|
867
|
+
fs7.rmSync(sdkPath, { recursive: true, force: true });
|
|
674
868
|
removed = true;
|
|
675
869
|
}
|
|
676
870
|
}
|
|
@@ -678,19 +872,18 @@ function removeSdk(config, api) {
|
|
|
678
872
|
}
|
|
679
873
|
|
|
680
874
|
// src/sdk/install.ts
|
|
681
|
-
var
|
|
682
|
-
var
|
|
683
|
-
var path7 = __toESM(require("path"), 1);
|
|
875
|
+
var fs9 = __toESM(require("fs"), 1);
|
|
876
|
+
var path9 = __toESM(require("path"), 1);
|
|
684
877
|
|
|
685
878
|
// src/sdk/move.ts
|
|
686
|
-
var
|
|
879
|
+
var fs8 = __toESM(require("fs"), 1);
|
|
687
880
|
function movePath(src, dest) {
|
|
688
881
|
try {
|
|
689
|
-
|
|
882
|
+
fs8.renameSync(src, dest);
|
|
690
883
|
} catch (err) {
|
|
691
884
|
if (err.code !== "EXDEV") throw err;
|
|
692
|
-
|
|
693
|
-
|
|
885
|
+
fs8.cpSync(src, dest, { recursive: true });
|
|
886
|
+
fs8.rmSync(src, { recursive: true, force: true });
|
|
694
887
|
}
|
|
695
888
|
}
|
|
696
889
|
|
|
@@ -702,21 +895,29 @@ async function downloadAndInstallSdk(opts) {
|
|
|
702
895
|
const urlBase = config.get("sdkUrlBase", OHOS_URL_BASE);
|
|
703
896
|
const downloadUrl = `${urlBase}/${version}-Release/${filename}`;
|
|
704
897
|
const sha256Url = `${downloadUrl}.sha256`;
|
|
705
|
-
const
|
|
706
|
-
const
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
898
|
+
const what = `the SDK ${version} install`;
|
|
899
|
+
const sdkRoot = getSdkRootDir(config);
|
|
900
|
+
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
901
|
+
config,
|
|
902
|
+
override: opts.tmpDir,
|
|
903
|
+
installRoot: sdkRoot,
|
|
904
|
+
prefix: "oniro-sdk-",
|
|
905
|
+
logger
|
|
906
|
+
});
|
|
907
|
+
const tarPath = path9.join(tmpDir, filename);
|
|
908
|
+
const sha256Path = path9.join(tmpDir, `${filename}.sha256`);
|
|
909
|
+
const extractDir = path9.join(tmpDir, "extract");
|
|
910
|
+
fs9.mkdirSync(extractDir);
|
|
911
|
+
const sdkInstallDir = path9.join(sdkRoot, osFolder, api);
|
|
912
|
+
fs9.mkdirSync(path9.dirname(sdkInstallDir), { recursive: true });
|
|
712
913
|
const checkCancelled = () => {
|
|
713
914
|
if (abortSignal?.aborted) throw new CancelledError();
|
|
714
915
|
};
|
|
715
916
|
try {
|
|
716
917
|
progress?.report({ message: "Downloading SDK archive...", increment: 0 });
|
|
717
|
-
await downloadFile({ url: downloadUrl, dest: tarPath, progress, abortSignal, start: 0, range: 35 });
|
|
918
|
+
await downloadFile({ url: downloadUrl, dest: tarPath, progress, abortSignal, start: 0, range: 35, what, tmpRoot });
|
|
718
919
|
progress?.report({ message: "Downloading checksum...", increment: 0 });
|
|
719
|
-
await downloadFile({ url: sha256Url, dest: sha256Path, progress, abortSignal, start: 35, range: 10 });
|
|
920
|
+
await downloadFile({ url: sha256Url, dest: sha256Path, progress, abortSignal, start: 35, range: 10, what, tmpRoot });
|
|
720
921
|
progress?.report({ message: "Verifying checksum...", increment: 0 });
|
|
721
922
|
await verifySha256(tarPath, sha256Path);
|
|
722
923
|
progress?.report({ message: "Verifying checksum...", increment: 5 });
|
|
@@ -725,13 +926,13 @@ async function downloadAndInstallSdk(opts) {
|
|
|
725
926
|
await extractTarball(tarPath, extractDir, strip);
|
|
726
927
|
progress?.report({ message: "Extracting SDK (this may take a while)...", increment: 10 });
|
|
727
928
|
checkCancelled();
|
|
728
|
-
const osContentPath =
|
|
729
|
-
if (!
|
|
929
|
+
const osContentPath = path9.join(extractDir, osFolder);
|
|
930
|
+
if (!fs9.existsSync(osContentPath)) {
|
|
730
931
|
throw new OniroError(
|
|
731
932
|
`Expected folder '${osFolder}' not found in extracted SDK. Tarball layout may have changed.`
|
|
732
933
|
);
|
|
733
934
|
}
|
|
734
|
-
const zipFiles =
|
|
935
|
+
const zipFiles = fs9.readdirSync(osContentPath).filter((n2) => n2.endsWith(".zip"));
|
|
735
936
|
const componentsStart = 60;
|
|
736
937
|
const componentsBudget = 35;
|
|
737
938
|
const n = zipFiles.length;
|
|
@@ -746,39 +947,40 @@ async function downloadAndInstallSdk(opts) {
|
|
|
746
947
|
for (const zipFile of zipFiles) {
|
|
747
948
|
checkCancelled();
|
|
748
949
|
logger.info(`Extracting component ${zipFile}`);
|
|
749
|
-
const zipPath =
|
|
950
|
+
const zipPath = path9.join(osContentPath, zipFile);
|
|
750
951
|
const thisBudget = base + (rem > 0 ? 1 : 0);
|
|
751
952
|
if (rem > 0) rem--;
|
|
752
953
|
await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });
|
|
753
954
|
cursor += thisBudget;
|
|
754
|
-
|
|
955
|
+
fs9.unlinkSync(zipPath);
|
|
755
956
|
}
|
|
756
957
|
progress?.report({ message: "Finalizing installation...", increment: 0 });
|
|
757
|
-
if (
|
|
758
|
-
|
|
958
|
+
if (fs9.existsSync(sdkInstallDir)) {
|
|
959
|
+
fs9.rmSync(sdkInstallDir, { recursive: true, force: true });
|
|
759
960
|
}
|
|
760
961
|
movePath(osContentPath, sdkInstallDir);
|
|
761
962
|
progress?.report({ message: "Finalizing installation...", increment: 3 });
|
|
762
963
|
progress?.report({ message: "Cleaning up...", increment: 0 });
|
|
763
|
-
|
|
964
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
764
965
|
progress?.report({ message: "Cleaning up...", increment: 2 });
|
|
765
966
|
} catch (err) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
967
|
+
const wrapped = toSpaceError(err, tmpRoot, what);
|
|
968
|
+
logger.error(`SDK install failed: ${wrapped instanceof Error ? wrapped.message : String(wrapped)}`);
|
|
969
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
970
|
+
throw wrapped;
|
|
769
971
|
}
|
|
770
972
|
}
|
|
771
973
|
|
|
772
974
|
// src/cmdTools/install.ts
|
|
773
|
-
var
|
|
975
|
+
var fs10 = __toESM(require("fs"), 1);
|
|
774
976
|
var os6 = __toESM(require("os"), 1);
|
|
775
|
-
var
|
|
977
|
+
var path10 = __toESM(require("path"), 1);
|
|
776
978
|
var import_node_child_process = require("child_process");
|
|
777
|
-
function getCmdToolsDownloadUrl(config,
|
|
778
|
-
if (
|
|
979
|
+
function getCmdToolsDownloadUrl(config, platform7 = os6.platform()) {
|
|
980
|
+
if (platform7 === "linux") {
|
|
779
981
|
return config.get("cmdToolsUrlLinux", defaultPaths.cmdToolsUrlLinux);
|
|
780
982
|
}
|
|
781
|
-
if (
|
|
983
|
+
if (platform7 === "win32") {
|
|
782
984
|
const url = config.get("cmdToolsUrlWindows", "");
|
|
783
985
|
if (!url) {
|
|
784
986
|
throw new OniroError(
|
|
@@ -787,7 +989,7 @@ function getCmdToolsDownloadUrl(config, platform6 = os6.platform()) {
|
|
|
787
989
|
}
|
|
788
990
|
return url;
|
|
789
991
|
}
|
|
790
|
-
if (
|
|
992
|
+
if (platform7 === "darwin") {
|
|
791
993
|
const url = config.get("cmdToolsUrlMac", "");
|
|
792
994
|
if (!url) {
|
|
793
995
|
throw new OniroError(
|
|
@@ -796,20 +998,20 @@ function getCmdToolsDownloadUrl(config, platform6 = os6.platform()) {
|
|
|
796
998
|
}
|
|
797
999
|
return url;
|
|
798
1000
|
}
|
|
799
|
-
throw new UnsupportedPlatformError(
|
|
1001
|
+
throw new UnsupportedPlatformError(platform7);
|
|
800
1002
|
}
|
|
801
1003
|
function findCmdToolsSourceDir(extractPath) {
|
|
802
1004
|
const known = [
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
1005
|
+
path10.join(extractPath, "command-line-tools"),
|
|
1006
|
+
path10.join(extractPath, "oh-command-line-tools"),
|
|
1007
|
+
path10.join(extractPath, "commandline-tools")
|
|
806
1008
|
];
|
|
807
1009
|
for (const c of known) {
|
|
808
|
-
if (
|
|
1010
|
+
if (fs10.existsSync(c)) return c;
|
|
809
1011
|
}
|
|
810
|
-
const entries =
|
|
1012
|
+
const entries = fs10.readdirSync(extractPath, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path10.join(extractPath, e.name));
|
|
811
1013
|
for (const dir of entries) {
|
|
812
|
-
if (
|
|
1014
|
+
if (fs10.existsSync(path10.join(dir, "bin"))) return dir;
|
|
813
1015
|
}
|
|
814
1016
|
throw new OniroError("Could not locate command line tools folder in the extracted archive.");
|
|
815
1017
|
}
|
|
@@ -817,53 +1019,62 @@ async function installCmdTools(opts) {
|
|
|
817
1019
|
const { config, progress, abortSignal } = opts;
|
|
818
1020
|
const logger = opts.logger ?? noopLogger;
|
|
819
1021
|
const CMD_PATH = getCmdToolsPath(config);
|
|
820
|
-
const
|
|
821
|
-
const
|
|
822
|
-
|
|
1022
|
+
const what = "the command-line tools install";
|
|
1023
|
+
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
1024
|
+
config,
|
|
1025
|
+
override: opts.tmpDir,
|
|
1026
|
+
installRoot: path10.dirname(CMD_PATH),
|
|
1027
|
+
prefix: "oniro-cmdtools-",
|
|
1028
|
+
logger
|
|
1029
|
+
});
|
|
1030
|
+
const zipPath = opts.localZipPath ?? path10.join(tmpDir, "oh-command-line-tools.zip");
|
|
1031
|
+
const extractPath = path10.join(tmpDir, "oh-command-line-tools");
|
|
823
1032
|
try {
|
|
824
1033
|
if (!opts.localZipPath) {
|
|
825
1034
|
const url = getCmdToolsDownloadUrl(config);
|
|
826
1035
|
progress?.report({ message: "Downloading command line tools...", increment: 0 });
|
|
827
|
-
await downloadFile({ url, dest: zipPath, progress, abortSignal, start: 0, range: 50 });
|
|
1036
|
+
await downloadFile({ url, dest: zipPath, progress, abortSignal, start: 0, range: 50, what, tmpRoot });
|
|
828
1037
|
}
|
|
829
1038
|
progress?.report({ message: "Extracting tools...", increment: 0 });
|
|
830
1039
|
await extractZipWithProgress({ zipPath, dest: extractPath, progress, start: 50, range: 45, logger });
|
|
831
|
-
|
|
1040
|
+
fs10.mkdirSync(CMD_PATH, { recursive: true });
|
|
832
1041
|
const srcDir = findCmdToolsSourceDir(extractPath);
|
|
833
|
-
for (const entry of
|
|
834
|
-
const src =
|
|
835
|
-
const dest =
|
|
836
|
-
if (
|
|
837
|
-
if (
|
|
1042
|
+
for (const entry of fs10.readdirSync(srcDir)) {
|
|
1043
|
+
const src = path10.join(srcDir, entry);
|
|
1044
|
+
const dest = path10.join(CMD_PATH, entry);
|
|
1045
|
+
if (fs10.statSync(src).isDirectory()) {
|
|
1046
|
+
if (fs10.existsSync(dest)) fs10.rmSync(dest, { recursive: true, force: true });
|
|
838
1047
|
movePath(src, dest);
|
|
839
1048
|
} else {
|
|
840
|
-
|
|
1049
|
+
fs10.copyFileSync(src, dest);
|
|
841
1050
|
}
|
|
842
1051
|
}
|
|
843
|
-
const binDir =
|
|
844
|
-
if (
|
|
845
|
-
for (const file of
|
|
846
|
-
|
|
1052
|
+
const binDir = path10.join(CMD_PATH, "bin");
|
|
1053
|
+
if (fs10.existsSync(binDir) && os6.platform() !== "win32") {
|
|
1054
|
+
for (const file of fs10.readdirSync(binDir)) {
|
|
1055
|
+
fs10.chmodSync(path10.join(binDir, file), 493);
|
|
847
1056
|
}
|
|
848
1057
|
}
|
|
849
1058
|
progress?.report({ message: "Finalizing installation...", increment: 5 });
|
|
850
1059
|
progress?.report({ message: "Cleaning up...", increment: 0 });
|
|
1060
|
+
} catch (err) {
|
|
1061
|
+
throw toSpaceError(err, tmpRoot, what);
|
|
851
1062
|
} finally {
|
|
852
|
-
|
|
1063
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
853
1064
|
}
|
|
854
1065
|
}
|
|
855
1066
|
function getCmdToolsStatus(config) {
|
|
856
1067
|
const cmdPath = getCmdToolsPath(config);
|
|
857
|
-
const binDir =
|
|
1068
|
+
const binDir = path10.join(cmdPath, "bin");
|
|
858
1069
|
const candidates = os6.platform() === "win32" ? ["ohpm.exe", "ohpm.cmd", "ohpm.bat", "ohpm"] : ["ohpm"];
|
|
859
|
-
const bin = candidates.map((c) =>
|
|
1070
|
+
const bin = candidates.map((c) => path10.join(binDir, c)).find((p) => fs10.existsSync(p));
|
|
860
1071
|
if (!bin) {
|
|
861
1072
|
return { installed: false, status: "Not installed" };
|
|
862
1073
|
}
|
|
863
1074
|
try {
|
|
864
|
-
const versionFile =
|
|
865
|
-
if (
|
|
866
|
-
const content =
|
|
1075
|
+
const versionFile = path10.join(cmdPath, "version.txt");
|
|
1076
|
+
if (fs10.existsSync(versionFile)) {
|
|
1077
|
+
const content = fs10.readFileSync(versionFile, "utf8");
|
|
867
1078
|
for (const line of content.split(/\r?\n/)) {
|
|
868
1079
|
const m = line.match(/^\s*#\s*Version:\s*(.+)$/);
|
|
869
1080
|
if (m?.[1]) return { installed: true, status: `Installed (${m[1].trim()})` };
|
|
@@ -883,14 +1094,14 @@ function isCmdToolsInstalled(config) {
|
|
|
883
1094
|
}
|
|
884
1095
|
function removeCmdTools(config) {
|
|
885
1096
|
const cmdPath = getCmdToolsPath(config);
|
|
886
|
-
if (
|
|
887
|
-
|
|
1097
|
+
if (fs10.existsSync(cmdPath)) {
|
|
1098
|
+
fs10.rmSync(cmdPath, { recursive: true, force: true });
|
|
888
1099
|
}
|
|
889
1100
|
}
|
|
890
1101
|
|
|
891
1102
|
// src/sign/encryptKey.ts
|
|
892
|
-
var
|
|
893
|
-
var
|
|
1103
|
+
var fs11 = __toESM(require("fs"), 1);
|
|
1104
|
+
var path11 = __toESM(require("path"), 1);
|
|
894
1105
|
var crypto2 = __toESM(require("crypto"), 1);
|
|
895
1106
|
var DAEMON_ROOT_KEY_COMPONENT_LENGTH = 16;
|
|
896
1107
|
var DAEMON_SALT_KEY_LENGTH = 16;
|
|
@@ -962,33 +1173,33 @@ function getRootKey(fdComponents, salt) {
|
|
|
962
1173
|
function createAndStoreKey(dir, keyLength) {
|
|
963
1174
|
const key = crypto2.randomBytes(keyLength);
|
|
964
1175
|
const hash = crypto2.createHash("sha256").update(key).digest("hex");
|
|
965
|
-
const filePath =
|
|
966
|
-
|
|
967
|
-
|
|
1176
|
+
const filePath = path11.join(dir, hash);
|
|
1177
|
+
fs11.writeFileSync(filePath, key);
|
|
1178
|
+
fs11.chmodSync(filePath, KEY_FILE_PERMISSIONS);
|
|
968
1179
|
return key;
|
|
969
1180
|
}
|
|
970
1181
|
function createAndStoreEnKey(rootKey, ceDir) {
|
|
971
1182
|
const workKey = crypto2.randomBytes(DAEMON_WORK_KEY_LENGTH);
|
|
972
1183
|
const encrypted = encrypt(rootKey, workKey);
|
|
973
1184
|
const hash = crypto2.createHash("sha256").update(encrypted).digest("hex");
|
|
974
|
-
const filePath =
|
|
975
|
-
|
|
976
|
-
|
|
1185
|
+
const filePath = path11.join(ceDir, hash);
|
|
1186
|
+
fs11.writeFileSync(filePath, encrypted);
|
|
1187
|
+
fs11.chmodSync(filePath, KEY_FILE_PERMISSIONS);
|
|
977
1188
|
}
|
|
978
1189
|
function createMaterial(materialPath) {
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
const fdDir =
|
|
982
|
-
const acDir =
|
|
983
|
-
const ceDir =
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1190
|
+
fs11.mkdirSync(materialPath, { recursive: true });
|
|
1191
|
+
fs11.chmodSync(materialPath, KEY_FILE_DIRECTORY_PERMISSIONS);
|
|
1192
|
+
const fdDir = path11.join(materialPath, "fd");
|
|
1193
|
+
const acDir = path11.join(materialPath, "ac");
|
|
1194
|
+
const ceDir = path11.join(materialPath, "ce");
|
|
1195
|
+
fs11.mkdirSync(fdDir, { recursive: true });
|
|
1196
|
+
fs11.mkdirSync(acDir, { recursive: true });
|
|
1197
|
+
fs11.mkdirSync(ceDir, { recursive: true });
|
|
987
1198
|
const fdSubDirs = ["0", "1", "2"];
|
|
988
1199
|
const fdComponents = [];
|
|
989
1200
|
for (const sub of fdSubDirs) {
|
|
990
|
-
const subDir =
|
|
991
|
-
|
|
1201
|
+
const subDir = path11.join(fdDir, sub);
|
|
1202
|
+
fs11.mkdirSync(subDir, { recursive: true });
|
|
992
1203
|
const comp = createAndStoreKey(subDir, DAEMON_ROOT_KEY_COMPONENT_LENGTH);
|
|
993
1204
|
fdComponents.push(comp);
|
|
994
1205
|
}
|
|
@@ -997,24 +1208,24 @@ function createMaterial(materialPath) {
|
|
|
997
1208
|
createAndStoreEnKey(rootKey, ceDir);
|
|
998
1209
|
}
|
|
999
1210
|
function readSingleFile(dir) {
|
|
1000
|
-
if (!
|
|
1211
|
+
if (!fs11.existsSync(dir) || !fs11.statSync(dir).isDirectory()) {
|
|
1001
1212
|
throw new Error(`Missing signing material directory: ${dir}`);
|
|
1002
1213
|
}
|
|
1003
|
-
const files =
|
|
1214
|
+
const files = fs11.readdirSync(dir).filter((f) => f !== ".DS_Store");
|
|
1004
1215
|
if (files.length !== 1) {
|
|
1005
1216
|
throw new Error(`Signing material in ${dir} is illegal (expected exactly one file).`);
|
|
1006
1217
|
}
|
|
1007
|
-
return
|
|
1218
|
+
return fs11.readFileSync(path11.join(dir, files[0]));
|
|
1008
1219
|
}
|
|
1009
1220
|
function getKey(materialPath) {
|
|
1010
|
-
if (!
|
|
1221
|
+
if (!fs11.existsSync(materialPath) || !fs11.statSync(materialPath).isDirectory()) {
|
|
1011
1222
|
throw new Error("Material directory does not exist.");
|
|
1012
1223
|
}
|
|
1013
|
-
const fdDir =
|
|
1014
|
-
const fdComponents = ["0", "1", "2"].map((sub) => readSingleFile(
|
|
1015
|
-
const salt = readSingleFile(
|
|
1224
|
+
const fdDir = path11.join(materialPath, "fd");
|
|
1225
|
+
const fdComponents = ["0", "1", "2"].map((sub) => readSingleFile(path11.join(fdDir, sub)));
|
|
1226
|
+
const salt = readSingleFile(path11.join(materialPath, "ac"));
|
|
1016
1227
|
const rootKey = getRootKey(fdComponents, salt);
|
|
1017
|
-
const workMaterial = readSingleFile(
|
|
1228
|
+
const workMaterial = readSingleFile(path11.join(materialPath, "ce"));
|
|
1018
1229
|
return decrypt(rootKey, workMaterial);
|
|
1019
1230
|
}
|
|
1020
1231
|
function encryptPwd(password, materialPath) {
|
|
@@ -1029,8 +1240,8 @@ function decryptPwd(encryptedHex, materialPath) {
|
|
|
1029
1240
|
}
|
|
1030
1241
|
|
|
1031
1242
|
// src/sign/generateSigningConfigs.ts
|
|
1032
|
-
var
|
|
1033
|
-
var
|
|
1243
|
+
var fs12 = __toESM(require("fs"), 1);
|
|
1244
|
+
var path12 = __toESM(require("path"), 1);
|
|
1034
1245
|
var import_node_child_process2 = require("child_process");
|
|
1035
1246
|
var import_json52 = __toESM(require("json5"), 1);
|
|
1036
1247
|
|
|
@@ -1100,17 +1311,17 @@ var SIGNING_KIND_CONFIG = {
|
|
|
1100
1311
|
};
|
|
1101
1312
|
function copyFilesToProject(projectDir, paths, kind, logger, applicationCertPath) {
|
|
1102
1313
|
logger.info("[sign] Copying signing material into project...");
|
|
1103
|
-
const signaturesDir =
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1314
|
+
const signaturesDir = path12.join(projectDir, "signatures");
|
|
1315
|
+
fs12.mkdirSync(signaturesDir, { recursive: true });
|
|
1316
|
+
fs12.copyFileSync(paths.keystore, path12.join(signaturesDir, "OpenHarmony.p12"));
|
|
1317
|
+
fs12.copyFileSync(paths.profileCert, path12.join(signaturesDir, "OpenHarmonyProfileRelease.pem"));
|
|
1318
|
+
fs12.copyFileSync(paths.unsignedProfileTemplate, path12.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json"));
|
|
1108
1319
|
if (kind === "application-release") {
|
|
1109
|
-
const dest =
|
|
1320
|
+
const dest = path12.join(signaturesDir, "OpenHarmonyApplication.cer");
|
|
1110
1321
|
if (applicationCertPath) {
|
|
1111
|
-
|
|
1322
|
+
fs12.copyFileSync(applicationCertPath, dest);
|
|
1112
1323
|
} else {
|
|
1113
|
-
|
|
1324
|
+
fs12.writeFileSync(dest, OPEN_HARMONY_APPLICATION_CERT);
|
|
1114
1325
|
}
|
|
1115
1326
|
}
|
|
1116
1327
|
}
|
|
@@ -1119,7 +1330,7 @@ function resolveAppFeature(apl, override) {
|
|
|
1119
1330
|
return apl === "normal" ? "hos_normal_app" : "hos_system_app";
|
|
1120
1331
|
}
|
|
1121
1332
|
function extractLeafCertificate(chainPath) {
|
|
1122
|
-
const certContent =
|
|
1333
|
+
const certContent = fs12.readFileSync(chainPath, "utf-8");
|
|
1123
1334
|
const parts = certContent.split("-----END CERTIFICATE-----");
|
|
1124
1335
|
if (parts.length < 3) {
|
|
1125
1336
|
throw new OniroError(`${chainPath} does not contain enough certificates.`);
|
|
@@ -1129,20 +1340,20 @@ function extractLeafCertificate(chainPath) {
|
|
|
1129
1340
|
function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}) {
|
|
1130
1341
|
const kind = options.kind ?? pickSigningKind(apl);
|
|
1131
1342
|
logger.info(`[sign] Modifying profile template (apl=${apl}, app-feature=${appFeature}, kind=${kind})...`);
|
|
1132
|
-
const appJsonPath =
|
|
1133
|
-
const profileTemplatePath =
|
|
1134
|
-
if (!
|
|
1343
|
+
const appJsonPath = path12.join(projectDir, "AppScope/app.json5");
|
|
1344
|
+
const profileTemplatePath = path12.join(projectDir, "signatures/UnsgnedReleasedProfileTemplate.json");
|
|
1345
|
+
if (!fs12.existsSync(appJsonPath)) {
|
|
1135
1346
|
throw new OniroError(`${appJsonPath} does not exist.`);
|
|
1136
1347
|
}
|
|
1137
1348
|
let appJson;
|
|
1138
1349
|
try {
|
|
1139
|
-
appJson = import_json52.default.parse(
|
|
1350
|
+
appJson = import_json52.default.parse(fs12.readFileSync(appJsonPath, "utf-8"));
|
|
1140
1351
|
} catch (e) {
|
|
1141
1352
|
throw new OniroError(`Error parsing ${appJsonPath}: ${e.message}`, e);
|
|
1142
1353
|
}
|
|
1143
1354
|
let profileTemplate;
|
|
1144
1355
|
try {
|
|
1145
|
-
profileTemplate = JSON.parse(
|
|
1356
|
+
profileTemplate = JSON.parse(fs12.readFileSync(profileTemplatePath, "utf-8"));
|
|
1146
1357
|
} catch (e) {
|
|
1147
1358
|
throw new OniroError(`Error parsing ${profileTemplatePath}: ${e.message}`, e);
|
|
1148
1359
|
}
|
|
@@ -1155,7 +1366,7 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
|
|
|
1155
1366
|
profileTemplate["bundle-info"]["bundle-name"] = appJson.app.bundleName;
|
|
1156
1367
|
profileTemplate["bundle-info"]["apl"] = apl;
|
|
1157
1368
|
profileTemplate["bundle-info"]["app-feature"] = appFeature;
|
|
1158
|
-
const distCertChainPath =
|
|
1369
|
+
const distCertChainPath = path12.join(
|
|
1159
1370
|
projectDir,
|
|
1160
1371
|
"signatures",
|
|
1161
1372
|
SIGNING_KIND_CONFIG[kind].certBasename
|
|
@@ -1165,13 +1376,13 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
|
|
|
1165
1376
|
profileTemplate.acls = profileTemplate.acls ?? {};
|
|
1166
1377
|
profileTemplate.acls["allowed-acls"] = options.acls;
|
|
1167
1378
|
}
|
|
1168
|
-
|
|
1379
|
+
fs12.writeFileSync(profileTemplatePath, JSON.stringify(profileTemplate, null, 2));
|
|
1169
1380
|
}
|
|
1170
1381
|
function generateP7bFile(projectDir, paths, logger, passwords) {
|
|
1171
1382
|
logger.info("[sign] Generating P7b profile via hap-sign-tool...");
|
|
1172
|
-
const signaturesDir =
|
|
1173
|
-
const profileTemplatePath =
|
|
1174
|
-
const outputProfilePath =
|
|
1383
|
+
const signaturesDir = path12.join(projectDir, "signatures");
|
|
1384
|
+
const profileTemplatePath = path12.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json");
|
|
1385
|
+
const outputProfilePath = path12.join(signaturesDir, "app1-profile.p7b");
|
|
1175
1386
|
const args = [
|
|
1176
1387
|
"-jar",
|
|
1177
1388
|
paths.signTool,
|
|
@@ -1205,11 +1416,11 @@ function generateP7bFile(projectDir, paths, logger, passwords) {
|
|
|
1205
1416
|
}
|
|
1206
1417
|
}
|
|
1207
1418
|
function detectSigningConfigNames(projectDir) {
|
|
1208
|
-
const buildProfilePath =
|
|
1209
|
-
if (!
|
|
1419
|
+
const buildProfilePath = path12.join(projectDir, "build-profile.json5");
|
|
1420
|
+
if (!fs12.existsSync(buildProfilePath)) return ["default"];
|
|
1210
1421
|
let parsed;
|
|
1211
1422
|
try {
|
|
1212
|
-
parsed = import_json52.default.parse(
|
|
1423
|
+
parsed = import_json52.default.parse(fs12.readFileSync(buildProfilePath, "utf-8"));
|
|
1213
1424
|
} catch {
|
|
1214
1425
|
return ["default"];
|
|
1215
1426
|
}
|
|
@@ -1226,14 +1437,14 @@ function detectSigningConfigNames(projectDir) {
|
|
|
1226
1437
|
}
|
|
1227
1438
|
function updateBuildProfile(projectDir, kind, logger, passwords) {
|
|
1228
1439
|
logger.info("[sign] Writing signing configs into build-profile.json5...");
|
|
1229
|
-
const materialDir =
|
|
1230
|
-
const buildProfilePath =
|
|
1440
|
+
const materialDir = path12.join(projectDir, "signatures", "material");
|
|
1441
|
+
const buildProfilePath = path12.join(projectDir, "build-profile.json5");
|
|
1231
1442
|
const encryptedStorePassword = encryptPwd(passwords.store, materialDir);
|
|
1232
1443
|
const encryptedKeyPassword = encryptPwd(passwords.key, materialDir);
|
|
1233
1444
|
let buildProfile = { app: {} };
|
|
1234
|
-
if (
|
|
1445
|
+
if (fs12.existsSync(buildProfilePath)) {
|
|
1235
1446
|
try {
|
|
1236
|
-
buildProfile = import_json52.default.parse(
|
|
1447
|
+
buildProfile = import_json52.default.parse(fs12.readFileSync(buildProfilePath, "utf-8"));
|
|
1237
1448
|
} catch (e) {
|
|
1238
1449
|
throw new OniroError(`Error parsing ${buildProfilePath}: ${e.message}`, e);
|
|
1239
1450
|
}
|
|
@@ -1254,13 +1465,13 @@ function updateBuildProfile(projectDir, kind, logger, passwords) {
|
|
|
1254
1465
|
storeFile: "./signatures/OpenHarmony.p12"
|
|
1255
1466
|
}
|
|
1256
1467
|
}));
|
|
1257
|
-
|
|
1468
|
+
fs12.writeFileSync(buildProfilePath, JSON.stringify(buildProfile, null, 2));
|
|
1258
1469
|
}
|
|
1259
1470
|
function prepareMaterialDirectory(projectDir, logger) {
|
|
1260
1471
|
logger.info("[sign] Generating fresh signing material...");
|
|
1261
|
-
const materialDir =
|
|
1262
|
-
if (
|
|
1263
|
-
|
|
1472
|
+
const materialDir = path12.join(projectDir, "signatures", "material");
|
|
1473
|
+
if (fs12.existsSync(materialDir)) {
|
|
1474
|
+
fs12.rmSync(materialDir, { recursive: true, force: true });
|
|
1264
1475
|
}
|
|
1265
1476
|
createMaterial(materialDir);
|
|
1266
1477
|
}
|
|
@@ -1283,15 +1494,15 @@ function generateSigningConfigs(options) {
|
|
|
1283
1494
|
"Could not detect project SDK version (compileSdkVersion missing in build-profile.json5)."
|
|
1284
1495
|
);
|
|
1285
1496
|
}
|
|
1286
|
-
const sdkPath =
|
|
1287
|
-
if (!
|
|
1497
|
+
const sdkPath = path12.join(sdkHome, String(sdkVersion));
|
|
1498
|
+
if (!fs12.existsSync(sdkPath)) {
|
|
1288
1499
|
throw new OniroError(`SDK path does not exist: ${sdkPath}`);
|
|
1289
1500
|
}
|
|
1290
1501
|
const paths = {
|
|
1291
|
-
signTool:
|
|
1292
|
-
keystore:
|
|
1293
|
-
profileCert:
|
|
1294
|
-
unsignedProfileTemplate:
|
|
1502
|
+
signTool: path12.join(sdkPath, "toolchains/lib/hap-sign-tool.jar"),
|
|
1503
|
+
keystore: path12.join(sdkPath, "toolchains/lib/OpenHarmony.p12"),
|
|
1504
|
+
profileCert: path12.join(sdkPath, "toolchains/lib/OpenHarmonyProfileRelease.pem"),
|
|
1505
|
+
unsignedProfileTemplate: path12.join(sdkPath, "toolchains/lib/UnsgnedReleasedProfileTemplate.json")
|
|
1295
1506
|
};
|
|
1296
1507
|
const kind = pickSigningKind(apl);
|
|
1297
1508
|
const passwords = options.passwords ?? DEFAULT_PASSWORDS;
|
|
@@ -1305,46 +1516,54 @@ function generateSigningConfigs(options) {
|
|
|
1305
1516
|
}
|
|
1306
1517
|
|
|
1307
1518
|
// src/emulator/install.ts
|
|
1308
|
-
var
|
|
1309
|
-
var
|
|
1310
|
-
var path11 = __toESM(require("path"), 1);
|
|
1519
|
+
var fs13 = __toESM(require("fs"), 1);
|
|
1520
|
+
var path13 = __toESM(require("path"), 1);
|
|
1311
1521
|
async function installEmulator(opts) {
|
|
1312
1522
|
const { config, progress, abortSignal } = opts;
|
|
1313
1523
|
const logger = opts.logger ?? noopLogger;
|
|
1314
1524
|
const url = config.get("emulatorUrl", defaultPaths.emulatorUrl);
|
|
1315
1525
|
const emulatorDir = getEmulatorDir(config);
|
|
1316
|
-
const
|
|
1317
|
-
const
|
|
1526
|
+
const what = "the emulator install";
|
|
1527
|
+
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
1528
|
+
config,
|
|
1529
|
+
override: opts.tmpDir,
|
|
1530
|
+
installRoot: path13.dirname(emulatorDir),
|
|
1531
|
+
prefix: "oniro-emulator-",
|
|
1532
|
+
logger
|
|
1533
|
+
});
|
|
1534
|
+
const tmpZip = path13.join(tmpDir, "oniro_emulator.zip");
|
|
1318
1535
|
try {
|
|
1319
|
-
|
|
1536
|
+
fs13.mkdirSync(emulatorDir, { recursive: true });
|
|
1320
1537
|
progress?.report({ message: "Downloading emulator...", increment: 0 });
|
|
1321
|
-
await downloadFile({ url, dest: tmpZip, progress, abortSignal, start: 0, range: 50 });
|
|
1538
|
+
await downloadFile({ url, dest: tmpZip, progress, abortSignal, start: 0, range: 50, what, tmpRoot });
|
|
1322
1539
|
progress?.report({ message: "Extracting emulator...", increment: 0 });
|
|
1323
1540
|
await extractZipWithProgress({ zipPath: tmpZip, dest: emulatorDir, progress, start: 50, range: 45, logger });
|
|
1324
|
-
const runSh =
|
|
1325
|
-
if (
|
|
1326
|
-
|
|
1541
|
+
const runSh = path13.join(emulatorDir, "images", "run.sh");
|
|
1542
|
+
if (fs13.existsSync(runSh)) {
|
|
1543
|
+
fs13.chmodSync(runSh, 493);
|
|
1327
1544
|
}
|
|
1328
1545
|
progress?.report({ message: "Finalizing installation...", increment: 5 });
|
|
1546
|
+
} catch (err) {
|
|
1547
|
+
throw toSpaceError(err, tmpRoot, what);
|
|
1329
1548
|
} finally {
|
|
1330
|
-
|
|
1549
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
1331
1550
|
}
|
|
1332
1551
|
}
|
|
1333
1552
|
function isEmulatorInstalled(config) {
|
|
1334
|
-
const imagesDir =
|
|
1335
|
-
return
|
|
1553
|
+
const imagesDir = path13.join(getEmulatorDir(config), "images");
|
|
1554
|
+
return fs13.existsSync(path13.join(imagesDir, "run.sh")) || fs13.existsSync(path13.join(imagesDir, "run.bat"));
|
|
1336
1555
|
}
|
|
1337
1556
|
function removeEmulator(config) {
|
|
1338
1557
|
const emulatorDir = getEmulatorDir(config);
|
|
1339
|
-
if (
|
|
1340
|
-
|
|
1558
|
+
if (fs13.existsSync(emulatorDir)) {
|
|
1559
|
+
fs13.rmSync(emulatorDir, { recursive: true, force: true });
|
|
1341
1560
|
}
|
|
1342
1561
|
}
|
|
1343
1562
|
|
|
1344
1563
|
// src/emulator/lifecycle.ts
|
|
1345
|
-
var
|
|
1346
|
-
var
|
|
1347
|
-
var
|
|
1564
|
+
var fs14 = __toESM(require("fs"), 1);
|
|
1565
|
+
var os7 = __toESM(require("os"), 1);
|
|
1566
|
+
var path14 = __toESM(require("path"), 1);
|
|
1348
1567
|
var import_node_child_process4 = require("child_process");
|
|
1349
1568
|
|
|
1350
1569
|
// src/hdc/exec.ts
|
|
@@ -1353,7 +1572,7 @@ function runProcess(opts) {
|
|
|
1353
1572
|
const { command, args, cwd, env, onOutput } = opts;
|
|
1354
1573
|
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
1355
1574
|
const { abortSignal } = opts;
|
|
1356
|
-
return new Promise((
|
|
1575
|
+
return new Promise((resolve4, reject) => {
|
|
1357
1576
|
if (abortSignal?.aborted) {
|
|
1358
1577
|
reject(new CancelledError(`Command aborted before start: ${command}`));
|
|
1359
1578
|
return;
|
|
@@ -1414,7 +1633,7 @@ ${stderr.trim()}` : "")
|
|
|
1414
1633
|
);
|
|
1415
1634
|
return;
|
|
1416
1635
|
}
|
|
1417
|
-
|
|
1636
|
+
resolve4({ code: code ?? -1, stdout, stderr });
|
|
1418
1637
|
});
|
|
1419
1638
|
});
|
|
1420
1639
|
}
|
|
@@ -1440,9 +1659,29 @@ function ensureOk(result, command) {
|
|
|
1440
1659
|
}
|
|
1441
1660
|
return result;
|
|
1442
1661
|
}
|
|
1662
|
+
var REMOTE_RC_RE = /__ONIRO_RC=(-?\d+)__/g;
|
|
1663
|
+
function parseRemoteExit(stdout) {
|
|
1664
|
+
let code = null;
|
|
1665
|
+
for (const m of stdout.matchAll(REMOTE_RC_RE)) code = Number(m[1]);
|
|
1666
|
+
if (code === null) return null;
|
|
1667
|
+
return { code, stdout: stdout.replace(REMOTE_RC_RE, "").replace(/[ \t\r\n]+$/, "") };
|
|
1668
|
+
}
|
|
1669
|
+
async function shellChecked(opts) {
|
|
1670
|
+
const { command, ...rest } = opts;
|
|
1671
|
+
const res = await hdcExec({ ...rest, args: ["shell", `${command}; echo "__ONIRO_RC=$?__"`] });
|
|
1672
|
+
const parsed = parseRemoteExit(res.stdout);
|
|
1673
|
+
if (!parsed) return res;
|
|
1674
|
+
return { code: parsed.code, stdout: parsed.stdout, stderr: res.stderr };
|
|
1675
|
+
}
|
|
1676
|
+
function ensureRemoteOk(result, command) {
|
|
1677
|
+
if (result.code !== 0) {
|
|
1678
|
+
throw new CommandFailedError(command, result.code, result.stderr.trim() || result.stdout.trim());
|
|
1679
|
+
}
|
|
1680
|
+
return result;
|
|
1681
|
+
}
|
|
1443
1682
|
|
|
1444
1683
|
// src/emulator/lifecycle.ts
|
|
1445
|
-
var PID_FILE =
|
|
1684
|
+
var PID_FILE = path14.join(os7.tmpdir(), "oniro_emulator.pid");
|
|
1446
1685
|
async function attemptHdcConnection(config, address = "127.0.0.1:55555", logger = noopLogger) {
|
|
1447
1686
|
try {
|
|
1448
1687
|
await hdcExec({ config, args: ["start", "-r"], logger });
|
|
@@ -1455,24 +1694,24 @@ async function attemptHdcConnection(config, address = "127.0.0.1:55555", logger
|
|
|
1455
1694
|
}
|
|
1456
1695
|
}
|
|
1457
1696
|
function resolveLauncher(imagesPath, headless, connect) {
|
|
1458
|
-
const runSh =
|
|
1459
|
-
const runBat =
|
|
1697
|
+
const runSh = path14.join(imagesPath, "run.sh");
|
|
1698
|
+
const runBat = path14.join(imagesPath, "run.bat");
|
|
1460
1699
|
const extra = [];
|
|
1461
1700
|
if (headless) extra.push("--headless");
|
|
1462
1701
|
if (connect) extra.push("--connect", connect);
|
|
1463
|
-
if (
|
|
1464
|
-
if (
|
|
1702
|
+
if (os7.platform() === "win32") {
|
|
1703
|
+
if (fs14.existsSync(runBat)) {
|
|
1465
1704
|
return { command: "cmd.exe", args: ["/c", runBat, ...extra], cwd: imagesPath };
|
|
1466
1705
|
}
|
|
1467
|
-
if (
|
|
1706
|
+
if (fs14.existsSync(runSh)) {
|
|
1468
1707
|
return { command: "bash", args: [runSh, ...extra], cwd: imagesPath };
|
|
1469
1708
|
}
|
|
1470
1709
|
throw new OniroError(`No emulator launcher (run.bat or run.sh) found in ${imagesPath}.`);
|
|
1471
1710
|
}
|
|
1472
|
-
if (
|
|
1711
|
+
if (fs14.existsSync(runSh)) {
|
|
1473
1712
|
return { command: "bash", args: [runSh, ...extra], cwd: imagesPath };
|
|
1474
1713
|
}
|
|
1475
|
-
if (
|
|
1714
|
+
if (fs14.existsSync(runBat)) {
|
|
1476
1715
|
return { command: "bash", args: [runBat, ...extra], cwd: imagesPath };
|
|
1477
1716
|
}
|
|
1478
1717
|
throw new OniroError(`No emulator launcher (run.sh or run.bat) found in ${imagesPath}.`);
|
|
@@ -1480,9 +1719,9 @@ function resolveLauncher(imagesPath, headless, connect) {
|
|
|
1480
1719
|
async function startEmulator(opts) {
|
|
1481
1720
|
const { config } = opts;
|
|
1482
1721
|
const logger = opts.logger ?? noopLogger;
|
|
1483
|
-
if (
|
|
1722
|
+
if (os7.platform() !== "win32" && fs14.existsSync(PID_FILE)) {
|
|
1484
1723
|
try {
|
|
1485
|
-
const pid = Number(
|
|
1724
|
+
const pid = Number(fs14.readFileSync(PID_FILE, "utf8").trim());
|
|
1486
1725
|
if (Number.isFinite(pid) && pid > 0) {
|
|
1487
1726
|
try {
|
|
1488
1727
|
process.kill(pid, 0);
|
|
@@ -1498,13 +1737,13 @@ async function startEmulator(opts) {
|
|
|
1498
1737
|
logger.warn(`Could not read PID file: ${err.message}`);
|
|
1499
1738
|
}
|
|
1500
1739
|
}
|
|
1501
|
-
const imagesPath =
|
|
1502
|
-
if (!
|
|
1740
|
+
const imagesPath = path14.join(getEmulatorDir(config), "images");
|
|
1741
|
+
if (!fs14.existsSync(imagesPath)) {
|
|
1503
1742
|
throw new OniroError(`Emulator images directory not found at ${imagesPath}. Run \`oniro-app emulator install\` first.`);
|
|
1504
1743
|
}
|
|
1505
1744
|
const launcher = resolveLauncher(imagesPath, opts.headless === true, opts.connect);
|
|
1506
|
-
const logPath = opts.logFile ?? (
|
|
1507
|
-
const logFd =
|
|
1745
|
+
const logPath = opts.logFile ?? (os7.platform() === "win32" ? "NUL" : "/dev/null");
|
|
1746
|
+
const logFd = fs14.openSync(logPath, "a");
|
|
1508
1747
|
let child;
|
|
1509
1748
|
try {
|
|
1510
1749
|
child = (0, import_node_child_process4.spawn)(launcher.command, [...launcher.args], {
|
|
@@ -1514,19 +1753,19 @@ async function startEmulator(opts) {
|
|
|
1514
1753
|
windowsHide: true
|
|
1515
1754
|
});
|
|
1516
1755
|
} finally {
|
|
1517
|
-
|
|
1756
|
+
fs14.closeSync(logFd);
|
|
1518
1757
|
}
|
|
1519
1758
|
if (!child.pid) {
|
|
1520
1759
|
throw new OniroError(`Failed to spawn launcher (${launcher.command} ${launcher.args.join(" ")}).`);
|
|
1521
1760
|
}
|
|
1522
|
-
|
|
1761
|
+
fs14.writeFileSync(PID_FILE, String(child.pid));
|
|
1523
1762
|
child.unref();
|
|
1524
1763
|
logger.info(`Emulator launched (PID ${child.pid}). Logs: ${logPath}`);
|
|
1525
|
-
const earlyExit = new Promise((
|
|
1526
|
-
child.once("exit", (code) =>
|
|
1527
|
-
child.once("error", () =>
|
|
1764
|
+
const earlyExit = new Promise((resolve4) => {
|
|
1765
|
+
child.once("exit", (code) => resolve4(code));
|
|
1766
|
+
child.once("error", () => resolve4(-1));
|
|
1528
1767
|
});
|
|
1529
|
-
const liveness = new Promise((
|
|
1768
|
+
const liveness = new Promise((resolve4) => setTimeout(() => resolve4("alive"), 2e3));
|
|
1530
1769
|
const outcome = await Promise.race([earlyExit, liveness]);
|
|
1531
1770
|
if (outcome !== "alive") {
|
|
1532
1771
|
const tail = readTail(logPath, 4e3);
|
|
@@ -1566,24 +1805,24 @@ ${tail}` : ""}`);
|
|
|
1566
1805
|
}
|
|
1567
1806
|
function readTail(filePath, bytes) {
|
|
1568
1807
|
try {
|
|
1569
|
-
const stat =
|
|
1808
|
+
const stat = fs14.statSync(filePath);
|
|
1570
1809
|
const start = Math.max(0, stat.size - bytes);
|
|
1571
|
-
const fd =
|
|
1810
|
+
const fd = fs14.openSync(filePath, "r");
|
|
1572
1811
|
try {
|
|
1573
1812
|
const buf = Buffer.alloc(stat.size - start);
|
|
1574
|
-
|
|
1813
|
+
fs14.readSync(fd, buf, 0, buf.length, start);
|
|
1575
1814
|
return buf.toString("utf8");
|
|
1576
1815
|
} finally {
|
|
1577
|
-
|
|
1816
|
+
fs14.closeSync(fd);
|
|
1578
1817
|
}
|
|
1579
1818
|
} catch {
|
|
1580
1819
|
return "";
|
|
1581
1820
|
}
|
|
1582
1821
|
}
|
|
1583
1822
|
async function stopEmulator(logger = noopLogger) {
|
|
1584
|
-
if (
|
|
1823
|
+
if (fs14.existsSync(PID_FILE)) {
|
|
1585
1824
|
try {
|
|
1586
|
-
const pid = Number(
|
|
1825
|
+
const pid = Number(fs14.readFileSync(PID_FILE, "utf8").trim());
|
|
1587
1826
|
if (Number.isFinite(pid) && pid > 0) {
|
|
1588
1827
|
try {
|
|
1589
1828
|
process.kill(pid, "SIGTERM");
|
|
@@ -1596,13 +1835,13 @@ async function stopEmulator(logger = noopLogger) {
|
|
|
1596
1835
|
logger.warn(`Could not read PID file: ${err.message}`);
|
|
1597
1836
|
}
|
|
1598
1837
|
}
|
|
1599
|
-
const [killCmd, ...killArgs] =
|
|
1838
|
+
const [killCmd, ...killArgs] = os7.platform() === "win32" ? ["taskkill", "/IM", "qemu-system-x86_64.exe", "/F"] : ["pkill", "-f", "qemu-system-x86_64"];
|
|
1600
1839
|
try {
|
|
1601
1840
|
await runProcess({ command: killCmd, args: killArgs, logger });
|
|
1602
1841
|
} catch (err) {
|
|
1603
1842
|
logger.warn(`[emulator] could not run ${killCmd}: ${err.message}`);
|
|
1604
1843
|
}
|
|
1605
|
-
|
|
1844
|
+
fs14.rm(PID_FILE, { force: true }, (err) => {
|
|
1606
1845
|
if (err) logger.warn(`Could not remove PID file: ${err.message}`);
|
|
1607
1846
|
});
|
|
1608
1847
|
}
|
|
@@ -1725,7 +1964,7 @@ async function getDisplaySize(config, opts = {}) {
|
|
|
1725
1964
|
|
|
1726
1965
|
// src/hdc/wait.ts
|
|
1727
1966
|
function delay(ms, signal) {
|
|
1728
|
-
return new Promise((
|
|
1967
|
+
return new Promise((resolve4, reject) => {
|
|
1729
1968
|
if (signal?.aborted) {
|
|
1730
1969
|
reject(new CancelledError("Wait cancelled."));
|
|
1731
1970
|
return;
|
|
@@ -1740,7 +1979,7 @@ function delay(ms, signal) {
|
|
|
1740
1979
|
};
|
|
1741
1980
|
const timer = setTimeout(() => {
|
|
1742
1981
|
cleanup();
|
|
1743
|
-
|
|
1982
|
+
resolve4();
|
|
1744
1983
|
}, ms);
|
|
1745
1984
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1746
1985
|
});
|
|
@@ -1769,21 +2008,21 @@ async function waitForCondition(opts) {
|
|
|
1769
2008
|
}
|
|
1770
2009
|
|
|
1771
2010
|
// src/hdc/app.ts
|
|
1772
|
-
var
|
|
1773
|
-
var
|
|
2011
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
2012
|
+
var path16 = __toESM(require("path"), 1);
|
|
1774
2013
|
var import_node_child_process5 = require("child_process");
|
|
1775
2014
|
|
|
1776
2015
|
// src/hdc/project.ts
|
|
1777
|
-
var
|
|
1778
|
-
var
|
|
2016
|
+
var fs15 = __toESM(require("fs"), 1);
|
|
2017
|
+
var path15 = __toESM(require("path"), 1);
|
|
1779
2018
|
var import_json53 = __toESM(require("json5"), 1);
|
|
1780
2019
|
function readJson5(filePath) {
|
|
1781
|
-
const content =
|
|
2020
|
+
const content = fs15.readFileSync(filePath, "utf-8");
|
|
1782
2021
|
return import_json53.default.parse(content);
|
|
1783
2022
|
}
|
|
1784
2023
|
function getBundleName(projectDir) {
|
|
1785
|
-
const appJsonPath =
|
|
1786
|
-
if (!
|
|
2024
|
+
const appJsonPath = path15.join(projectDir, "AppScope", "app.json5");
|
|
2025
|
+
if (!fs15.existsSync(appJsonPath)) {
|
|
1787
2026
|
throw new OniroError(`Could not find app.json5 at ${appJsonPath}`);
|
|
1788
2027
|
}
|
|
1789
2028
|
const appJson = readJson5(appJsonPath);
|
|
@@ -1793,8 +2032,8 @@ function getBundleName(projectDir) {
|
|
|
1793
2032
|
return appJson.app.bundleName;
|
|
1794
2033
|
}
|
|
1795
2034
|
function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
1796
|
-
const moduleJsonPath =
|
|
1797
|
-
if (!
|
|
2035
|
+
const moduleJsonPath = path15.join(projectDir, moduleName, "src", "main", "module.json5");
|
|
2036
|
+
if (!fs15.existsSync(moduleJsonPath)) {
|
|
1798
2037
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
1799
2038
|
}
|
|
1800
2039
|
const moduleJson = readJson5(moduleJsonPath);
|
|
@@ -1817,8 +2056,8 @@ function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
|
1817
2056
|
async function installApp(opts) {
|
|
1818
2057
|
const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
|
|
1819
2058
|
const relativeHapPath = opts.hapPath ?? opts.config.get("hapPath", defaultPaths.hapPath);
|
|
1820
|
-
const hapPath =
|
|
1821
|
-
if (!
|
|
2059
|
+
const hapPath = path16.isAbsolute(relativeHapPath) ? relativeHapPath : path16.join(opts.projectDir, relativeHapPath);
|
|
2060
|
+
if (!fs16.existsSync(hapPath)) {
|
|
1822
2061
|
throw new OniroError(`HAP file not found at: ${hapPath}. Build and sign the app first.`);
|
|
1823
2062
|
}
|
|
1824
2063
|
const result = await hdcExec({ config: opts.config, args: ["install", hapPath], timeoutMs: 3e5 });
|
|
@@ -1835,13 +2074,59 @@ async function installApp(opts) {
|
|
|
1835
2074
|
function detectAaStartFailure(output) {
|
|
1836
2075
|
return /failed to start ability|Error Code:\s*\d|Error Message:/i.test(output) ? output.trim() : null;
|
|
1837
2076
|
}
|
|
2077
|
+
function parseMainAbilityFromBmDump(stdout) {
|
|
2078
|
+
const start = stdout.indexOf("{");
|
|
2079
|
+
if (start < 0) return null;
|
|
2080
|
+
let info;
|
|
2081
|
+
try {
|
|
2082
|
+
info = JSON.parse(stdout.slice(start));
|
|
2083
|
+
} catch {
|
|
2084
|
+
return null;
|
|
2085
|
+
}
|
|
2086
|
+
const mods = Array.isArray(info?.hapModuleInfos) ? info.hapModuleInfos : [];
|
|
2087
|
+
const abilityOf = (m) => m?.mainElementName || m?.mainAbility || void 0;
|
|
2088
|
+
const isEntry = (m) => m?.moduleType === 1 || m?.moduleType === "1" || m?.moduleType === "entry";
|
|
2089
|
+
const entry = mods.find((m) => isEntry(m) && abilityOf(m));
|
|
2090
|
+
const any = mods.find((m) => abilityOf(m));
|
|
2091
|
+
return entry && abilityOf(entry) || any && abilityOf(any) || null;
|
|
2092
|
+
}
|
|
2093
|
+
async function resolveInstalledMainAbility(opts) {
|
|
2094
|
+
const res = await shell({
|
|
2095
|
+
config: opts.config,
|
|
2096
|
+
command: `bm dump -n ${opts.bundle}`,
|
|
2097
|
+
deviceSerial: opts.deviceSerial,
|
|
2098
|
+
timeoutMs: 15e3,
|
|
2099
|
+
logger: opts.logger
|
|
2100
|
+
});
|
|
2101
|
+
const ability = parseMainAbilityFromBmDump(res.stdout);
|
|
2102
|
+
if (!ability) {
|
|
2103
|
+
throw new OniroError(
|
|
2104
|
+
`Could not determine the main ability for installed bundle ${opts.bundle} (is it installed?). Pass an explicit ability instead.`
|
|
2105
|
+
);
|
|
2106
|
+
}
|
|
2107
|
+
return ability;
|
|
2108
|
+
}
|
|
1838
2109
|
async function launchApp(opts) {
|
|
1839
2110
|
const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
|
|
1840
|
-
|
|
1841
|
-
|
|
2111
|
+
let bundleName;
|
|
2112
|
+
let mainAbility;
|
|
2113
|
+
if (opts.bundleName) {
|
|
2114
|
+
bundleName = opts.bundleName;
|
|
2115
|
+
mainAbility = opts.abilityName ?? await resolveInstalledMainAbility({
|
|
2116
|
+
config: opts.config,
|
|
2117
|
+
bundle: bundleName,
|
|
2118
|
+
deviceSerial: opts.deviceSerial,
|
|
2119
|
+
logger: opts.logger
|
|
2120
|
+
});
|
|
2121
|
+
} else {
|
|
2122
|
+
if (!opts.projectDir) throw new OniroError("launchApp requires either bundleName or projectDir.");
|
|
2123
|
+
bundleName = getBundleName(opts.projectDir);
|
|
2124
|
+
mainAbility = getMainAbility(opts.projectDir, opts.moduleName, opts.abilityName);
|
|
2125
|
+
}
|
|
1842
2126
|
const result = await hdcExec({
|
|
1843
2127
|
config: opts.config,
|
|
1844
|
-
args: ["shell", "aa", "start", "-a", mainAbility, "-b", bundleName]
|
|
2128
|
+
args: ["shell", "aa", "start", "-a", mainAbility, "-b", bundleName],
|
|
2129
|
+
deviceSerial: opts.deviceSerial
|
|
1845
2130
|
});
|
|
1846
2131
|
if (result.stdout.trim()) logger.info(result.stdout.trim());
|
|
1847
2132
|
if (result.stderr.trim()) logger.warn(result.stderr.trim());
|
|
@@ -1856,7 +2141,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1856
2141
|
const logger = options.logger ?? noopLogger;
|
|
1857
2142
|
const timeoutMs = options.timeoutMs ?? 1e3;
|
|
1858
2143
|
const hdc = getHdcPath(config);
|
|
1859
|
-
return new Promise((
|
|
2144
|
+
return new Promise((resolve4, reject) => {
|
|
1860
2145
|
const proc = (0, import_node_child_process5.spawn)(hdc, ["track-jpid"]);
|
|
1861
2146
|
const processes = [];
|
|
1862
2147
|
let resolved = false;
|
|
@@ -1870,7 +2155,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1870
2155
|
if (options.targetProcessName && name === options.targetProcessName && !resolved) {
|
|
1871
2156
|
resolved = true;
|
|
1872
2157
|
proc.kill();
|
|
1873
|
-
|
|
2158
|
+
resolve4(pid);
|
|
1874
2159
|
return;
|
|
1875
2160
|
}
|
|
1876
2161
|
}
|
|
@@ -1891,7 +2176,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1891
2176
|
if (options.targetProcessName) {
|
|
1892
2177
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
1893
2178
|
} else {
|
|
1894
|
-
|
|
2179
|
+
resolve4(processes);
|
|
1895
2180
|
}
|
|
1896
2181
|
}, timeoutMs);
|
|
1897
2182
|
proc.on("close", () => {
|
|
@@ -1901,7 +2186,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1901
2186
|
if (options.targetProcessName) {
|
|
1902
2187
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
1903
2188
|
} else {
|
|
1904
|
-
|
|
2189
|
+
resolve4(processes);
|
|
1905
2190
|
}
|
|
1906
2191
|
});
|
|
1907
2192
|
});
|
|
@@ -1921,8 +2206,17 @@ async function findRunningProcess(opts) {
|
|
|
1921
2206
|
logger: opts.logger
|
|
1922
2207
|
});
|
|
1923
2208
|
const pid = res.stdout.trim().split(/\s+/).filter(Boolean)[0];
|
|
1924
|
-
if (res.code
|
|
1925
|
-
|
|
2209
|
+
if (res.code === 0 && pid && /^\d+$/.test(pid)) return { pid, name: opts.bundle };
|
|
2210
|
+
try {
|
|
2211
|
+
const list = await listRunningProcesses(opts.config, { timeoutMs: 1200, logger: opts.logger });
|
|
2212
|
+
if (Array.isArray(list)) {
|
|
2213
|
+
const mine = (name) => name === opts.bundle || name.startsWith(`${opts.bundle}/`) || name.startsWith(`${opts.bundle}:`);
|
|
2214
|
+
const match = list.find((p) => p.name === opts.bundle) ?? list.find((p) => mine(p.name));
|
|
2215
|
+
if (match) return match;
|
|
2216
|
+
}
|
|
2217
|
+
} catch {
|
|
2218
|
+
}
|
|
2219
|
+
return null;
|
|
1926
2220
|
}
|
|
1927
2221
|
async function uninstallApp(opts) {
|
|
1928
2222
|
const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
|
|
@@ -2036,12 +2330,12 @@ async function reboot(opts) {
|
|
|
2036
2330
|
}
|
|
2037
2331
|
|
|
2038
2332
|
// src/hdc/screen.ts
|
|
2039
|
-
var
|
|
2040
|
-
var
|
|
2041
|
-
var
|
|
2333
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
2334
|
+
var os8 = __toESM(require("os"), 1);
|
|
2335
|
+
var path17 = __toESM(require("path"), 1);
|
|
2042
2336
|
var import_node_crypto = require("crypto");
|
|
2043
2337
|
function tmpName(ext) {
|
|
2044
|
-
return
|
|
2338
|
+
return path17.join(os8.tmpdir(), `oniro_screen_${(0, import_node_crypto.randomBytes)(6).toString("hex")}.${ext}`);
|
|
2045
2339
|
}
|
|
2046
2340
|
async function takeScreenshot(opts) {
|
|
2047
2341
|
const remote = "/data/local/tmp/oniro_screenshot.jpeg";
|
|
@@ -2051,11 +2345,11 @@ async function takeScreenshot(opts) {
|
|
|
2051
2345
|
const local = tmpName("jpeg");
|
|
2052
2346
|
try {
|
|
2053
2347
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
2054
|
-
const pixels = await
|
|
2348
|
+
const pixels = await fs17.promises.readFile(local);
|
|
2055
2349
|
const size = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial }) ?? { width: 0, height: 0 };
|
|
2056
2350
|
return { pixels, width: size.width, height: size.height };
|
|
2057
2351
|
} finally {
|
|
2058
|
-
|
|
2352
|
+
fs17.promises.unlink(local).catch(() => {
|
|
2059
2353
|
});
|
|
2060
2354
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
2061
2355
|
});
|
|
@@ -2074,9 +2368,9 @@ async function captureBurst(opts) {
|
|
|
2074
2368
|
const local = tmpName(`burst_${i}.jpeg`);
|
|
2075
2369
|
try {
|
|
2076
2370
|
await recvFile({ config: opts.config, remote: `${remoteDir}/f${i}.jpeg`, local, deviceSerial: opts.deviceSerial });
|
|
2077
|
-
frames.push(await
|
|
2371
|
+
frames.push(await fs17.promises.readFile(local));
|
|
2078
2372
|
} finally {
|
|
2079
|
-
|
|
2373
|
+
fs17.promises.unlink(local).catch(() => {
|
|
2080
2374
|
});
|
|
2081
2375
|
}
|
|
2082
2376
|
}
|
|
@@ -2120,8 +2414,8 @@ function buildInputCommand(opts) {
|
|
|
2120
2414
|
}
|
|
2121
2415
|
async function sendInput(opts) {
|
|
2122
2416
|
const cmd = buildInputCommand(opts);
|
|
2123
|
-
const res = await
|
|
2124
|
-
|
|
2417
|
+
const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
|
|
2418
|
+
ensureRemoteOk(res, `hdc shell ${cmd}`);
|
|
2125
2419
|
}
|
|
2126
2420
|
function buildGestureCommands(waypoints) {
|
|
2127
2421
|
if (waypoints.length < 2) {
|
|
@@ -2164,32 +2458,47 @@ function waypointsToRawEvents(waypoints, holdStartMs = 0, holdEndMs = 0) {
|
|
|
2164
2458
|
events.push({ type: "up", x: last.x, y: last.y, t: last.t + holdStartMs + holdEndMs });
|
|
2165
2459
|
return events;
|
|
2166
2460
|
}
|
|
2461
|
+
var UITEST_VELOCITY_MIN = 200;
|
|
2462
|
+
var UITEST_VELOCITY_MAX = 4e4;
|
|
2463
|
+
function buildGestureUitestCommand(waypoints, opts = {}) {
|
|
2464
|
+
if (waypoints.length < 2) throw new OniroError("sendGesture requires at least two waypoints.");
|
|
2465
|
+
const a = waypoints[0];
|
|
2466
|
+
const b = waypoints[waypoints.length - 1];
|
|
2467
|
+
const dist = Math.hypot(b.x - a.x, b.y - a.y);
|
|
2468
|
+
const dtMs = b.t - a.t;
|
|
2469
|
+
const op = (opts.holdStartMs ?? 0) > 0 ? "drag" : "swipe";
|
|
2470
|
+
let cmd = `uitest uiInput ${op} ${a.x} ${a.y} ${b.x} ${b.y}`;
|
|
2471
|
+
if (dtMs > 0 && dist > 0) {
|
|
2472
|
+
const v = Math.round(dist / (dtMs / 1e3));
|
|
2473
|
+
cmd += ` ${Math.max(UITEST_VELOCITY_MIN, Math.min(UITEST_VELOCITY_MAX, v))}`;
|
|
2474
|
+
}
|
|
2475
|
+
return cmd;
|
|
2476
|
+
}
|
|
2167
2477
|
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;
|
|
2478
|
+
if ((opts.holdEndMs ?? 0) > 0) {
|
|
2479
|
+
opts.logger?.warn(
|
|
2480
|
+
"sendGesture: hold-end has no uitest equivalent and is ignored; use sendRawTouch for a trailing hold."
|
|
2481
|
+
);
|
|
2177
2482
|
}
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2483
|
+
if (opts.waypoints.length > 2) {
|
|
2484
|
+
opts.logger?.debug(
|
|
2485
|
+
`sendGesture: ${opts.waypoints.length} waypoints collapsed to first\u2192last (uitest has no polyline path).`
|
|
2486
|
+
);
|
|
2181
2487
|
}
|
|
2488
|
+
const cmd = buildGestureUitestCommand(opts.waypoints, { holdStartMs: opts.holdStartMs });
|
|
2489
|
+
const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
|
|
2490
|
+
ensureRemoteOk(res, `hdc shell ${cmd}`);
|
|
2182
2491
|
}
|
|
2183
2492
|
async function sendRawTouch(opts) {
|
|
2184
2493
|
const cmd = buildRawTouchCommand(opts.events);
|
|
2185
|
-
const res = await
|
|
2186
|
-
|
|
2494
|
+
const res = await shellChecked({ config: opts.config, command: cmd, deviceSerial: opts.deviceSerial, timeoutMs: 3e4, logger: opts.logger });
|
|
2495
|
+
ensureRemoteOk(res, `hdc shell ${cmd}`);
|
|
2187
2496
|
}
|
|
2188
2497
|
|
|
2189
2498
|
// src/hdc/dump.ts
|
|
2190
|
-
var
|
|
2191
|
-
var
|
|
2192
|
-
var
|
|
2499
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
2500
|
+
var os9 = __toESM(require("os"), 1);
|
|
2501
|
+
var path18 = __toESM(require("path"), 1);
|
|
2193
2502
|
var import_node_crypto2 = require("crypto");
|
|
2194
2503
|
function parseBounds(s) {
|
|
2195
2504
|
const m = /^\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]$/.exec(s ?? "");
|
|
@@ -2274,10 +2583,10 @@ async function dumpLayout(opts) {
|
|
|
2274
2583
|
if (!m) throw new OniroError(`Could not parse dumpLayout output:
|
|
2275
2584
|
${dump.stdout}`);
|
|
2276
2585
|
const remote = m[1];
|
|
2277
|
-
const local =
|
|
2586
|
+
const local = path18.join(os9.tmpdir(), `oniro_layout_${(0, import_node_crypto2.randomBytes)(6).toString("hex")}.json`);
|
|
2278
2587
|
try {
|
|
2279
2588
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
2280
|
-
const parsed = JSON.parse(await
|
|
2589
|
+
const parsed = JSON.parse(await fs18.promises.readFile(local, "utf8"));
|
|
2281
2590
|
const display = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial });
|
|
2282
2591
|
if (opts.prune === false) {
|
|
2283
2592
|
return { display, tree: parsed };
|
|
@@ -2286,7 +2595,7 @@ ${dump.stdout}`);
|
|
|
2286
2595
|
const tree = Array.isArray(prunedRaw) ? { children: prunedRaw } : prunedRaw ?? { children: [] };
|
|
2287
2596
|
return { display, tree };
|
|
2288
2597
|
} finally {
|
|
2289
|
-
|
|
2598
|
+
fs18.promises.unlink(local).catch(() => {
|
|
2290
2599
|
});
|
|
2291
2600
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
2292
2601
|
});
|
|
@@ -2298,7 +2607,7 @@ var import_node_child_process6 = require("child_process");
|
|
|
2298
2607
|
function setHilogLevel(opts) {
|
|
2299
2608
|
const logger = opts.logger ?? noopLogger;
|
|
2300
2609
|
const hdc = getHdcPath(opts.config);
|
|
2301
|
-
return new Promise((
|
|
2610
|
+
return new Promise((resolve4, reject) => {
|
|
2302
2611
|
const child = (0, import_node_child_process6.spawn)(hdc, ["shell", "hilog", "-b", opts.level]);
|
|
2303
2612
|
let stderr = "";
|
|
2304
2613
|
child.stderr.on("data", (chunk) => {
|
|
@@ -2310,7 +2619,7 @@ function setHilogLevel(opts) {
|
|
|
2310
2619
|
});
|
|
2311
2620
|
child.once("close", (code) => {
|
|
2312
2621
|
if (code === 0) {
|
|
2313
|
-
|
|
2622
|
+
resolve4();
|
|
2314
2623
|
} else {
|
|
2315
2624
|
const msg = stderr.trim() || `hdc shell hilog -b ${opts.level} exited with code ${code}`;
|
|
2316
2625
|
logger.error(`[hilog] ${msg}`);
|
|
@@ -2365,7 +2674,7 @@ async function resolveProcessId(config, bundle, deviceSerial) {
|
|
|
2365
2674
|
return proc?.pid;
|
|
2366
2675
|
}
|
|
2367
2676
|
function waitForLog(opts) {
|
|
2368
|
-
return new Promise((
|
|
2677
|
+
return new Promise((resolve4, reject) => {
|
|
2369
2678
|
const deadline = Date.now() + opts.timeoutMs;
|
|
2370
2679
|
let settled = false;
|
|
2371
2680
|
let child = null;
|
|
@@ -2387,7 +2696,7 @@ function waitForLog(opts) {
|
|
|
2387
2696
|
if (settled) return;
|
|
2388
2697
|
settled = true;
|
|
2389
2698
|
cleanup();
|
|
2390
|
-
|
|
2699
|
+
resolve4(entry);
|
|
2391
2700
|
};
|
|
2392
2701
|
const fail = (err) => {
|
|
2393
2702
|
if (settled) return;
|
|
@@ -2434,7 +2743,7 @@ function waitForLog(opts) {
|
|
|
2434
2743
|
});
|
|
2435
2744
|
}
|
|
2436
2745
|
function watchLog(opts) {
|
|
2437
|
-
return new Promise((
|
|
2746
|
+
return new Promise((resolve4, reject) => {
|
|
2438
2747
|
const matches = [];
|
|
2439
2748
|
let settled = false;
|
|
2440
2749
|
let child = null;
|
|
@@ -2454,7 +2763,7 @@ function watchLog(opts) {
|
|
|
2454
2763
|
if (settled) return;
|
|
2455
2764
|
settled = true;
|
|
2456
2765
|
cleanup();
|
|
2457
|
-
|
|
2766
|
+
resolve4(opts.dedup === false ? matches : dedupEntries(matches));
|
|
2458
2767
|
};
|
|
2459
2768
|
const onAbort = () => {
|
|
2460
2769
|
if (settled) return;
|
|
@@ -2506,8 +2815,8 @@ async function dumpLog(opts) {
|
|
|
2506
2815
|
}
|
|
2507
2816
|
|
|
2508
2817
|
// src/build/runHvigorw.ts
|
|
2509
|
-
var
|
|
2510
|
-
var
|
|
2818
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
2819
|
+
var path19 = __toESM(require("path"), 1);
|
|
2511
2820
|
var import_node_child_process7 = require("child_process");
|
|
2512
2821
|
function buildHvigorwArgs(opts) {
|
|
2513
2822
|
const args = [opts.task ?? "assembleHap", "--mode", "module"];
|
|
@@ -2522,17 +2831,17 @@ function buildHvigorwArgs(opts) {
|
|
|
2522
2831
|
function runHvigorw(opts) {
|
|
2523
2832
|
const { config, projectDir } = opts;
|
|
2524
2833
|
const logger = opts.logger ?? noopLogger;
|
|
2525
|
-
if (!
|
|
2834
|
+
if (!fs19.existsSync(path19.join(projectDir, "build-profile.json5"))) {
|
|
2526
2835
|
throw new OniroError(`Not an OpenHarmony project: ${projectDir} (build-profile.json5 not found).`);
|
|
2527
2836
|
}
|
|
2528
|
-
if (!
|
|
2837
|
+
if (!fs19.existsSync(getCmdToolsPath(config))) {
|
|
2529
2838
|
throw new CmdToolsNotInstalledError(getCmdToolsPath(config));
|
|
2530
2839
|
}
|
|
2531
2840
|
const hvigorw = getHvigorwPath(config, projectDir);
|
|
2532
2841
|
const args = buildHvigorwArgs(opts);
|
|
2533
2842
|
if (process.platform !== "win32") {
|
|
2534
2843
|
try {
|
|
2535
|
-
|
|
2844
|
+
fs19.chmodSync(hvigorw, 493);
|
|
2536
2845
|
} catch {
|
|
2537
2846
|
}
|
|
2538
2847
|
}
|
|
@@ -2540,7 +2849,7 @@ function runHvigorw(opts) {
|
|
|
2540
2849
|
...process.env,
|
|
2541
2850
|
OHOS_BASE_SDK_HOME: getOhosBaseSdkHome(config)
|
|
2542
2851
|
};
|
|
2543
|
-
return new Promise((
|
|
2852
|
+
return new Promise((resolve4, reject) => {
|
|
2544
2853
|
if (opts.abortSignal?.aborted) {
|
|
2545
2854
|
reject(new CancelledError("hvigorw build cancelled."));
|
|
2546
2855
|
return;
|
|
@@ -2581,19 +2890,18 @@ function runHvigorw(opts) {
|
|
|
2581
2890
|
settled = true;
|
|
2582
2891
|
cleanup();
|
|
2583
2892
|
const exitCode = code ?? 1;
|
|
2584
|
-
if (exitCode === 0)
|
|
2893
|
+
if (exitCode === 0) resolve4({ exitCode });
|
|
2585
2894
|
else reject(new OniroError(`hvigorw exited with code ${exitCode}`));
|
|
2586
2895
|
});
|
|
2587
2896
|
});
|
|
2588
2897
|
}
|
|
2589
2898
|
|
|
2590
2899
|
// src/build/discoverHaps.ts
|
|
2591
|
-
var
|
|
2592
|
-
var
|
|
2593
|
-
function
|
|
2594
|
-
const
|
|
2595
|
-
|
|
2596
|
-
return first && first !== ".." ? first : "(root)";
|
|
2900
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
2901
|
+
var path20 = __toESM(require("path"), 1);
|
|
2902
|
+
function moduleOfHap(hapFileName) {
|
|
2903
|
+
const dash = hapFileName.indexOf("-");
|
|
2904
|
+
return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
|
|
2597
2905
|
}
|
|
2598
2906
|
async function discoverHaps(opts) {
|
|
2599
2907
|
const { projectDir } = opts;
|
|
@@ -2601,14 +2909,14 @@ async function discoverHaps(opts) {
|
|
|
2601
2909
|
const result = {};
|
|
2602
2910
|
const walk = async (dir, depth) => {
|
|
2603
2911
|
if (depth > maxDepth) return;
|
|
2604
|
-
const entries = await
|
|
2912
|
+
const entries = await fs20.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
2605
2913
|
for (const e of entries) {
|
|
2606
|
-
const full =
|
|
2914
|
+
const full = path20.join(dir, e.name);
|
|
2607
2915
|
if (e.isDirectory()) {
|
|
2608
2916
|
if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
|
|
2609
2917
|
await walk(full, depth + 1);
|
|
2610
2918
|
} else if (e.isFile() && e.name.endsWith(".hap")) {
|
|
2611
|
-
const moduleName =
|
|
2919
|
+
const moduleName = moduleOfHap(e.name);
|
|
2612
2920
|
const bucket = result[moduleName] ??= { signed: [], unsigned: [] };
|
|
2613
2921
|
if (e.name.includes("unsigned")) bucket.unsigned.push(full);
|
|
2614
2922
|
else if (e.name.includes("signed")) bucket.signed.push(full);
|
|
@@ -2620,8 +2928,8 @@ async function discoverHaps(opts) {
|
|
|
2620
2928
|
}
|
|
2621
2929
|
|
|
2622
2930
|
// src/build/ohpm.ts
|
|
2623
|
-
var
|
|
2624
|
-
var
|
|
2931
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
2932
|
+
var path21 = __toESM(require("path"), 1);
|
|
2625
2933
|
function runOhpm(opts) {
|
|
2626
2934
|
return runProcess({
|
|
2627
2935
|
command: getOhpmPath(opts.config),
|
|
@@ -2634,7 +2942,7 @@ function runOhpm(opts) {
|
|
|
2634
2942
|
});
|
|
2635
2943
|
}
|
|
2636
2944
|
async function ensureOhModules(opts) {
|
|
2637
|
-
if (
|
|
2945
|
+
if (fs21.existsSync(path21.join(opts.projectDir, "oh_modules"))) {
|
|
2638
2946
|
return { installed: false };
|
|
2639
2947
|
}
|
|
2640
2948
|
const res = await runOhpm({
|
|
@@ -2729,21 +3037,21 @@ function isValidBundleName(bundleName) {
|
|
|
2729
3037
|
}
|
|
2730
3038
|
|
|
2731
3039
|
// src/project/templates.ts
|
|
2732
|
-
var
|
|
2733
|
-
var
|
|
3040
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
3041
|
+
var path22 = __toESM(require("path"), 1);
|
|
2734
3042
|
function toHumanTemplateName(folderName) {
|
|
2735
3043
|
return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
2736
3044
|
}
|
|
2737
3045
|
function listTemplates(templateRoot) {
|
|
2738
|
-
if (!
|
|
2739
|
-
const entries =
|
|
3046
|
+
if (!fs22.existsSync(templateRoot)) return [];
|
|
3047
|
+
const entries = fs22.readdirSync(templateRoot, { withFileTypes: true });
|
|
2740
3048
|
return entries.filter((e) => e.isDirectory()).map((e) => {
|
|
2741
|
-
const dir =
|
|
2742
|
-
const metaPath =
|
|
3049
|
+
const dir = path22.join(templateRoot, e.name);
|
|
3050
|
+
const metaPath = path22.join(dir, "template.json");
|
|
2743
3051
|
let meta = {};
|
|
2744
|
-
if (
|
|
3052
|
+
if (fs22.existsSync(metaPath)) {
|
|
2745
3053
|
try {
|
|
2746
|
-
meta = JSON.parse(
|
|
3054
|
+
meta = JSON.parse(fs22.readFileSync(metaPath, "utf8"));
|
|
2747
3055
|
} catch {
|
|
2748
3056
|
}
|
|
2749
3057
|
}
|
|
@@ -2758,57 +3066,57 @@ function listTemplates(templateRoot) {
|
|
|
2758
3066
|
function validateTemplateLayout(templateDir, defaultModuleName) {
|
|
2759
3067
|
const required = [
|
|
2760
3068
|
"build-profile.json5",
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
3069
|
+
path22.join("AppScope", "app.json5"),
|
|
3070
|
+
path22.join(defaultModuleName, "src", "main", "module.json5"),
|
|
3071
|
+
path22.join(defaultModuleName, "oh-package.json5"),
|
|
2764
3072
|
"hvigorfile.ts"
|
|
2765
3073
|
];
|
|
2766
|
-
return required.filter((rel) => !
|
|
3074
|
+
return required.filter((rel) => !fs22.existsSync(path22.join(templateDir, rel)));
|
|
2767
3075
|
}
|
|
2768
3076
|
|
|
2769
3077
|
// src/project/createScaffold.ts
|
|
2770
|
-
var
|
|
2771
|
-
var
|
|
3078
|
+
var fs24 = __toESM(require("fs"), 1);
|
|
3079
|
+
var path23 = __toESM(require("path"), 1);
|
|
2772
3080
|
|
|
2773
3081
|
// src/project/jsonHelpers.ts
|
|
2774
|
-
var
|
|
3082
|
+
var fs23 = __toESM(require("fs"), 1);
|
|
2775
3083
|
var import_json54 = __toESM(require("json5"), 1);
|
|
2776
3084
|
function readJson5File(filePath) {
|
|
2777
|
-
return import_json54.default.parse(
|
|
3085
|
+
return import_json54.default.parse(fs23.readFileSync(filePath, "utf8"));
|
|
2778
3086
|
}
|
|
2779
3087
|
function writeJson5File(filePath, value) {
|
|
2780
|
-
|
|
3088
|
+
fs23.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
2781
3089
|
}
|
|
2782
3090
|
function readJsonFile(filePath) {
|
|
2783
|
-
return JSON.parse(
|
|
3091
|
+
return JSON.parse(fs23.readFileSync(filePath, "utf8"));
|
|
2784
3092
|
}
|
|
2785
3093
|
function writeJsonFile(filePath, value) {
|
|
2786
|
-
|
|
3094
|
+
fs23.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
2787
3095
|
}
|
|
2788
3096
|
|
|
2789
3097
|
// src/project/createScaffold.ts
|
|
2790
3098
|
var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
|
|
2791
3099
|
async function pathExists(p) {
|
|
2792
3100
|
try {
|
|
2793
|
-
await
|
|
3101
|
+
await fs24.promises.access(p);
|
|
2794
3102
|
return true;
|
|
2795
3103
|
} catch {
|
|
2796
3104
|
return false;
|
|
2797
3105
|
}
|
|
2798
3106
|
}
|
|
2799
3107
|
async function copyDirRecursive(srcDir, destDir) {
|
|
2800
|
-
await
|
|
2801
|
-
const entries = await
|
|
3108
|
+
await fs24.promises.mkdir(destDir, { recursive: true });
|
|
3109
|
+
const entries = await fs24.promises.readdir(srcDir, { withFileTypes: true });
|
|
2802
3110
|
for (const entry of entries) {
|
|
2803
|
-
const src =
|
|
2804
|
-
const dest =
|
|
3111
|
+
const src = path23.join(srcDir, entry.name);
|
|
3112
|
+
const dest = path23.join(destDir, entry.name);
|
|
2805
3113
|
if (entry.isDirectory()) {
|
|
2806
3114
|
await copyDirRecursive(src, dest);
|
|
2807
3115
|
} else if (entry.isSymbolicLink()) {
|
|
2808
3116
|
continue;
|
|
2809
3117
|
} else if (entry.isFile()) {
|
|
2810
3118
|
if (entry.name === "template.json") continue;
|
|
2811
|
-
await
|
|
3119
|
+
await fs24.promises.copyFile(src, dest);
|
|
2812
3120
|
}
|
|
2813
3121
|
}
|
|
2814
3122
|
}
|
|
@@ -2816,9 +3124,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
|
|
|
2816
3124
|
const stack = [projectDir];
|
|
2817
3125
|
while (stack.length > 0) {
|
|
2818
3126
|
const currentDir = stack.pop();
|
|
2819
|
-
const entries = await
|
|
3127
|
+
const entries = await fs24.promises.readdir(currentDir, { withFileTypes: true });
|
|
2820
3128
|
for (const entry of entries) {
|
|
2821
|
-
const fullPath =
|
|
3129
|
+
const fullPath = path23.join(currentDir, entry.name);
|
|
2822
3130
|
if (entry.isDirectory()) {
|
|
2823
3131
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
2824
3132
|
stack.push(fullPath);
|
|
@@ -2840,23 +3148,23 @@ function toJavaPropertiesPath(p) {
|
|
|
2840
3148
|
function createOrUpdateLocalProperties(projectDir, sdkDir) {
|
|
2841
3149
|
const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
|
|
2842
3150
|
`;
|
|
2843
|
-
|
|
3151
|
+
fs24.writeFileSync(path23.join(projectDir, "local.properties"), content, "utf8");
|
|
2844
3152
|
}
|
|
2845
3153
|
function renameIfExists(fromPath, toPath) {
|
|
2846
|
-
if (
|
|
2847
|
-
|
|
3154
|
+
if (fs24.existsSync(fromPath) && fromPath !== toPath) {
|
|
3155
|
+
fs24.renameSync(fromPath, toPath);
|
|
2848
3156
|
}
|
|
2849
3157
|
}
|
|
2850
3158
|
function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
2851
|
-
const appJsonPath =
|
|
2852
|
-
if (
|
|
3159
|
+
const appJsonPath = path23.join(projectDir, "AppScope", "app.json5");
|
|
3160
|
+
if (fs24.existsSync(appJsonPath)) {
|
|
2853
3161
|
const appJson = readJson5File(appJsonPath);
|
|
2854
3162
|
appJson.app = appJson.app ?? {};
|
|
2855
3163
|
appJson.app.bundleName = args.bundleName;
|
|
2856
3164
|
writeJson5File(appJsonPath, appJson);
|
|
2857
3165
|
}
|
|
2858
|
-
const stringsPath =
|
|
2859
|
-
if (
|
|
3166
|
+
const stringsPath = path23.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
|
|
3167
|
+
if (fs24.existsSync(stringsPath)) {
|
|
2860
3168
|
const strings = readJsonFile(stringsPath);
|
|
2861
3169
|
if (Array.isArray(strings.string)) {
|
|
2862
3170
|
const appName = strings.string.find((s) => s.name === "app_name");
|
|
@@ -2864,8 +3172,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
2864
3172
|
}
|
|
2865
3173
|
writeJsonFile(stringsPath, strings);
|
|
2866
3174
|
}
|
|
2867
|
-
const buildProfilePath =
|
|
2868
|
-
if (
|
|
3175
|
+
const buildProfilePath = path23.join(projectDir, "build-profile.json5");
|
|
3176
|
+
if (fs24.existsSync(buildProfilePath)) {
|
|
2869
3177
|
const buildProfile = readJson5File(buildProfilePath);
|
|
2870
3178
|
buildProfile.app = buildProfile.app ?? {};
|
|
2871
3179
|
if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
|
|
@@ -2878,23 +3186,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
2878
3186
|
}
|
|
2879
3187
|
writeJson5File(buildProfilePath, buildProfile);
|
|
2880
3188
|
}
|
|
2881
|
-
const moduleJsonPath =
|
|
2882
|
-
if (
|
|
3189
|
+
const moduleJsonPath = path23.join(projectDir, args.moduleName, "src", "main", "module.json5");
|
|
3190
|
+
if (fs24.existsSync(moduleJsonPath)) {
|
|
2883
3191
|
const moduleJson = readJson5File(moduleJsonPath);
|
|
2884
3192
|
moduleJson.module = moduleJson.module ?? {};
|
|
2885
3193
|
moduleJson.module.name = args.moduleName;
|
|
2886
3194
|
writeJson5File(moduleJsonPath, moduleJson);
|
|
2887
3195
|
}
|
|
2888
|
-
const moduleOhPackagePath =
|
|
2889
|
-
if (
|
|
3196
|
+
const moduleOhPackagePath = path23.join(projectDir, args.moduleName, "oh-package.json5");
|
|
3197
|
+
if (fs24.existsSync(moduleOhPackagePath)) {
|
|
2890
3198
|
const pkg = readJson5File(moduleOhPackagePath);
|
|
2891
3199
|
pkg.name = args.moduleName;
|
|
2892
3200
|
writeJson5File(moduleOhPackagePath, pkg);
|
|
2893
3201
|
}
|
|
2894
|
-
const vscodeDir =
|
|
2895
|
-
|
|
3202
|
+
const vscodeDir = path23.join(projectDir, ".vscode");
|
|
3203
|
+
fs24.mkdirSync(vscodeDir, { recursive: true });
|
|
2896
3204
|
const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
|
|
2897
|
-
writeJsonFile(
|
|
3205
|
+
writeJsonFile(path23.join(vscodeDir, "settings.json"), {
|
|
2898
3206
|
"oniro.hapPath": hapPath,
|
|
2899
3207
|
"files.associations": { "*.json5": "jsonc" }
|
|
2900
3208
|
});
|
|
@@ -2911,7 +3219,7 @@ async function createScaffold(opts) {
|
|
|
2911
3219
|
if (!opts.location || !await pathExists(opts.location)) {
|
|
2912
3220
|
throw new OniroError(`Location does not exist: ${opts.location}`);
|
|
2913
3221
|
}
|
|
2914
|
-
const templateDir =
|
|
3222
|
+
const templateDir = path23.join(opts.templateRoot, opts.templateId);
|
|
2915
3223
|
if (!await pathExists(templateDir)) {
|
|
2916
3224
|
throw new OniroError(`Template not found: ${templateDir}`);
|
|
2917
3225
|
}
|
|
@@ -2924,17 +3232,17 @@ async function createScaffold(opts) {
|
|
|
2924
3232
|
throw new OniroError(`Template '${opts.templateId}' is missing required files:
|
|
2925
3233
|
- ${missing.join("\n- ")}`);
|
|
2926
3234
|
}
|
|
2927
|
-
const projectDir =
|
|
3235
|
+
const projectDir = path23.join(opts.location, opts.projectName);
|
|
2928
3236
|
if (await pathExists(projectDir)) {
|
|
2929
3237
|
if (!opts.overwrite) {
|
|
2930
3238
|
throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
|
|
2931
3239
|
}
|
|
2932
|
-
await
|
|
3240
|
+
await fs24.promises.rm(projectDir, { recursive: true, force: true });
|
|
2933
3241
|
}
|
|
2934
3242
|
logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
|
|
2935
3243
|
await copyDirRecursive(templateDir, projectDir);
|
|
2936
3244
|
if (moduleName !== defaultModuleName) {
|
|
2937
|
-
renameIfExists(
|
|
3245
|
+
renameIfExists(path23.join(projectDir, defaultModuleName), path23.join(projectDir, moduleName));
|
|
2938
3246
|
}
|
|
2939
3247
|
updateTemplateConfigs(
|
|
2940
3248
|
projectDir,
|
|
@@ -2951,11 +3259,11 @@ async function createScaffold(opts) {
|
|
|
2951
3259
|
}
|
|
2952
3260
|
|
|
2953
3261
|
// src/project/listModules.ts
|
|
2954
|
-
var
|
|
2955
|
-
var
|
|
3262
|
+
var fs25 = __toESM(require("fs"), 1);
|
|
3263
|
+
var path24 = __toESM(require("path"), 1);
|
|
2956
3264
|
function listModules(opts) {
|
|
2957
|
-
const buildProfile =
|
|
2958
|
-
if (!
|
|
3265
|
+
const buildProfile = path24.join(opts.projectDir, "build-profile.json5");
|
|
3266
|
+
if (!fs25.existsSync(buildProfile)) {
|
|
2959
3267
|
throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
|
|
2960
3268
|
}
|
|
2961
3269
|
const parsed = readJson5File(buildProfile);
|
|
@@ -2967,12 +3275,12 @@ function listModules(opts) {
|
|
|
2967
3275
|
}
|
|
2968
3276
|
|
|
2969
3277
|
// src/project/abilities.ts
|
|
2970
|
-
var
|
|
2971
|
-
var
|
|
3278
|
+
var fs26 = __toESM(require("fs"), 1);
|
|
3279
|
+
var path25 = __toESM(require("path"), 1);
|
|
2972
3280
|
function listAbilities(opts) {
|
|
2973
3281
|
const moduleName = opts.moduleName ?? "entry";
|
|
2974
|
-
const moduleJsonPath =
|
|
2975
|
-
if (!
|
|
3282
|
+
const moduleJsonPath = path25.join(opts.projectDir, moduleName, "src", "main", "module.json5");
|
|
3283
|
+
if (!fs26.existsSync(moduleJsonPath)) {
|
|
2976
3284
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
2977
3285
|
}
|
|
2978
3286
|
const parsed = readJson5File(moduleJsonPath);
|
|
@@ -2980,12 +3288,12 @@ function listAbilities(opts) {
|
|
|
2980
3288
|
}
|
|
2981
3289
|
|
|
2982
3290
|
// src/project/prepareSigning.ts
|
|
2983
|
-
var
|
|
2984
|
-
var
|
|
3291
|
+
var fs27 = __toESM(require("fs"), 1);
|
|
3292
|
+
var path26 = __toESM(require("path"), 1);
|
|
2985
3293
|
function hasSigningArtifacts(dir) {
|
|
2986
|
-
if (!
|
|
2987
|
-
const buildProfile =
|
|
2988
|
-
if (!
|
|
3294
|
+
if (!fs27.existsSync(path26.join(dir, "signatures"))) return false;
|
|
3295
|
+
const buildProfile = path26.join(dir, "build-profile.json5");
|
|
3296
|
+
if (!fs27.existsSync(buildProfile)) return false;
|
|
2989
3297
|
try {
|
|
2990
3298
|
const parsed = readJson5File(buildProfile);
|
|
2991
3299
|
return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
|
|
@@ -3075,8 +3383,8 @@ async function diffHapAssets(opts) {
|
|
|
3075
3383
|
}
|
|
3076
3384
|
|
|
3077
3385
|
// src/install/apply.ts
|
|
3078
|
-
var
|
|
3079
|
-
var
|
|
3386
|
+
var fs28 = __toESM(require("fs"), 1);
|
|
3387
|
+
var path27 = __toESM(require("path"), 1);
|
|
3080
3388
|
function decideInstallMethod(s) {
|
|
3081
3389
|
if (!s.signInfoInconsistent) return "replace";
|
|
3082
3390
|
if (s.isSystemBundle && !s.allowUninstall) return "refuse";
|
|
@@ -3097,7 +3405,7 @@ async function pidOf(config, bundle, deviceSerial) {
|
|
|
3097
3405
|
async function resolveHapPath(opts) {
|
|
3098
3406
|
let hapPath = opts.hapPath;
|
|
3099
3407
|
if (hapPath) {
|
|
3100
|
-
if (!
|
|
3408
|
+
if (!path27.isAbsolute(hapPath) && opts.projectDir) hapPath = path27.join(opts.projectDir, hapPath);
|
|
3101
3409
|
} else {
|
|
3102
3410
|
if (!opts.projectDir) throw new OniroError("applyChanges requires hapPath or projectDir.");
|
|
3103
3411
|
const haps = await discoverHaps({ projectDir: opts.projectDir });
|
|
@@ -3116,7 +3424,7 @@ async function resolveHapPath(opts) {
|
|
|
3116
3424
|
hapPath = withSigned[0][1].signed[0];
|
|
3117
3425
|
}
|
|
3118
3426
|
}
|
|
3119
|
-
if (!
|
|
3427
|
+
if (!fs28.existsSync(hapPath)) throw new OniroError(`HAP not found at ${hapPath}.`);
|
|
3120
3428
|
return hapPath;
|
|
3121
3429
|
}
|
|
3122
3430
|
async function applyChanges(opts) {
|
|
@@ -3126,7 +3434,7 @@ async function applyChanges(opts) {
|
|
|
3126
3434
|
const allowUninstall = opts.allowUninstall ?? false;
|
|
3127
3435
|
const hapPath = await resolveHapPath(opts);
|
|
3128
3436
|
let assetsChanged = false;
|
|
3129
|
-
if (opts.installedHapPath &&
|
|
3437
|
+
if (opts.installedHapPath && fs28.existsSync(opts.installedHapPath)) {
|
|
3130
3438
|
try {
|
|
3131
3439
|
const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
|
|
3132
3440
|
assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
|
|
@@ -3168,7 +3476,7 @@ async function applyChanges(opts) {
|
|
|
3168
3476
|
}
|
|
3169
3477
|
|
|
3170
3478
|
// src/index.ts
|
|
3171
|
-
var VERSION = "0.
|
|
3479
|
+
var VERSION = "0.8.0";
|
|
3172
3480
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3173
3481
|
0 && (module.exports = {
|
|
3174
3482
|
ALL_SDKS,
|
|
@@ -3178,22 +3486,28 @@ var VERSION = "0.7.0";
|
|
|
3178
3486
|
ChecksumMismatchError,
|
|
3179
3487
|
CmdToolsNotInstalledError,
|
|
3180
3488
|
CommandFailedError,
|
|
3489
|
+
INSTALL_TMP_DIRNAME,
|
|
3490
|
+
InsufficientSpaceError,
|
|
3181
3491
|
OHOS_URL_BASE,
|
|
3182
3492
|
OniroError,
|
|
3183
3493
|
SdkNotInstalledError,
|
|
3494
|
+
TMP_DIR_HINT,
|
|
3184
3495
|
UnsupportedPlatformError,
|
|
3185
3496
|
VERSION,
|
|
3186
3497
|
applyChanges,
|
|
3187
3498
|
attemptHdcConnection,
|
|
3188
3499
|
buildGestureCommands,
|
|
3500
|
+
buildGestureUitestCommand,
|
|
3189
3501
|
buildHap,
|
|
3190
3502
|
buildHvigorwArgs,
|
|
3191
3503
|
buildInputCommand,
|
|
3192
3504
|
buildRawTouchCommand,
|
|
3193
3505
|
captureBurst,
|
|
3194
3506
|
consoleLogger,
|
|
3507
|
+
createInstallTempDir,
|
|
3195
3508
|
createMaterial,
|
|
3196
3509
|
createScaffold,
|
|
3510
|
+
createTempWorkDir,
|
|
3197
3511
|
decideInstallMethod,
|
|
3198
3512
|
decideReboot,
|
|
3199
3513
|
decryptPwd,
|
|
@@ -3214,14 +3528,17 @@ var VERSION = "0.7.0";
|
|
|
3214
3528
|
dumpScreen,
|
|
3215
3529
|
dumpWindow,
|
|
3216
3530
|
encryptPwd,
|
|
3531
|
+
ensureFreeSpace,
|
|
3217
3532
|
ensureOhModules,
|
|
3218
3533
|
ensureOk,
|
|
3534
|
+
ensureRemoteOk,
|
|
3219
3535
|
extractTarball,
|
|
3220
3536
|
extractZipWithProgress,
|
|
3221
3537
|
findAppProcessId,
|
|
3222
3538
|
findCmdToolsSourceDir,
|
|
3223
3539
|
findRunningProcess,
|
|
3224
3540
|
forceStop,
|
|
3541
|
+
formatBytes,
|
|
3225
3542
|
generateSigningConfigs,
|
|
3226
3543
|
getBundleName,
|
|
3227
3544
|
getCmdToolsBin,
|
|
@@ -3231,6 +3548,7 @@ var VERSION = "0.7.0";
|
|
|
3231
3548
|
getDeviceInfo,
|
|
3232
3549
|
getDisplaySize,
|
|
3233
3550
|
getEmulatorDir,
|
|
3551
|
+
getFreeSpaceBytes,
|
|
3234
3552
|
getHdcPath,
|
|
3235
3553
|
getHvigorwPath,
|
|
3236
3554
|
getInstalledSdks,
|
|
@@ -3248,6 +3566,8 @@ var VERSION = "0.7.0";
|
|
|
3248
3566
|
installEmulator,
|
|
3249
3567
|
isCmdToolsInstalled,
|
|
3250
3568
|
isEmulatorInstalled,
|
|
3569
|
+
isOutOfSpaceError,
|
|
3570
|
+
isRamBackedPath,
|
|
3251
3571
|
isValidBundleName,
|
|
3252
3572
|
isValidProjectName,
|
|
3253
3573
|
launchApp,
|
|
@@ -3265,6 +3585,8 @@ var VERSION = "0.7.0";
|
|
|
3265
3585
|
parseCodelinterFindings,
|
|
3266
3586
|
parseDeviceList,
|
|
3267
3587
|
parseHilogLine,
|
|
3588
|
+
parseMainAbilityFromBmDump,
|
|
3589
|
+
parseRemoteExit,
|
|
3268
3590
|
pickSigningKind,
|
|
3269
3591
|
prepareSigning,
|
|
3270
3592
|
pruneLayout,
|
|
@@ -3275,6 +3597,8 @@ var VERSION = "0.7.0";
|
|
|
3275
3597
|
removeCmdTools,
|
|
3276
3598
|
removeEmulator,
|
|
3277
3599
|
removeSdk,
|
|
3600
|
+
removeTempWorkDir,
|
|
3601
|
+
resolveTmpRoot,
|
|
3278
3602
|
runCodelinter,
|
|
3279
3603
|
runHvigorw,
|
|
3280
3604
|
runOhpm,
|
|
@@ -3287,11 +3611,13 @@ var VERSION = "0.7.0";
|
|
|
3287
3611
|
sendRawTouch,
|
|
3288
3612
|
setHilogLevel,
|
|
3289
3613
|
shell,
|
|
3614
|
+
shellChecked,
|
|
3290
3615
|
startEmulator,
|
|
3291
3616
|
staticConfig,
|
|
3292
3617
|
stopEmulator,
|
|
3293
3618
|
streamHilog,
|
|
3294
3619
|
takeScreenshot,
|
|
3620
|
+
toSpaceError,
|
|
3295
3621
|
uninstallApp,
|
|
3296
3622
|
validateTemplateLayout,
|
|
3297
3623
|
verifySha256,
|
|
@@ -3300,6 +3626,7 @@ var VERSION = "0.7.0";
|
|
|
3300
3626
|
waitForCondition,
|
|
3301
3627
|
waitForLog,
|
|
3302
3628
|
watchLog,
|
|
3629
|
+
waypointsToRawEvents,
|
|
3303
3630
|
writeJson5File,
|
|
3304
3631
|
writeJsonFile
|
|
3305
3632
|
});
|