@oniroproject/core 0.14.1 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.cjs +402 -172
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -13
- package/dist/index.d.ts +100 -13
- package/dist/index.js +393 -172
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -180,6 +180,7 @@ var ALL_SDKS = [
|
|
|
180
180
|
{ version: "7.0", api: "26", tarballStrip: { linuxWindows: 1, darwin: 3 }, archiveSuffix: "_20260829" }
|
|
181
181
|
];
|
|
182
182
|
var OHOS_URL_BASE = "https://repo.huaweicloud.com/openharmony/os";
|
|
183
|
+
var OHOS_DAILY_BUILDS_URL = "https://dcp.openharmony.cn/workbench/cicd/dailybuild/dailylist";
|
|
183
184
|
|
|
184
185
|
// src/sdk/platform.ts
|
|
185
186
|
import * as os2 from "os";
|
|
@@ -762,8 +763,17 @@ async function extractZipWithProgress(opts) {
|
|
|
762
763
|
if (inc > 0) progress.report({ message: "Extracting: 100%", increment: inc });
|
|
763
764
|
}
|
|
764
765
|
}
|
|
765
|
-
async function extractTarball(tarPath, dest, strip = 0) {
|
|
766
|
-
await tar.x({ file: tarPath, cwd: dest, strip });
|
|
766
|
+
async function extractTarball(tarPath, dest, strip = 0, filter) {
|
|
767
|
+
await tar.x({ file: tarPath, cwd: dest, strip, ...filter ? { filter: (p) => filter(p) } : {} });
|
|
768
|
+
}
|
|
769
|
+
async function readZipEntry(zipPath, match) {
|
|
770
|
+
const zip = new StreamZip.async({ file: zipPath });
|
|
771
|
+
try {
|
|
772
|
+
const entry = Object.values(await zip.entries()).find((e) => !e.isDirectory && match(e.name));
|
|
773
|
+
return entry ? await zip.entryData(entry) : void 0;
|
|
774
|
+
} finally {
|
|
775
|
+
await zip.close();
|
|
776
|
+
}
|
|
767
777
|
}
|
|
768
778
|
|
|
769
779
|
// src/sdk/list.ts
|
|
@@ -869,34 +879,7 @@ async function downloadAndInstallSdk(opts) {
|
|
|
869
879
|
`Expected folder '${osFolder}' not found in extracted SDK. Tarball layout may have changed.`
|
|
870
880
|
);
|
|
871
881
|
}
|
|
872
|
-
|
|
873
|
-
const componentsStart = 60;
|
|
874
|
-
const componentsBudget = 35;
|
|
875
|
-
const n = zipFiles.length;
|
|
876
|
-
if (n === 0) {
|
|
877
|
-
progress?.report({ message: "No SDK component ZIPs found.", increment: componentsBudget });
|
|
878
|
-
} else {
|
|
879
|
-
progress?.report({ message: "Extracting SDK components...", increment: 0 });
|
|
880
|
-
}
|
|
881
|
-
const base = n > 0 ? Math.floor(componentsBudget / n) : 0;
|
|
882
|
-
let rem = n > 0 ? componentsBudget % n : 0;
|
|
883
|
-
let cursor = componentsStart;
|
|
884
|
-
for (const zipFile of zipFiles) {
|
|
885
|
-
checkCancelled();
|
|
886
|
-
logger.info(`Extracting component ${zipFile}`);
|
|
887
|
-
const zipPath = path10.join(osContentPath, zipFile);
|
|
888
|
-
const thisBudget = base + (rem > 0 ? 1 : 0);
|
|
889
|
-
if (rem > 0) rem--;
|
|
890
|
-
await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });
|
|
891
|
-
cursor += thisBudget;
|
|
892
|
-
fs10.unlinkSync(zipPath);
|
|
893
|
-
}
|
|
894
|
-
progress?.report({ message: "Finalizing installation...", increment: 0 });
|
|
895
|
-
if (fs10.existsSync(sdkInstallDir)) {
|
|
896
|
-
fs10.rmSync(sdkInstallDir, { recursive: true, force: true });
|
|
897
|
-
}
|
|
898
|
-
movePath(osContentPath, sdkInstallDir);
|
|
899
|
-
progress?.report({ message: "Finalizing installation...", increment: 3 });
|
|
882
|
+
await installComponents({ osContentPath, sdkInstallDir, progress, logger, start: 60, range: 35, checkCancelled });
|
|
900
883
|
progress?.report({ message: "Cleaning up...", increment: 0 });
|
|
901
884
|
removeTempWorkDir(tmpDir, tmpRoot);
|
|
902
885
|
progress?.report({ message: "Cleaning up...", increment: 2 });
|
|
@@ -907,6 +890,115 @@ async function downloadAndInstallSdk(opts) {
|
|
|
907
890
|
throw wrapped;
|
|
908
891
|
}
|
|
909
892
|
}
|
|
893
|
+
async function installComponents(opts) {
|
|
894
|
+
const { osContentPath, sdkInstallDir, progress, logger, checkCancelled } = opts;
|
|
895
|
+
const zipFiles = fs10.readdirSync(osContentPath).filter((n2) => n2.endsWith(".zip"));
|
|
896
|
+
const n = zipFiles.length;
|
|
897
|
+
if (n === 0) {
|
|
898
|
+
progress?.report({ message: "No SDK component ZIPs found.", increment: opts.range });
|
|
899
|
+
} else {
|
|
900
|
+
progress?.report({ message: "Extracting SDK components...", increment: 0 });
|
|
901
|
+
}
|
|
902
|
+
const base = n > 0 ? Math.floor(opts.range / n) : 0;
|
|
903
|
+
let rem = n > 0 ? opts.range % n : 0;
|
|
904
|
+
let cursor = opts.start;
|
|
905
|
+
for (const zipFile of zipFiles) {
|
|
906
|
+
checkCancelled();
|
|
907
|
+
logger.info(`Extracting component ${zipFile}`);
|
|
908
|
+
const zipPath = path10.join(osContentPath, zipFile);
|
|
909
|
+
const thisBudget = base + (rem > 0 ? 1 : 0);
|
|
910
|
+
if (rem > 0) rem--;
|
|
911
|
+
await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });
|
|
912
|
+
cursor += thisBudget;
|
|
913
|
+
fs10.unlinkSync(zipPath);
|
|
914
|
+
}
|
|
915
|
+
progress?.report({ message: "Finalizing installation...", increment: 0 });
|
|
916
|
+
if (fs10.existsSync(sdkInstallDir)) {
|
|
917
|
+
fs10.rmSync(sdkInstallDir, { recursive: true, force: true });
|
|
918
|
+
}
|
|
919
|
+
movePath(osContentPath, sdkInstallDir);
|
|
920
|
+
progress?.report({ message: "Finalizing installation...", increment: 3 });
|
|
921
|
+
}
|
|
922
|
+
async function installSdkFromArchive(opts) {
|
|
923
|
+
const { config, archivePath, progress, abortSignal } = opts;
|
|
924
|
+
const logger = opts.logger ?? noopLogger;
|
|
925
|
+
if (!fs10.statSync(archivePath, { throwIfNoEntry: false })?.isFile()) {
|
|
926
|
+
throw new OniroError(`SDK archive not found: ${archivePath}`);
|
|
927
|
+
}
|
|
928
|
+
const osFolder = getOsFolder();
|
|
929
|
+
const what = `the SDK install from '${path10.basename(archivePath)}'`;
|
|
930
|
+
const sdkRoot = getSdkRootDir(config);
|
|
931
|
+
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
932
|
+
config,
|
|
933
|
+
override: opts.tmpDir,
|
|
934
|
+
installRoot: sdkRoot,
|
|
935
|
+
prefix: "oniro-sdk-",
|
|
936
|
+
logger
|
|
937
|
+
});
|
|
938
|
+
const extractDir = path10.join(tmpDir, "extract");
|
|
939
|
+
fs10.mkdirSync(extractDir);
|
|
940
|
+
const checkCancelled = () => {
|
|
941
|
+
if (abortSignal?.aborted) throw new CancelledError();
|
|
942
|
+
};
|
|
943
|
+
try {
|
|
944
|
+
progress?.report({ message: "Extracting SDK archive (this may take a while)...", increment: 0 });
|
|
945
|
+
await extractTarball(archivePath, extractDir, 0, (p) => p.split("/").includes(osFolder));
|
|
946
|
+
progress?.report({ message: "Extracting SDK archive (this may take a while)...", increment: 40 });
|
|
947
|
+
checkCancelled();
|
|
948
|
+
const osContentPath = findSdkOsDir(extractDir, osFolder);
|
|
949
|
+
if (!osContentPath) {
|
|
950
|
+
throw new OniroError(
|
|
951
|
+
`No '${osFolder}' SDK components (a '${osFolder}' folder of ZIPs) found in ${archivePath}. Is it an OpenHarmony SDK archive for this OS?`
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
const { api, version } = await readSdkComponentsMeta(osContentPath);
|
|
955
|
+
const sdkInstallDir = path10.join(sdkRoot, osFolder, api);
|
|
956
|
+
if (fs10.existsSync(sdkInstallDir) && !opts.force) {
|
|
957
|
+
throw new OniroError(
|
|
958
|
+
`An SDK for api ${api} is already installed at ${sdkInstallDir}; pass --force to replace it with this archive, or set ONIRO_SDK_ROOT_DIR to install it in a separate SDK root.`
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
fs10.mkdirSync(path10.dirname(sdkInstallDir), { recursive: true });
|
|
962
|
+
await installComponents({ osContentPath, sdkInstallDir, progress, logger, start: 40, range: 55, checkCancelled });
|
|
963
|
+
progress?.report({ message: "Cleaning up...", increment: 0 });
|
|
964
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
965
|
+
progress?.report({ message: "Cleaning up...", increment: 2 });
|
|
966
|
+
return { api, version, dir: sdkInstallDir };
|
|
967
|
+
} catch (err) {
|
|
968
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
969
|
+
throw toSpaceError(err, tmpRoot, what);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
function findSdkOsDir(root, osFolder, maxDepth = 4) {
|
|
973
|
+
let level = [root];
|
|
974
|
+
for (let depth = 0; depth < maxDepth && level.length > 0; depth++) {
|
|
975
|
+
const next = [];
|
|
976
|
+
for (const dir of level) {
|
|
977
|
+
for (const entry of fs10.readdirSync(dir, { withFileTypes: true })) {
|
|
978
|
+
if (!entry.isDirectory()) continue;
|
|
979
|
+
const p = path10.join(dir, entry.name);
|
|
980
|
+
if (entry.name === osFolder && fs10.readdirSync(p).some((n) => n.endsWith(".zip"))) return p;
|
|
981
|
+
next.push(p);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
level = next;
|
|
985
|
+
}
|
|
986
|
+
return void 0;
|
|
987
|
+
}
|
|
988
|
+
async function readSdkComponentsMeta(dir) {
|
|
989
|
+
const zips = fs10.readdirSync(dir).filter((n) => n.endsWith(".zip")).sort((a, b) => Number(b.startsWith("ets-")) - Number(a.startsWith("ets-")));
|
|
990
|
+
for (const name of zips) {
|
|
991
|
+
const data = await readZipEntry(path10.join(dir, name), (e) => /^[^/]+\/oh-uni-package\.json$/.test(e));
|
|
992
|
+
if (!data) continue;
|
|
993
|
+
try {
|
|
994
|
+
const pkg = JSON.parse(data.toString("utf8"));
|
|
995
|
+
const api = String(pkg.apiVersion ?? "");
|
|
996
|
+
if (/^\d+$/.test(api)) return { api, version: String(pkg.version ?? "") };
|
|
997
|
+
} catch {
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
throw new OniroError("No SDK component in the archive declares a numeric apiVersion (oh-uni-package.json).");
|
|
1001
|
+
}
|
|
910
1002
|
|
|
911
1003
|
// src/cmdTools/install.ts
|
|
912
1004
|
import * as fs11 from "fs";
|
|
@@ -1998,12 +2090,13 @@ async function listDevices(config, opts = {}) {
|
|
|
1998
2090
|
});
|
|
1999
2091
|
return parseDeviceList(res.stdout);
|
|
2000
2092
|
}
|
|
2093
|
+
function isUsableDevice(device) {
|
|
2094
|
+
return device.status === "Connected" || device.status === "Unknown";
|
|
2095
|
+
}
|
|
2001
2096
|
async function selectDevice(config, serial, opts = {}) {
|
|
2002
2097
|
const resolved = resolveDeviceSerial(serial);
|
|
2003
2098
|
if (resolved) return resolved;
|
|
2004
|
-
const usable = (await listDevices(config, opts)).filter(
|
|
2005
|
-
(d) => d.status === "Connected" || d.status === "Unknown"
|
|
2006
|
-
);
|
|
2099
|
+
const usable = (await listDevices(config, opts)).filter(isUsableDevice);
|
|
2007
2100
|
if (usable.length === 1) return usable[0].serial;
|
|
2008
2101
|
if (usable.length === 0) {
|
|
2009
2102
|
throw new OniroError("No connected device found. Connect a device/emulator or set ONIRO_DEVICE_SERIAL.");
|
|
@@ -2194,9 +2287,13 @@ function moduleOfHap(hapFileName) {
|
|
|
2194
2287
|
const dash = hapFileName.indexOf("-");
|
|
2195
2288
|
return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
|
|
2196
2289
|
}
|
|
2290
|
+
function isAppProjectRoot(dir) {
|
|
2291
|
+
return fs17.existsSync(path18.join(dir, "AppScope", "app.json5"));
|
|
2292
|
+
}
|
|
2197
2293
|
async function discoverHaps(opts) {
|
|
2198
2294
|
const { projectDir } = opts;
|
|
2199
2295
|
const maxDepth = opts.maxDepth ?? 8;
|
|
2296
|
+
const skipNestedProjects = isAppProjectRoot(projectDir);
|
|
2200
2297
|
const result = {};
|
|
2201
2298
|
const walk = async (dir, depth) => {
|
|
2202
2299
|
if (depth > maxDepth) return;
|
|
@@ -2205,6 +2302,7 @@ async function discoverHaps(opts) {
|
|
|
2205
2302
|
const full = path18.join(dir, e.name);
|
|
2206
2303
|
if (e.isDirectory()) {
|
|
2207
2304
|
if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
|
|
2305
|
+
if (skipNestedProjects && isAppProjectRoot(full)) continue;
|
|
2208
2306
|
await walk(full, depth + 1);
|
|
2209
2307
|
} else if (e.isFile() && e.name.endsWith(".hap")) {
|
|
2210
2308
|
const moduleName = moduleOfHap(e.name);
|
|
@@ -3396,6 +3494,54 @@ async function resolveProcessId(config, bundle, deviceSerial) {
|
|
|
3396
3494
|
const proc = await findRunningProcess({ config, bundle, deviceSerial });
|
|
3397
3495
|
return proc?.pid;
|
|
3398
3496
|
}
|
|
3497
|
+
async function readDeviceClock(config, deviceSerial) {
|
|
3498
|
+
try {
|
|
3499
|
+
const res = await shell({ config, command: "date +%Y-%m-%dT%H:%M:%S", deviceSerial, timeoutMs: 1e4 });
|
|
3500
|
+
const m = res.code === 0 ? /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/.exec(res.stdout) : null;
|
|
3501
|
+
if (!m) return null;
|
|
3502
|
+
const [year, month, day, hour, minute, second] = m.slice(1).map(Number);
|
|
3503
|
+
return Date.UTC(year, month - 1, day, hour, minute, second);
|
|
3504
|
+
} catch {
|
|
3505
|
+
return null;
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
function hilogTimeMs(time, referenceMs) {
|
|
3509
|
+
const m = /^(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})\.(\d{3})$/.exec(time);
|
|
3510
|
+
if (!m) return null;
|
|
3511
|
+
const [month, day, hour, minute, second, ms] = m.slice(1).map(Number);
|
|
3512
|
+
const year = new Date(referenceMs).getUTCFullYear();
|
|
3513
|
+
let best = null;
|
|
3514
|
+
for (const y of [year - 1, year, year + 1]) {
|
|
3515
|
+
const t = Date.UTC(y, month - 1, day, hour, minute, second, ms);
|
|
3516
|
+
if (best === null || Math.abs(t - referenceMs) < Math.abs(best - referenceMs)) best = t;
|
|
3517
|
+
}
|
|
3518
|
+
return best;
|
|
3519
|
+
}
|
|
3520
|
+
async function recentEntryFilter(opts) {
|
|
3521
|
+
const passAll = { test: () => true, afterReconnect: async () => {
|
|
3522
|
+
} };
|
|
3523
|
+
const lookbackMs = opts.lookbackMs ?? 0;
|
|
3524
|
+
if (lookbackMs === Infinity) return passAll;
|
|
3525
|
+
const startedAt = Date.now();
|
|
3526
|
+
const now = await readDeviceClock(opts.config, opts.deviceSerial);
|
|
3527
|
+
if (now === null) {
|
|
3528
|
+
opts.logger.warn("Could not read the device clock, so lines already in the log buffer can match too.");
|
|
3529
|
+
return passAll;
|
|
3530
|
+
}
|
|
3531
|
+
let since = now - (Date.now() - startedAt) - lookbackMs;
|
|
3532
|
+
return {
|
|
3533
|
+
test: (entry) => {
|
|
3534
|
+
if (since === null) return true;
|
|
3535
|
+
const t = hilogTimeMs(entry.time, now);
|
|
3536
|
+
return t === null || t >= since;
|
|
3537
|
+
},
|
|
3538
|
+
afterReconnect: async () => {
|
|
3539
|
+
if (since === null) return;
|
|
3540
|
+
const later = await readDeviceClock(opts.config, opts.deviceSerial);
|
|
3541
|
+
if (later !== null && later < since) since = null;
|
|
3542
|
+
}
|
|
3543
|
+
};
|
|
3544
|
+
}
|
|
3399
3545
|
function waitForLog(opts) {
|
|
3400
3546
|
return new Promise((resolve7, reject) => {
|
|
3401
3547
|
const deadline = Date.now() + opts.timeoutMs;
|
|
@@ -3403,6 +3549,8 @@ function waitForLog(opts) {
|
|
|
3403
3549
|
let child = null;
|
|
3404
3550
|
let reconnectTimer;
|
|
3405
3551
|
let buf = "";
|
|
3552
|
+
let recent = { test: () => true, afterReconnect: async () => {
|
|
3553
|
+
} };
|
|
3406
3554
|
const cleanup = () => {
|
|
3407
3555
|
clearTimeout(timer);
|
|
3408
3556
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
@@ -3443,7 +3591,7 @@ function waitForLog(opts) {
|
|
|
3443
3591
|
buf = lines.pop() ?? "";
|
|
3444
3592
|
for (const line of lines) {
|
|
3445
3593
|
const entry = parseHilogLine(line);
|
|
3446
|
-
if (entry && opts.pattern.test(entryText(entry))) {
|
|
3594
|
+
if (entry && recent.test(entry) && opts.pattern.test(entryText(entry))) {
|
|
3447
3595
|
finish(entry);
|
|
3448
3596
|
return;
|
|
3449
3597
|
}
|
|
@@ -3453,13 +3601,21 @@ function waitForLog(opts) {
|
|
|
3453
3601
|
if (settled || child !== stream) return;
|
|
3454
3602
|
child = null;
|
|
3455
3603
|
if (Date.now() < deadline) {
|
|
3456
|
-
reconnectTimer = setTimeout(() => void
|
|
3604
|
+
reconnectTimer = setTimeout(() => void recent.afterReconnect().then(spawnStream).catch(failWith), 1e3);
|
|
3457
3605
|
}
|
|
3458
3606
|
};
|
|
3459
3607
|
stream.once("close", onEnd);
|
|
3460
3608
|
stream.once("error", onEnd);
|
|
3461
3609
|
};
|
|
3462
|
-
void
|
|
3610
|
+
void (async () => {
|
|
3611
|
+
recent = await recentEntryFilter({
|
|
3612
|
+
config: opts.config,
|
|
3613
|
+
deviceSerial: opts.deviceSerial,
|
|
3614
|
+
lookbackMs: opts.lookbackMs,
|
|
3615
|
+
logger: opts.logger ?? noopLogger
|
|
3616
|
+
});
|
|
3617
|
+
await spawnStream();
|
|
3618
|
+
})().catch(failWith);
|
|
3463
3619
|
});
|
|
3464
3620
|
}
|
|
3465
3621
|
function watchLog(opts) {
|
|
@@ -3468,6 +3624,8 @@ function watchLog(opts) {
|
|
|
3468
3624
|
let settled = false;
|
|
3469
3625
|
let child = null;
|
|
3470
3626
|
let buf = "";
|
|
3627
|
+
let recent = { test: () => true, afterReconnect: async () => {
|
|
3628
|
+
} };
|
|
3471
3629
|
const cleanup = () => {
|
|
3472
3630
|
clearTimeout(timer);
|
|
3473
3631
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
@@ -3491,6 +3649,13 @@ function watchLog(opts) {
|
|
|
3491
3649
|
const timer = setTimeout(done, opts.durationMs);
|
|
3492
3650
|
opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
3493
3651
|
void (async () => {
|
|
3652
|
+
recent = await recentEntryFilter({
|
|
3653
|
+
config: opts.config,
|
|
3654
|
+
deviceSerial: opts.deviceSerial,
|
|
3655
|
+
lookbackMs: opts.lookbackMs,
|
|
3656
|
+
logger: opts.logger ?? noopLogger
|
|
3657
|
+
});
|
|
3658
|
+
if (settled) return;
|
|
3494
3659
|
const processId = await resolveProcessId(opts.config, opts.bundle, opts.deviceSerial);
|
|
3495
3660
|
if (settled) return;
|
|
3496
3661
|
const stream = streamHilog({ config: opts.config, processId, domain: opts.domain, deviceSerial: opts.deviceSerial });
|
|
@@ -3501,7 +3666,7 @@ function watchLog(opts) {
|
|
|
3501
3666
|
buf = lines.pop() ?? "";
|
|
3502
3667
|
for (const line of lines) {
|
|
3503
3668
|
const entry = parseHilogLine(line);
|
|
3504
|
-
if (entry && opts.pattern.test(entryText(entry))) matches.push(entry);
|
|
3669
|
+
if (entry && recent.test(entry) && opts.pattern.test(entryText(entry))) matches.push(entry);
|
|
3505
3670
|
}
|
|
3506
3671
|
});
|
|
3507
3672
|
})().catch((err) => {
|
|
@@ -3786,6 +3951,8 @@ async function ensureOhModules(opts) {
|
|
|
3786
3951
|
}
|
|
3787
3952
|
|
|
3788
3953
|
// src/build/codelinter.ts
|
|
3954
|
+
import * as fs26 from "fs";
|
|
3955
|
+
import * as path26 from "path";
|
|
3789
3956
|
var FINDING_RE = /^(.*?):(\d+):(?:(\d+):)?\s*(error|warning|warn|suggestion|info)\b[:\s-]*(.*)$/i;
|
|
3790
3957
|
var TRAILING_CODE_RE = /[([]([\w@/.\-]+)[)\]]\s*$/;
|
|
3791
3958
|
var FILE_HEADER_RE = /^(.+\.\w+)\((\d+)\)$/;
|
|
@@ -3872,6 +4039,16 @@ function parseCodelinterReport(output) {
|
|
|
3872
4039
|
function parseCodelinterFindings(output) {
|
|
3873
4040
|
return parseCodelinterReport(output).findings;
|
|
3874
4041
|
}
|
|
4042
|
+
var PROJECT_ROOT_FILES = [
|
|
4043
|
+
["build-profile.json5"],
|
|
4044
|
+
["hvigorfile.ts", "hvigorfile.js"],
|
|
4045
|
+
[path26.join("hvigor", "hvigor-config.json5")]
|
|
4046
|
+
];
|
|
4047
|
+
function missingProjectRootFiles(projectDir) {
|
|
4048
|
+
return PROJECT_ROOT_FILES.filter((names) => !names.some((f) => fs26.existsSync(path26.join(projectDir, f)))).map(
|
|
4049
|
+
(names) => names[0]
|
|
4050
|
+
);
|
|
4051
|
+
}
|
|
3875
4052
|
async function runCodelinter(opts) {
|
|
3876
4053
|
const res = await runProcess({
|
|
3877
4054
|
command: getCmdToolsBin(opts.config, "codelinter"),
|
|
@@ -3889,7 +4066,7 @@ async function runCodelinter(opts) {
|
|
|
3889
4066
|
var DIAGNOSIS_OUTPUT_LIMIT = 2e6;
|
|
3890
4067
|
function diagnoseBuildFailure(output) {
|
|
3891
4068
|
if (/is not exported from Kit|has no exported member .*@systemapi/i.test(output)) {
|
|
3892
|
-
return
|
|
4069
|
+
return `The project calls system APIs (\`@systemapi\`), which the public SDK leaves out. Build against the full OpenHarmony SDK: download an \`ohos-sdk-full\` archive from ${OHOS_DAILY_BUILDS_URL} and install it with \`oniro-app sdk install --from-archive <archive> --force\` (this replaces the public SDK of that API level; set ONIRO_SDK_ROOT_DIR to keep the two apart). Installing such an app also needs privileged signing (\`oniro-app sign --apl system_core --acls \u2026 --app-privilege-capabilities \u2026\`).`;
|
|
3893
4070
|
}
|
|
3894
4071
|
if (/00308018|SDK path does not exist|SDK license agreement is not accepted/i.test(output)) {
|
|
3895
4072
|
return "hvigor cannot find the SDK the project compiles against: check `oniro-app sdk list` against compileSdkVersion.";
|
|
@@ -3961,21 +4138,21 @@ function isValidBundleName(bundleName) {
|
|
|
3961
4138
|
}
|
|
3962
4139
|
|
|
3963
4140
|
// src/project/templates.ts
|
|
3964
|
-
import * as
|
|
3965
|
-
import * as
|
|
4141
|
+
import * as fs27 from "fs";
|
|
4142
|
+
import * as path27 from "path";
|
|
3966
4143
|
function toHumanTemplateName(folderName) {
|
|
3967
4144
|
return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
3968
4145
|
}
|
|
3969
4146
|
function listTemplates(templateRoot) {
|
|
3970
|
-
if (!
|
|
3971
|
-
const entries =
|
|
4147
|
+
if (!fs27.existsSync(templateRoot)) return [];
|
|
4148
|
+
const entries = fs27.readdirSync(templateRoot, { withFileTypes: true });
|
|
3972
4149
|
return entries.filter((e) => e.isDirectory()).map((e) => {
|
|
3973
|
-
const dir =
|
|
3974
|
-
const metaPath =
|
|
4150
|
+
const dir = path27.join(templateRoot, e.name);
|
|
4151
|
+
const metaPath = path27.join(dir, "template.json");
|
|
3975
4152
|
let meta = {};
|
|
3976
|
-
if (
|
|
4153
|
+
if (fs27.existsSync(metaPath)) {
|
|
3977
4154
|
try {
|
|
3978
|
-
meta = JSON.parse(
|
|
4155
|
+
meta = JSON.parse(fs27.readFileSync(metaPath, "utf8"));
|
|
3979
4156
|
} catch {
|
|
3980
4157
|
}
|
|
3981
4158
|
}
|
|
@@ -3990,57 +4167,57 @@ function listTemplates(templateRoot) {
|
|
|
3990
4167
|
function validateTemplateLayout(templateDir, defaultModuleName) {
|
|
3991
4168
|
const required = [
|
|
3992
4169
|
"build-profile.json5",
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
4170
|
+
path27.join("AppScope", "app.json5"),
|
|
4171
|
+
path27.join(defaultModuleName, "src", "main", "module.json5"),
|
|
4172
|
+
path27.join(defaultModuleName, "oh-package.json5"),
|
|
3996
4173
|
"hvigorfile.ts"
|
|
3997
4174
|
];
|
|
3998
|
-
return required.filter((rel) => !
|
|
4175
|
+
return required.filter((rel) => !fs27.existsSync(path27.join(templateDir, rel)));
|
|
3999
4176
|
}
|
|
4000
4177
|
|
|
4001
4178
|
// src/project/createScaffold.ts
|
|
4002
|
-
import * as
|
|
4003
|
-
import * as
|
|
4179
|
+
import * as fs29 from "fs";
|
|
4180
|
+
import * as path28 from "path";
|
|
4004
4181
|
|
|
4005
4182
|
// src/project/jsonHelpers.ts
|
|
4006
|
-
import * as
|
|
4183
|
+
import * as fs28 from "fs";
|
|
4007
4184
|
import JSON55 from "json5";
|
|
4008
4185
|
function readJson5File(filePath) {
|
|
4009
|
-
return JSON55.parse(
|
|
4186
|
+
return JSON55.parse(fs28.readFileSync(filePath, "utf8"));
|
|
4010
4187
|
}
|
|
4011
4188
|
function writeJson5File(filePath, value) {
|
|
4012
|
-
|
|
4189
|
+
fs28.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
4013
4190
|
}
|
|
4014
4191
|
function readJsonFile(filePath) {
|
|
4015
|
-
return JSON.parse(
|
|
4192
|
+
return JSON.parse(fs28.readFileSync(filePath, "utf8"));
|
|
4016
4193
|
}
|
|
4017
4194
|
function writeJsonFile(filePath, value) {
|
|
4018
|
-
|
|
4195
|
+
fs28.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
4019
4196
|
}
|
|
4020
4197
|
|
|
4021
4198
|
// src/project/createScaffold.ts
|
|
4022
4199
|
var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
|
|
4023
4200
|
async function pathExists(p) {
|
|
4024
4201
|
try {
|
|
4025
|
-
await
|
|
4202
|
+
await fs29.promises.access(p);
|
|
4026
4203
|
return true;
|
|
4027
4204
|
} catch {
|
|
4028
4205
|
return false;
|
|
4029
4206
|
}
|
|
4030
4207
|
}
|
|
4031
4208
|
async function copyDirRecursive(srcDir, destDir) {
|
|
4032
|
-
await
|
|
4033
|
-
const entries = await
|
|
4209
|
+
await fs29.promises.mkdir(destDir, { recursive: true });
|
|
4210
|
+
const entries = await fs29.promises.readdir(srcDir, { withFileTypes: true });
|
|
4034
4211
|
for (const entry of entries) {
|
|
4035
|
-
const src =
|
|
4036
|
-
const dest =
|
|
4212
|
+
const src = path28.join(srcDir, entry.name);
|
|
4213
|
+
const dest = path28.join(destDir, entry.name);
|
|
4037
4214
|
if (entry.isDirectory()) {
|
|
4038
4215
|
await copyDirRecursive(src, dest);
|
|
4039
4216
|
} else if (entry.isSymbolicLink()) {
|
|
4040
4217
|
continue;
|
|
4041
4218
|
} else if (entry.isFile()) {
|
|
4042
4219
|
if (entry.name === "template.json") continue;
|
|
4043
|
-
await
|
|
4220
|
+
await fs29.promises.copyFile(src, dest);
|
|
4044
4221
|
}
|
|
4045
4222
|
}
|
|
4046
4223
|
}
|
|
@@ -4048,9 +4225,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
|
|
|
4048
4225
|
const stack = [projectDir];
|
|
4049
4226
|
while (stack.length > 0) {
|
|
4050
4227
|
const currentDir = stack.pop();
|
|
4051
|
-
const entries = await
|
|
4228
|
+
const entries = await fs29.promises.readdir(currentDir, { withFileTypes: true });
|
|
4052
4229
|
for (const entry of entries) {
|
|
4053
|
-
const fullPath =
|
|
4230
|
+
const fullPath = path28.join(currentDir, entry.name);
|
|
4054
4231
|
if (entry.isDirectory()) {
|
|
4055
4232
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
4056
4233
|
stack.push(fullPath);
|
|
@@ -4072,23 +4249,23 @@ function toJavaPropertiesPath(p) {
|
|
|
4072
4249
|
function createOrUpdateLocalProperties(projectDir, sdkDir) {
|
|
4073
4250
|
const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
|
|
4074
4251
|
`;
|
|
4075
|
-
|
|
4252
|
+
fs29.writeFileSync(path28.join(projectDir, "local.properties"), content, "utf8");
|
|
4076
4253
|
}
|
|
4077
4254
|
function renameIfExists(fromPath, toPath) {
|
|
4078
|
-
if (
|
|
4079
|
-
|
|
4255
|
+
if (fs29.existsSync(fromPath) && fromPath !== toPath) {
|
|
4256
|
+
fs29.renameSync(fromPath, toPath);
|
|
4080
4257
|
}
|
|
4081
4258
|
}
|
|
4082
4259
|
function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
4083
|
-
const appJsonPath =
|
|
4084
|
-
if (
|
|
4260
|
+
const appJsonPath = path28.join(projectDir, "AppScope", "app.json5");
|
|
4261
|
+
if (fs29.existsSync(appJsonPath)) {
|
|
4085
4262
|
const appJson = readJson5File(appJsonPath);
|
|
4086
4263
|
appJson.app = appJson.app ?? {};
|
|
4087
4264
|
appJson.app.bundleName = args.bundleName;
|
|
4088
4265
|
writeJson5File(appJsonPath, appJson);
|
|
4089
4266
|
}
|
|
4090
|
-
const stringsPath =
|
|
4091
|
-
if (
|
|
4267
|
+
const stringsPath = path28.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
|
|
4268
|
+
if (fs29.existsSync(stringsPath)) {
|
|
4092
4269
|
const strings = readJsonFile(stringsPath);
|
|
4093
4270
|
if (Array.isArray(strings.string)) {
|
|
4094
4271
|
const appName = strings.string.find((s) => s.name === "app_name");
|
|
@@ -4096,8 +4273,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
4096
4273
|
}
|
|
4097
4274
|
writeJsonFile(stringsPath, strings);
|
|
4098
4275
|
}
|
|
4099
|
-
const buildProfilePath =
|
|
4100
|
-
if (
|
|
4276
|
+
const buildProfilePath = path28.join(projectDir, "build-profile.json5");
|
|
4277
|
+
if (fs29.existsSync(buildProfilePath)) {
|
|
4101
4278
|
const buildProfile = readJson5File(buildProfilePath);
|
|
4102
4279
|
buildProfile.app = buildProfile.app ?? {};
|
|
4103
4280
|
if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
|
|
@@ -4110,23 +4287,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
4110
4287
|
}
|
|
4111
4288
|
writeJson5File(buildProfilePath, buildProfile);
|
|
4112
4289
|
}
|
|
4113
|
-
const moduleJsonPath =
|
|
4114
|
-
if (
|
|
4290
|
+
const moduleJsonPath = path28.join(projectDir, args.moduleName, "src", "main", "module.json5");
|
|
4291
|
+
if (fs29.existsSync(moduleJsonPath)) {
|
|
4115
4292
|
const moduleJson = readJson5File(moduleJsonPath);
|
|
4116
4293
|
moduleJson.module = moduleJson.module ?? {};
|
|
4117
4294
|
moduleJson.module.name = args.moduleName;
|
|
4118
4295
|
writeJson5File(moduleJsonPath, moduleJson);
|
|
4119
4296
|
}
|
|
4120
|
-
const moduleOhPackagePath =
|
|
4121
|
-
if (
|
|
4297
|
+
const moduleOhPackagePath = path28.join(projectDir, args.moduleName, "oh-package.json5");
|
|
4298
|
+
if (fs29.existsSync(moduleOhPackagePath)) {
|
|
4122
4299
|
const pkg = readJson5File(moduleOhPackagePath);
|
|
4123
4300
|
pkg.name = args.moduleName;
|
|
4124
4301
|
writeJson5File(moduleOhPackagePath, pkg);
|
|
4125
4302
|
}
|
|
4126
|
-
const vscodeDir =
|
|
4127
|
-
|
|
4303
|
+
const vscodeDir = path28.join(projectDir, ".vscode");
|
|
4304
|
+
fs29.mkdirSync(vscodeDir, { recursive: true });
|
|
4128
4305
|
const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
|
|
4129
|
-
writeJsonFile(
|
|
4306
|
+
writeJsonFile(path28.join(vscodeDir, "settings.json"), {
|
|
4130
4307
|
"oniro.hapPath": hapPath,
|
|
4131
4308
|
"files.associations": { "*.json5": "jsonc" }
|
|
4132
4309
|
});
|
|
@@ -4143,7 +4320,7 @@ async function createScaffold(opts) {
|
|
|
4143
4320
|
if (!opts.location || !await pathExists(opts.location)) {
|
|
4144
4321
|
throw new OniroError(`Location does not exist: ${opts.location}`);
|
|
4145
4322
|
}
|
|
4146
|
-
const templateDir =
|
|
4323
|
+
const templateDir = path28.join(opts.templateRoot, opts.templateId);
|
|
4147
4324
|
if (!await pathExists(templateDir)) {
|
|
4148
4325
|
throw new OniroError(`Template not found: ${templateDir}`);
|
|
4149
4326
|
}
|
|
@@ -4178,17 +4355,17 @@ async function createScaffold(opts) {
|
|
|
4178
4355
|
}
|
|
4179
4356
|
}
|
|
4180
4357
|
}
|
|
4181
|
-
const projectDir =
|
|
4358
|
+
const projectDir = path28.join(opts.location, opts.projectName);
|
|
4182
4359
|
if (await pathExists(projectDir)) {
|
|
4183
4360
|
if (!opts.overwrite) {
|
|
4184
4361
|
throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
|
|
4185
4362
|
}
|
|
4186
|
-
await
|
|
4363
|
+
await fs29.promises.rm(projectDir, { recursive: true, force: true });
|
|
4187
4364
|
}
|
|
4188
4365
|
logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
|
|
4189
4366
|
await copyDirRecursive(templateDir, projectDir);
|
|
4190
4367
|
if (moduleName !== defaultModuleName) {
|
|
4191
|
-
renameIfExists(
|
|
4368
|
+
renameIfExists(path28.join(projectDir, defaultModuleName), path28.join(projectDir, moduleName));
|
|
4192
4369
|
}
|
|
4193
4370
|
updateTemplateConfigs(
|
|
4194
4371
|
projectDir,
|
|
@@ -4205,11 +4382,11 @@ async function createScaffold(opts) {
|
|
|
4205
4382
|
}
|
|
4206
4383
|
|
|
4207
4384
|
// src/project/listModules.ts
|
|
4208
|
-
import * as
|
|
4209
|
-
import * as
|
|
4385
|
+
import * as fs30 from "fs";
|
|
4386
|
+
import * as path29 from "path";
|
|
4210
4387
|
function listModules(opts) {
|
|
4211
|
-
const buildProfile =
|
|
4212
|
-
if (!
|
|
4388
|
+
const buildProfile = path29.join(opts.projectDir, "build-profile.json5");
|
|
4389
|
+
if (!fs30.existsSync(buildProfile)) {
|
|
4213
4390
|
throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
|
|
4214
4391
|
}
|
|
4215
4392
|
const parsed = readJson5File(buildProfile);
|
|
@@ -4221,12 +4398,12 @@ function listModules(opts) {
|
|
|
4221
4398
|
}
|
|
4222
4399
|
|
|
4223
4400
|
// src/project/abilities.ts
|
|
4224
|
-
import * as
|
|
4225
|
-
import * as
|
|
4401
|
+
import * as fs31 from "fs";
|
|
4402
|
+
import * as path30 from "path";
|
|
4226
4403
|
function listAbilities(opts) {
|
|
4227
4404
|
const moduleName = opts.moduleName ?? "entry";
|
|
4228
|
-
const moduleJsonPath =
|
|
4229
|
-
if (!
|
|
4405
|
+
const moduleJsonPath = path30.join(opts.projectDir, moduleName, "src", "main", "module.json5");
|
|
4406
|
+
if (!fs31.existsSync(moduleJsonPath)) {
|
|
4230
4407
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
4231
4408
|
}
|
|
4232
4409
|
const parsed = readJson5File(moduleJsonPath);
|
|
@@ -4234,12 +4411,12 @@ function listAbilities(opts) {
|
|
|
4234
4411
|
}
|
|
4235
4412
|
|
|
4236
4413
|
// src/project/prepareSigning.ts
|
|
4237
|
-
import * as
|
|
4238
|
-
import * as
|
|
4414
|
+
import * as fs32 from "fs";
|
|
4415
|
+
import * as path31 from "path";
|
|
4239
4416
|
function hasSigningArtifacts(dir) {
|
|
4240
|
-
if (!
|
|
4241
|
-
const buildProfile =
|
|
4242
|
-
if (!
|
|
4417
|
+
if (!fs32.existsSync(path31.join(dir, "signatures"))) return false;
|
|
4418
|
+
const buildProfile = path31.join(dir, "build-profile.json5");
|
|
4419
|
+
if (!fs32.existsSync(buildProfile)) return false;
|
|
4243
4420
|
try {
|
|
4244
4421
|
const parsed = readJson5File(buildProfile);
|
|
4245
4422
|
return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
|
|
@@ -4342,8 +4519,25 @@ async function diffHapAssets(opts) {
|
|
|
4342
4519
|
}
|
|
4343
4520
|
|
|
4344
4521
|
// src/install/apply.ts
|
|
4345
|
-
import * as
|
|
4346
|
-
import * as
|
|
4522
|
+
import * as fs33 from "fs";
|
|
4523
|
+
import * as path32 from "path";
|
|
4524
|
+
|
|
4525
|
+
// src/install/hapBundleName.ts
|
|
4526
|
+
function bundleNameFromHapConfig(text) {
|
|
4527
|
+
try {
|
|
4528
|
+
const parsed = JSON.parse(text.replace(/^/, ""));
|
|
4529
|
+
const name = parsed.app?.bundleName;
|
|
4530
|
+
return typeof name === "string" && name ? name : null;
|
|
4531
|
+
} catch {
|
|
4532
|
+
return null;
|
|
4533
|
+
}
|
|
4534
|
+
}
|
|
4535
|
+
async function readHapBundleName(hapPath) {
|
|
4536
|
+
const config = await readZipEntry(hapPath, (n) => n === "module.json") ?? await readZipEntry(hapPath, (n) => n === "config.json");
|
|
4537
|
+
return config ? bundleNameFromHapConfig(config.toString("utf8")) : null;
|
|
4538
|
+
}
|
|
4539
|
+
|
|
4540
|
+
// src/install/apply.ts
|
|
4347
4541
|
function decideInstallMethod(s) {
|
|
4348
4542
|
if (!s.signInfoInconsistent) return "replace";
|
|
4349
4543
|
if (s.isSystemBundle && !s.allowUninstall) return "refuse";
|
|
@@ -4364,7 +4558,7 @@ async function pidOf(config, bundle, deviceSerial) {
|
|
|
4364
4558
|
async function resolveHap(opts, logger) {
|
|
4365
4559
|
let hap;
|
|
4366
4560
|
if (opts.hapPath) {
|
|
4367
|
-
const hapPath = !
|
|
4561
|
+
const hapPath = !path32.isAbsolute(opts.hapPath) && opts.projectDir ? path32.join(opts.projectDir, opts.hapPath) : opts.hapPath;
|
|
4368
4562
|
hap = existingHapOrUnsigned(hapPath);
|
|
4369
4563
|
if (!hap) throw new OniroError(`HAP not found at ${hapPath}.`);
|
|
4370
4564
|
} else {
|
|
@@ -4373,7 +4567,7 @@ async function resolveHap(opts, logger) {
|
|
|
4373
4567
|
if (!picked) throw new OniroError(`No HAP found${opts.module ? ` for module ${opts.module}` : ""}. Build first.`);
|
|
4374
4568
|
hap = { path: picked.path, fallback: !picked.signed };
|
|
4375
4569
|
}
|
|
4376
|
-
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${
|
|
4570
|
+
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path32.basename(hap.path)}.`);
|
|
4377
4571
|
return hap;
|
|
4378
4572
|
}
|
|
4379
4573
|
async function applyChanges(opts) {
|
|
@@ -4383,9 +4577,18 @@ async function applyChanges(opts) {
|
|
|
4383
4577
|
const allowUninstall = opts.allowUninstall ?? false;
|
|
4384
4578
|
const hap = await resolveHap(opts, logger);
|
|
4385
4579
|
const hapPath = hap.path;
|
|
4580
|
+
const hapBundle = await readHapBundleName(hapPath).catch((err) => {
|
|
4581
|
+
logger.debug(`bundle name check skipped: ${err.message}`);
|
|
4582
|
+
return null;
|
|
4583
|
+
});
|
|
4584
|
+
if (hapBundle && hapBundle !== bundle) {
|
|
4585
|
+
throw new OniroError(
|
|
4586
|
+
`${path32.basename(hapPath)} (${hapPath}) is bundle ${hapBundle}, not ${bundle}, so installing it would not update ${bundle}. Choose the HAP explicitly, or name ${hapBundle} as the bundle if it is the app to update.`
|
|
4587
|
+
);
|
|
4588
|
+
}
|
|
4386
4589
|
logger.info(`installing ${hapPath}`);
|
|
4387
4590
|
let assetsChanged = false;
|
|
4388
|
-
if (opts.installedHapPath &&
|
|
4591
|
+
if (opts.installedHapPath && fs33.existsSync(opts.installedHapPath)) {
|
|
4389
4592
|
try {
|
|
4390
4593
|
const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
|
|
4391
4594
|
assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
|
|
@@ -4418,7 +4621,7 @@ async function applyChanges(opts) {
|
|
|
4418
4621
|
}
|
|
4419
4622
|
if (!await isBundleInstalled({ config, bundle, deviceSerial })) {
|
|
4420
4623
|
throw new OniroError(
|
|
4421
|
-
`hdc reported ${
|
|
4624
|
+
`hdc reported ${path32.basename(hapPath)} as installed, but bm dump does not list ${bundle}. Check that the HAP was built from this project (its bundleName must match).`
|
|
4422
4625
|
);
|
|
4423
4626
|
}
|
|
4424
4627
|
let postInstallPid = await pidOf(config, bundle, deviceSerial);
|
|
@@ -4495,9 +4698,9 @@ var AUTH_PATHS = {
|
|
|
4495
4698
|
};
|
|
4496
4699
|
|
|
4497
4700
|
// src/harmonyos/auth/tokenStore.ts
|
|
4498
|
-
import * as
|
|
4701
|
+
import * as fs34 from "fs";
|
|
4499
4702
|
import * as os11 from "os";
|
|
4500
|
-
import * as
|
|
4703
|
+
import * as path33 from "path";
|
|
4501
4704
|
import * as crypto3 from "crypto";
|
|
4502
4705
|
var ALGORITHM = "aes-256-gcm";
|
|
4503
4706
|
var KEY_LENGTH = 32;
|
|
@@ -4533,7 +4736,7 @@ function permissionHint(dir) {
|
|
|
4533
4736
|
}
|
|
4534
4737
|
function ensureDir(dir) {
|
|
4535
4738
|
try {
|
|
4536
|
-
|
|
4739
|
+
fs34.mkdirSync(dir, { recursive: true, mode: DIR_MODE });
|
|
4537
4740
|
} catch (err) {
|
|
4538
4741
|
if (err.code === "EACCES") {
|
|
4539
4742
|
throw new OniroError(permissionHint(dir), err);
|
|
@@ -4544,17 +4747,17 @@ function ensureDir(dir) {
|
|
|
4544
4747
|
function createTokenStore(opts) {
|
|
4545
4748
|
const logger = opts.logger ?? noopLogger;
|
|
4546
4749
|
const authDir = opts.config.get("harmonyosAuthDir", defaultPaths.harmonyosAuthDir());
|
|
4547
|
-
const tokenPath =
|
|
4548
|
-
const keyPath =
|
|
4750
|
+
const tokenPath = path33.join(authDir, TOKEN_FILE);
|
|
4751
|
+
const keyPath = path33.join(os11.homedir(), ".local", "share", "oniro-app", "keys", KEY_FILE);
|
|
4549
4752
|
function loadOrCreateKey() {
|
|
4550
|
-
if (
|
|
4551
|
-
const existing =
|
|
4753
|
+
if (fs34.existsSync(keyPath)) {
|
|
4754
|
+
const existing = fs34.readFileSync(keyPath);
|
|
4552
4755
|
if (existing.length === KEY_LENGTH) return existing;
|
|
4553
4756
|
logger.warn("[harmonyos] The token key file was malformed; regenerating (you will need to log in again).");
|
|
4554
4757
|
}
|
|
4555
|
-
ensureDir(
|
|
4758
|
+
ensureDir(path33.dirname(keyPath));
|
|
4556
4759
|
const key = crypto3.randomBytes(KEY_LENGTH);
|
|
4557
|
-
|
|
4760
|
+
fs34.writeFileSync(keyPath, key, { mode: FILE_MODE });
|
|
4558
4761
|
return key;
|
|
4559
4762
|
}
|
|
4560
4763
|
return {
|
|
@@ -4564,12 +4767,12 @@ function createTokenStore(opts) {
|
|
|
4564
4767
|
const payload = Buffer.from(JSON.stringify(session), "utf8");
|
|
4565
4768
|
const blob = encrypt2(loadOrCreateKey(), payload);
|
|
4566
4769
|
ensureDir(authDir);
|
|
4567
|
-
|
|
4770
|
+
fs34.writeFileSync(tokenPath, JSON.stringify(blob, null, 2), { mode: FILE_MODE });
|
|
4568
4771
|
},
|
|
4569
4772
|
load() {
|
|
4570
|
-
if (!
|
|
4773
|
+
if (!fs34.existsSync(tokenPath)) return null;
|
|
4571
4774
|
try {
|
|
4572
|
-
const blob = JSON.parse(
|
|
4775
|
+
const blob = JSON.parse(fs34.readFileSync(tokenPath, "utf8"));
|
|
4573
4776
|
if (!isEncryptedBlob(blob)) return null;
|
|
4574
4777
|
const { jwtToken, siteId } = JSON.parse(decrypt2(loadOrCreateKey(), blob).toString("utf8"));
|
|
4575
4778
|
return typeof jwtToken === "string" && jwtToken && typeof siteId === "string" ? { jwtToken, siteId } : null;
|
|
@@ -4581,7 +4784,7 @@ function createTokenStore(opts) {
|
|
|
4581
4784
|
}
|
|
4582
4785
|
logger.debug(`[harmonyos] Discarding unreadable token at ${tokenPath}.`);
|
|
4583
4786
|
try {
|
|
4584
|
-
|
|
4787
|
+
fs34.rmSync(tokenPath, { force: true });
|
|
4585
4788
|
} catch {
|
|
4586
4789
|
}
|
|
4587
4790
|
return null;
|
|
@@ -4589,7 +4792,7 @@ function createTokenStore(opts) {
|
|
|
4589
4792
|
},
|
|
4590
4793
|
clear() {
|
|
4591
4794
|
try {
|
|
4592
|
-
|
|
4795
|
+
fs34.rmSync(tokenPath, { force: true });
|
|
4593
4796
|
} catch (err) {
|
|
4594
4797
|
throw new OniroError(`Failed to remove ${tokenPath}.`, err);
|
|
4595
4798
|
}
|
|
@@ -5025,7 +5228,7 @@ var SIGNING_ERRORS = {
|
|
|
5025
5228
|
DEVICE_ADD: "AppGallery Connect did not register the device.",
|
|
5026
5229
|
DEVICE_LIMIT: "This team has reached its device limit. Remove an unused device in AppGallery Connect and retry.",
|
|
5027
5230
|
DEVICE_NAME_REPEAT: "A device with that name is already registered. Retry.",
|
|
5028
|
-
DEVICE_NONE: "
|
|
5231
|
+
DEVICE_NONE: "This team has no registered device and none could be registered from here, but a debug profile must name at least one. Connect a device that reports a UDID (`hdc shell bm get -u`), or register one in AppGallery Connect, and retry.",
|
|
5029
5232
|
PROFILE_ADD: "AppGallery Connect did not issue the provisioning profile.",
|
|
5030
5233
|
PROFILE_NAME_REPEAT: "A provisioning profile with that name already exists in AppGallery Connect. Retry.",
|
|
5031
5234
|
PROVISION_LIMIT: "This team has reached its debug-profile limit. Delete unused profiles in AppGallery Connect and retry.",
|
|
@@ -5070,7 +5273,7 @@ function mapAgcError(operation, statusCode, reasonPhrase, body) {
|
|
|
5070
5273
|
}
|
|
5071
5274
|
|
|
5072
5275
|
// src/harmonyos/signing/profile.ts
|
|
5073
|
-
import * as
|
|
5276
|
+
import * as fs35 from "fs";
|
|
5074
5277
|
import { X509Certificate } from "crypto";
|
|
5075
5278
|
import forge from "node-forge";
|
|
5076
5279
|
function extractProfileJson(buffer) {
|
|
@@ -5102,7 +5305,7 @@ function extractProfileJson(buffer) {
|
|
|
5102
5305
|
function readProvisionProfile(profilePath) {
|
|
5103
5306
|
let raw;
|
|
5104
5307
|
try {
|
|
5105
|
-
const json = extractProfileJson(
|
|
5308
|
+
const json = extractProfileJson(fs35.readFileSync(profilePath));
|
|
5106
5309
|
if (!json) return null;
|
|
5107
5310
|
raw = JSON.parse(json);
|
|
5108
5311
|
} catch {
|
|
@@ -5131,7 +5334,7 @@ function parseCertificate(pem) {
|
|
|
5131
5334
|
}
|
|
5132
5335
|
function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
|
|
5133
5336
|
try {
|
|
5134
|
-
const der = forge.util.createBuffer(
|
|
5337
|
+
const der = forge.util.createBuffer(fs35.readFileSync(p12Path).toString("binary"));
|
|
5135
5338
|
const p12 = forge.pkcs12.pkcs12FromAsn1(forge.asn1.fromDer(der), keyPwd);
|
|
5136
5339
|
const certBag = forge.pki.oids.certBag ?? "1.2.840.113549.1.12.10.1.3";
|
|
5137
5340
|
const wanted = certificate.publicKey.export({ type: "spki", format: "der" });
|
|
@@ -5147,7 +5350,7 @@ function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
|
|
|
5147
5350
|
}
|
|
5148
5351
|
}
|
|
5149
5352
|
function verifySigningMaterial(opts) {
|
|
5150
|
-
const pems =
|
|
5353
|
+
const pems = fs35.readFileSync(opts.cerPath, "utf8").match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g);
|
|
5151
5354
|
const chain = (pems ?? []).map(parseCertificate);
|
|
5152
5355
|
const leaf = chain.find((c) => !c.ca) ?? chain.at(-1);
|
|
5153
5356
|
if (!leaf) throw new AgcError(SIGNING_ERRORS.CERT_INVALID);
|
|
@@ -5166,14 +5369,14 @@ function verifySigningMaterial(opts) {
|
|
|
5166
5369
|
|
|
5167
5370
|
// src/harmonyos/signing/autoSign.ts
|
|
5168
5371
|
import * as crypto9 from "crypto";
|
|
5169
|
-
import * as
|
|
5170
|
-
import * as
|
|
5372
|
+
import * as fs40 from "fs";
|
|
5373
|
+
import * as path39 from "path";
|
|
5171
5374
|
import JSON57 from "json5";
|
|
5172
5375
|
|
|
5173
5376
|
// src/harmonyos/signing/agc.ts
|
|
5174
5377
|
import * as crypto6 from "crypto";
|
|
5175
|
-
import * as
|
|
5176
|
-
import * as
|
|
5378
|
+
import * as fs36 from "fs";
|
|
5379
|
+
import * as path34 from "path";
|
|
5177
5380
|
var ENDPOINTS = {
|
|
5178
5381
|
CERT_LIST: "/api/cps/harmony-cert-manage/v1/cert/list",
|
|
5179
5382
|
CERT_ADD: "/api/cps/harmony-cert-manage/v1/cert/add",
|
|
@@ -5259,8 +5462,8 @@ function createAgcClient(http3, auth) {
|
|
|
5259
5462
|
if (target.sha256 && actual !== target.sha256.toLowerCase()) {
|
|
5260
5463
|
throw new ChecksumMismatchError(target.sha256, actual);
|
|
5261
5464
|
}
|
|
5262
|
-
|
|
5263
|
-
|
|
5465
|
+
fs36.mkdirSync(path34.dirname(dest), { recursive: true, mode: 448 });
|
|
5466
|
+
fs36.writeFileSync(dest, buffer, { mode: 384 });
|
|
5264
5467
|
}
|
|
5265
5468
|
};
|
|
5266
5469
|
}
|
|
@@ -5274,21 +5477,31 @@ function parseDeviceKind(stdout) {
|
|
|
5274
5477
|
}
|
|
5275
5478
|
async function collectLocalDevices(config, logger) {
|
|
5276
5479
|
const devices = [];
|
|
5480
|
+
const skipped = [];
|
|
5277
5481
|
for (const target of await listDevices(config, { logger, timeoutMs: 15e3 })) {
|
|
5278
|
-
|
|
5482
|
+
const skip = (why) => {
|
|
5483
|
+
logger.warn(`[harmonyos] ${target.serial} ${why}`);
|
|
5484
|
+
skipped.push(target.serial);
|
|
5485
|
+
};
|
|
5486
|
+
if (!isUsableDevice(target)) {
|
|
5487
|
+
skip(
|
|
5488
|
+
target.status === "Unauthorized" ? "is unauthorized; accept the debugging prompt on the device to register it." : `is ${target.status.toLowerCase()}; skipping it.`
|
|
5489
|
+
);
|
|
5490
|
+
continue;
|
|
5491
|
+
}
|
|
5279
5492
|
const shell2 = async (...args) => (await hdcExec({ config, deviceSerial: target.serial, args: ["shell", ...args], timeoutMs: 15e3, logger })).stdout;
|
|
5280
5493
|
try {
|
|
5281
5494
|
const udid = parseUdid(await shell2("bm", "get", "-u"));
|
|
5282
5495
|
if (!udid) {
|
|
5283
|
-
|
|
5496
|
+
skip("did not report a UDID (`bm get -u`), so it cannot be registered.");
|
|
5284
5497
|
continue;
|
|
5285
5498
|
}
|
|
5286
5499
|
devices.push({ serial: target.serial, udid, kind: parseDeviceKind(await shell2("getprop", "hw_sc.build.os.deviceType")) });
|
|
5287
5500
|
} catch (err) {
|
|
5288
|
-
|
|
5501
|
+
skip(`could not be read: ${err.message}`);
|
|
5289
5502
|
}
|
|
5290
5503
|
}
|
|
5291
|
-
return devices;
|
|
5504
|
+
return { devices, skipped };
|
|
5292
5505
|
}
|
|
5293
5506
|
async function registerDevices(agc, connected, logger) {
|
|
5294
5507
|
let devices = await agc.listDevices();
|
|
@@ -5301,32 +5514,27 @@ async function registerDevices(agc, connected, logger) {
|
|
|
5301
5514
|
if (unregistered.length > 0) devices = await agc.listDevices();
|
|
5302
5515
|
const deviceIds = devices.map((d) => d.id);
|
|
5303
5516
|
if (deviceIds.length === 0) throw new AgcError(SIGNING_ERRORS.DEVICE_NONE);
|
|
5304
|
-
if (connected.length === 0) {
|
|
5305
|
-
logger.warn(
|
|
5306
|
-
`[harmonyos] No device is connected; the profile will name the ${deviceIds.length} device(s) already registered to this team.`
|
|
5307
|
-
);
|
|
5308
|
-
}
|
|
5309
5517
|
return deviceIds;
|
|
5310
5518
|
}
|
|
5311
5519
|
|
|
5312
5520
|
// src/harmonyos/signing/keystore.ts
|
|
5313
5521
|
import * as crypto7 from "crypto";
|
|
5314
|
-
import * as
|
|
5315
|
-
import * as
|
|
5522
|
+
import * as fs38 from "fs";
|
|
5523
|
+
import * as path36 from "path";
|
|
5316
5524
|
|
|
5317
5525
|
// src/harmonyos/java.ts
|
|
5318
|
-
import * as
|
|
5319
|
-
import * as
|
|
5526
|
+
import * as fs37 from "fs";
|
|
5527
|
+
import * as path35 from "path";
|
|
5320
5528
|
var JAVA_BIN = process.platform === "win32" ? "java.exe" : "java";
|
|
5321
5529
|
function findJava(sdk, env = process.env) {
|
|
5322
5530
|
const candidates = [
|
|
5323
|
-
env.JAVA_HOME &&
|
|
5324
|
-
sdk &&
|
|
5531
|
+
env.JAVA_HOME && path35.join(env.JAVA_HOME, "bin", JAVA_BIN),
|
|
5532
|
+
sdk && path35.join(sdk.installRoot, "jbr", "bin", JAVA_BIN),
|
|
5325
5533
|
// macOS: the JBR is itself a bundle inside Studio's Contents.
|
|
5326
|
-
sdk &&
|
|
5327
|
-
...(env.PATH ?? "").split(
|
|
5534
|
+
sdk && path35.join(sdk.installRoot, "jbr", "Contents", "Home", "bin", JAVA_BIN),
|
|
5535
|
+
...(env.PATH ?? "").split(path35.delimiter).map((dir) => dir && path35.join(dir, JAVA_BIN))
|
|
5328
5536
|
];
|
|
5329
|
-
const found = candidates.find((c) => !!c &&
|
|
5537
|
+
const found = candidates.find((c) => !!c && fs37.existsSync(c));
|
|
5330
5538
|
if (found) return found;
|
|
5331
5539
|
throw new OniroError(
|
|
5332
5540
|
"No Java runtime found. HarmonyOS signing runs the SDK's hap-sign-tool.jar, which needs one: install a JDK and set JAVA_HOME, or install DevEco Studio, whose bundled runtime is used automatically."
|
|
@@ -5340,13 +5548,13 @@ function redactArgs(args) {
|
|
|
5340
5548
|
return args.map((arg, i) => args[i - 1] === "-keyPwd" || args[i - 1] === "-keystorePwd" ? "******" : arg);
|
|
5341
5549
|
}
|
|
5342
5550
|
async function generateKeystoreAndCsr(opts) {
|
|
5343
|
-
const jar =
|
|
5344
|
-
if (!
|
|
5551
|
+
const jar = path36.join(opts.sdk.sdkPath, "default", "openharmony", "toolchains", "lib", "hap-sign-tool.jar");
|
|
5552
|
+
if (!fs38.existsSync(jar)) {
|
|
5345
5553
|
throw new OniroError(`hap-sign-tool.jar not found at ${jar}; the HarmonyOS SDK looks incomplete.`);
|
|
5346
5554
|
}
|
|
5347
5555
|
const java = findJava(opts.sdk);
|
|
5348
5556
|
const keyPwd = crypto7.randomBytes(12).toString("base64url").replaceAll(/[-_]/g, "");
|
|
5349
|
-
|
|
5557
|
+
fs38.mkdirSync(path36.dirname(opts.p12Path), { recursive: true, mode: 448 });
|
|
5350
5558
|
const run = async (what, args) => {
|
|
5351
5559
|
const argv = ["-jar", jar, ...args, "-keyAlias", KEY_ALIAS, "-keystoreFile", opts.p12Path, "-keystorePwd", keyPwd, "-keyPwd", keyPwd];
|
|
5352
5560
|
opts.logger.debug(`[harmonyos] ${java} ${redactArgs(argv).join(" ")}`);
|
|
@@ -5360,28 +5568,28 @@ ${detail}` : ""}`);
|
|
|
5360
5568
|
opts.logger.info("[harmonyos] Generating the local keystore and certificate signing request...");
|
|
5361
5569
|
await run("generate the key pair", ["generate-keypair", "-keyAlg", "ECC", "-keySize", "NIST-P-256"]);
|
|
5362
5570
|
await run("generate the CSR", ["generate-csr", "-subject", "CN=DebugKey", "-signAlg", SIGN_ALG, "-outFile", opts.csrPath]);
|
|
5363
|
-
return { keyPwd, csr:
|
|
5571
|
+
return { keyPwd, csr: fs38.readFileSync(opts.csrPath, "utf8") };
|
|
5364
5572
|
}
|
|
5365
5573
|
|
|
5366
5574
|
// src/harmonyos/signing/paths.ts
|
|
5367
5575
|
import * as crypto8 from "crypto";
|
|
5368
|
-
import * as
|
|
5576
|
+
import * as path37 from "path";
|
|
5369
5577
|
function sanitizeNamePart(raw) {
|
|
5370
5578
|
const safe = (raw?.trim() ?? "").replace(/[\\/:*?"<>|=.-]+/g, "_");
|
|
5371
5579
|
return safe.slice(0, 64) || "default";
|
|
5372
5580
|
}
|
|
5373
5581
|
function resolveSigningMaterialPaths(config, productName, projectRoot) {
|
|
5374
5582
|
const hash = crypto8.createHash("sha256").update(projectRoot, "utf8").digest("base64url").replaceAll(/[-_]/g, "");
|
|
5375
|
-
const base =
|
|
5583
|
+
const base = path37.join(
|
|
5376
5584
|
config.get("harmonyosSigningDir", defaultPaths.harmonyosSigningDir()),
|
|
5377
|
-
`${sanitizeNamePart(productName)}_${
|
|
5585
|
+
`${sanitizeNamePart(productName)}_${path37.basename(projectRoot)}_${hash}=`
|
|
5378
5586
|
);
|
|
5379
5587
|
return { p12Path: `${base}.p12`, csrPath: `${base}.csr`, cerPath: `${base}.cer`, profilePath: `${base}.p7b` };
|
|
5380
5588
|
}
|
|
5381
5589
|
|
|
5382
5590
|
// src/harmonyos/signing/project.ts
|
|
5383
|
-
import * as
|
|
5384
|
-
import * as
|
|
5591
|
+
import * as fs39 from "fs";
|
|
5592
|
+
import * as path38 from "path";
|
|
5385
5593
|
import JSON56 from "json5";
|
|
5386
5594
|
|
|
5387
5595
|
// src/harmonyos/signing/aclPermissionList.ts
|
|
@@ -5449,9 +5657,9 @@ var ACL_PERMISSIONS = /* @__PURE__ */ new Set([
|
|
|
5449
5657
|
|
|
5450
5658
|
// src/harmonyos/signing/project.ts
|
|
5451
5659
|
function readRequestedPermissions(moduleConfigPath) {
|
|
5452
|
-
if (!
|
|
5660
|
+
if (!fs39.existsSync(moduleConfigPath)) return [];
|
|
5453
5661
|
try {
|
|
5454
|
-
const parsed = JSON56.parse(
|
|
5662
|
+
const parsed = JSON56.parse(fs39.readFileSync(moduleConfigPath, "utf-8"));
|
|
5455
5663
|
return (parsed.module?.requestPermissions ?? []).map((p) => p?.name).filter((n) => typeof n === "string" && n.length > 0);
|
|
5456
5664
|
} catch {
|
|
5457
5665
|
return [];
|
|
@@ -5460,10 +5668,10 @@ function readRequestedPermissions(moduleConfigPath) {
|
|
|
5460
5668
|
function collectAclPermissions(projectDir, logger = noopLogger) {
|
|
5461
5669
|
const requested = /* @__PURE__ */ new Set();
|
|
5462
5670
|
for (const module of listModules({ projectDir })) {
|
|
5463
|
-
const moduleRoot =
|
|
5671
|
+
const moduleRoot = path38.resolve(projectDir, module.srcPath);
|
|
5464
5672
|
for (const sourceSet of ["main", "ohosTest"]) {
|
|
5465
5673
|
for (const name of readRequestedPermissions(
|
|
5466
|
-
|
|
5674
|
+
path38.join(moduleRoot, "src", sourceSet, "module.json5")
|
|
5467
5675
|
)) {
|
|
5468
5676
|
requested.add(name);
|
|
5469
5677
|
}
|
|
@@ -5479,7 +5687,7 @@ function collectAclPermissions(projectDir, logger = noopLogger) {
|
|
|
5479
5687
|
// src/harmonyos/signing/autoSign.ts
|
|
5480
5688
|
function shouldRegenerate(input) {
|
|
5481
5689
|
if (input.force) return "--force was passed";
|
|
5482
|
-
const missing = Object.values(input.paths).find((file) => !
|
|
5690
|
+
const missing = Object.values(input.paths).find((file) => !fs40.existsSync(file));
|
|
5483
5691
|
if (missing) return `${missing} is missing`;
|
|
5484
5692
|
const config = input.buildProfile.app?.signingConfigs?.find((c) => c.name === input.productName);
|
|
5485
5693
|
if (config?.type !== "HarmonyOS" || config.material?.profile !== input.paths.profilePath) {
|
|
@@ -5518,16 +5726,16 @@ function writeSigningConfig(opts) {
|
|
|
5518
5726
|
for (const product of app.products ?? []) {
|
|
5519
5727
|
if (product.name === opts.productName) product.signingConfig = opts.productName;
|
|
5520
5728
|
}
|
|
5521
|
-
|
|
5729
|
+
fs40.writeFileSync(opts.buildProfilePath, JSON.stringify(opts.buildProfile, null, 2));
|
|
5522
5730
|
}
|
|
5523
5731
|
async function harmonyOsAutoSign(opts) {
|
|
5524
5732
|
const logger = opts.logger ?? noopLogger;
|
|
5525
5733
|
const productName = opts.productName ?? "default";
|
|
5526
|
-
const projectDir =
|
|
5527
|
-
const buildProfilePath =
|
|
5734
|
+
const projectDir = path39.resolve(opts.projectDir);
|
|
5735
|
+
const buildProfilePath = path39.join(projectDir, "build-profile.json5");
|
|
5528
5736
|
let buildProfile;
|
|
5529
5737
|
try {
|
|
5530
|
-
buildProfile = JSON57.parse(
|
|
5738
|
+
buildProfile = JSON57.parse(fs40.readFileSync(buildProfilePath, "utf-8"));
|
|
5531
5739
|
} catch (err) {
|
|
5532
5740
|
throw new OniroError(`Could not read ${buildProfilePath}: ${err.message}`, err);
|
|
5533
5741
|
}
|
|
@@ -5542,7 +5750,7 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5542
5750
|
const aclPermissions = collectAclPermissions(projectDir, logger);
|
|
5543
5751
|
const paths = resolveSigningMaterialPaths(opts.config, productName, projectDir);
|
|
5544
5752
|
logger.info(`[harmonyos] Signing ${bundleName} (product '${productName}', team ${auth.teamId}).`);
|
|
5545
|
-
const
|
|
5753
|
+
const local = await collectLocalDevices(opts.config, logger);
|
|
5546
5754
|
const result = (regenerated) => ({
|
|
5547
5755
|
bundleName,
|
|
5548
5756
|
teamId: auth.teamId,
|
|
@@ -5556,7 +5764,7 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5556
5764
|
productName,
|
|
5557
5765
|
bundleName,
|
|
5558
5766
|
teamId: auth.teamId,
|
|
5559
|
-
connectedUdids:
|
|
5767
|
+
connectedUdids: local.devices.map((d) => d.udid),
|
|
5560
5768
|
aclPermissions,
|
|
5561
5769
|
force: opts.force
|
|
5562
5770
|
});
|
|
@@ -5566,8 +5774,12 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5566
5774
|
}
|
|
5567
5775
|
logger.info(`[harmonyos] Regenerating signing material: ${reason}.`);
|
|
5568
5776
|
const agc = createAgcClient(opts.http ?? createHttpClient({ logger }), auth);
|
|
5569
|
-
const deviceIds = await registerDevices(agc,
|
|
5570
|
-
|
|
5777
|
+
const deviceIds = await registerDevices(agc, local.devices, logger);
|
|
5778
|
+
if (local.devices.length === 0) {
|
|
5779
|
+
const cause = local.skipped.length > 0 ? "No connected device could be registered" : "No device is connected";
|
|
5780
|
+
logger.warn(`[harmonyos] ${cause}; the profile will name the ${deviceIds.length} device(s) already registered to this team.`);
|
|
5781
|
+
}
|
|
5782
|
+
for (const file of Object.values(paths)) fs40.rmSync(file, { force: true });
|
|
5571
5783
|
const certName = `oniro_debug_${auth.teamId.replace(/[\\/.:]/g, "")}.cer`;
|
|
5572
5784
|
const stale = (await agc.listCertificates()).find((c) => c.certName === certName);
|
|
5573
5785
|
if (stale) {
|
|
@@ -5598,10 +5810,10 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5598
5810
|
try {
|
|
5599
5811
|
verifySigningMaterial({ ...paths, keyAlias: KEY_ALIAS, keyPwd });
|
|
5600
5812
|
} catch (err) {
|
|
5601
|
-
|
|
5813
|
+
fs40.rmSync(paths.profilePath, { force: true });
|
|
5602
5814
|
throw err;
|
|
5603
5815
|
}
|
|
5604
|
-
const materialDir =
|
|
5816
|
+
const materialDir = path39.join(path39.dirname(paths.p12Path), "material");
|
|
5605
5817
|
try {
|
|
5606
5818
|
getKey(materialDir);
|
|
5607
5819
|
} catch {
|
|
@@ -5613,7 +5825,7 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5613
5825
|
}
|
|
5614
5826
|
|
|
5615
5827
|
// src/index.ts
|
|
5616
|
-
var VERSION = "0.
|
|
5828
|
+
var VERSION = "0.15.1";
|
|
5617
5829
|
export {
|
|
5618
5830
|
ALL_SDKS,
|
|
5619
5831
|
APL_VALUES,
|
|
@@ -5627,6 +5839,7 @@ export {
|
|
|
5627
5839
|
HUAWEI_SITES,
|
|
5628
5840
|
INSTALL_TMP_DIRNAME,
|
|
5629
5841
|
InsufficientSpaceError,
|
|
5842
|
+
OHOS_DAILY_BUILDS_URL,
|
|
5630
5843
|
OHOS_URL_BASE,
|
|
5631
5844
|
OniroError,
|
|
5632
5845
|
SIGNING_ERRORS,
|
|
@@ -5647,6 +5860,7 @@ export {
|
|
|
5647
5860
|
buildHvigorwArgs,
|
|
5648
5861
|
buildInputCommand,
|
|
5649
5862
|
buildRawTouchCommand,
|
|
5863
|
+
bundleNameFromHapConfig,
|
|
5650
5864
|
captureBurst,
|
|
5651
5865
|
captureLog,
|
|
5652
5866
|
cleanCodelinterOutput,
|
|
@@ -5700,6 +5914,7 @@ export {
|
|
|
5700
5914
|
findLayoutNodes,
|
|
5701
5915
|
findMissingProjectSdk,
|
|
5702
5916
|
findRunningProcess,
|
|
5917
|
+
findSdkOsDir,
|
|
5703
5918
|
flattenLayout,
|
|
5704
5919
|
forceStop,
|
|
5705
5920
|
formatBytes,
|
|
@@ -5733,16 +5948,19 @@ export {
|
|
|
5733
5948
|
hdcTargetArgs,
|
|
5734
5949
|
hdcTargetArgsFor,
|
|
5735
5950
|
hideKeyboard,
|
|
5951
|
+
hilogTimeMs,
|
|
5736
5952
|
installApp,
|
|
5737
5953
|
installCmdTools,
|
|
5738
5954
|
installEmulator,
|
|
5739
5955
|
installFailureReason,
|
|
5956
|
+
installSdkFromArchive,
|
|
5740
5957
|
isBundleInstalled,
|
|
5741
5958
|
isCmdToolsInstalled,
|
|
5742
5959
|
isEmulatorInstalled,
|
|
5743
5960
|
isOutOfSpaceError,
|
|
5744
5961
|
isRamBackedPath,
|
|
5745
5962
|
isUnsignedHap,
|
|
5963
|
+
isUsableDevice,
|
|
5746
5964
|
isValidBundleName,
|
|
5747
5965
|
isValidProjectName,
|
|
5748
5966
|
killProcessTree,
|
|
@@ -5753,6 +5971,7 @@ export {
|
|
|
5753
5971
|
listRunningProcesses,
|
|
5754
5972
|
listTemplates,
|
|
5755
5973
|
locateTarget,
|
|
5974
|
+
missingProjectRootFiles,
|
|
5756
5975
|
needsCmdWrapper,
|
|
5757
5976
|
nonInteractivePrompter,
|
|
5758
5977
|
noopLogger,
|
|
@@ -5776,9 +5995,11 @@ export {
|
|
|
5776
5995
|
pickTarget,
|
|
5777
5996
|
prepareSigning,
|
|
5778
5997
|
pruneLayout,
|
|
5998
|
+
readHapBundleName,
|
|
5779
5999
|
readJson5File,
|
|
5780
6000
|
readJsonFile,
|
|
5781
6001
|
readProvisionProfile,
|
|
6002
|
+
readZipEntry,
|
|
5782
6003
|
reboot,
|
|
5783
6004
|
recvFile,
|
|
5784
6005
|
removeCmdTools,
|