@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.cjs
CHANGED
|
@@ -42,6 +42,7 @@ __export(index_exports, {
|
|
|
42
42
|
HUAWEI_SITES: () => HUAWEI_SITES,
|
|
43
43
|
INSTALL_TMP_DIRNAME: () => INSTALL_TMP_DIRNAME,
|
|
44
44
|
InsufficientSpaceError: () => InsufficientSpaceError,
|
|
45
|
+
OHOS_DAILY_BUILDS_URL: () => OHOS_DAILY_BUILDS_URL,
|
|
45
46
|
OHOS_URL_BASE: () => OHOS_URL_BASE,
|
|
46
47
|
OniroError: () => OniroError,
|
|
47
48
|
SIGNING_ERRORS: () => SIGNING_ERRORS,
|
|
@@ -62,6 +63,7 @@ __export(index_exports, {
|
|
|
62
63
|
buildHvigorwArgs: () => buildHvigorwArgs,
|
|
63
64
|
buildInputCommand: () => buildInputCommand,
|
|
64
65
|
buildRawTouchCommand: () => buildRawTouchCommand,
|
|
66
|
+
bundleNameFromHapConfig: () => bundleNameFromHapConfig,
|
|
65
67
|
captureBurst: () => captureBurst,
|
|
66
68
|
captureLog: () => captureLog,
|
|
67
69
|
cleanCodelinterOutput: () => cleanCodelinterOutput,
|
|
@@ -115,6 +117,7 @@ __export(index_exports, {
|
|
|
115
117
|
findLayoutNodes: () => findLayoutNodes,
|
|
116
118
|
findMissingProjectSdk: () => findMissingProjectSdk,
|
|
117
119
|
findRunningProcess: () => findRunningProcess,
|
|
120
|
+
findSdkOsDir: () => findSdkOsDir,
|
|
118
121
|
flattenLayout: () => flattenLayout,
|
|
119
122
|
forceStop: () => forceStop,
|
|
120
123
|
formatBytes: () => formatBytes,
|
|
@@ -148,16 +151,19 @@ __export(index_exports, {
|
|
|
148
151
|
hdcTargetArgs: () => hdcTargetArgs,
|
|
149
152
|
hdcTargetArgsFor: () => hdcTargetArgsFor,
|
|
150
153
|
hideKeyboard: () => hideKeyboard,
|
|
154
|
+
hilogTimeMs: () => hilogTimeMs,
|
|
151
155
|
installApp: () => installApp,
|
|
152
156
|
installCmdTools: () => installCmdTools,
|
|
153
157
|
installEmulator: () => installEmulator,
|
|
154
158
|
installFailureReason: () => installFailureReason,
|
|
159
|
+
installSdkFromArchive: () => installSdkFromArchive,
|
|
155
160
|
isBundleInstalled: () => isBundleInstalled,
|
|
156
161
|
isCmdToolsInstalled: () => isCmdToolsInstalled,
|
|
157
162
|
isEmulatorInstalled: () => isEmulatorInstalled,
|
|
158
163
|
isOutOfSpaceError: () => isOutOfSpaceError,
|
|
159
164
|
isRamBackedPath: () => isRamBackedPath,
|
|
160
165
|
isUnsignedHap: () => isUnsignedHap,
|
|
166
|
+
isUsableDevice: () => isUsableDevice,
|
|
161
167
|
isValidBundleName: () => isValidBundleName,
|
|
162
168
|
isValidProjectName: () => isValidProjectName,
|
|
163
169
|
killProcessTree: () => killProcessTree,
|
|
@@ -168,6 +174,7 @@ __export(index_exports, {
|
|
|
168
174
|
listRunningProcesses: () => listRunningProcesses,
|
|
169
175
|
listTemplates: () => listTemplates,
|
|
170
176
|
locateTarget: () => locateTarget,
|
|
177
|
+
missingProjectRootFiles: () => missingProjectRootFiles,
|
|
171
178
|
needsCmdWrapper: () => needsCmdWrapper,
|
|
172
179
|
nonInteractivePrompter: () => nonInteractivePrompter,
|
|
173
180
|
noopLogger: () => noopLogger,
|
|
@@ -191,9 +198,11 @@ __export(index_exports, {
|
|
|
191
198
|
pickTarget: () => pickTarget,
|
|
192
199
|
prepareSigning: () => prepareSigning,
|
|
193
200
|
pruneLayout: () => pruneLayout,
|
|
201
|
+
readHapBundleName: () => readHapBundleName,
|
|
194
202
|
readJson5File: () => readJson5File,
|
|
195
203
|
readJsonFile: () => readJsonFile,
|
|
196
204
|
readProvisionProfile: () => readProvisionProfile,
|
|
205
|
+
readZipEntry: () => readZipEntry,
|
|
197
206
|
reboot: () => reboot,
|
|
198
207
|
recvFile: () => recvFile,
|
|
199
208
|
removeCmdTools: () => removeCmdTools,
|
|
@@ -424,6 +433,7 @@ var ALL_SDKS = [
|
|
|
424
433
|
{ version: "7.0", api: "26", tarballStrip: { linuxWindows: 1, darwin: 3 }, archiveSuffix: "_20260829" }
|
|
425
434
|
];
|
|
426
435
|
var OHOS_URL_BASE = "https://repo.huaweicloud.com/openharmony/os";
|
|
436
|
+
var OHOS_DAILY_BUILDS_URL = "https://dcp.openharmony.cn/workbench/cicd/dailybuild/dailylist";
|
|
427
437
|
|
|
428
438
|
// src/sdk/platform.ts
|
|
429
439
|
var os2 = __toESM(require("os"), 1);
|
|
@@ -1006,8 +1016,17 @@ async function extractZipWithProgress(opts) {
|
|
|
1006
1016
|
if (inc > 0) progress.report({ message: "Extracting: 100%", increment: inc });
|
|
1007
1017
|
}
|
|
1008
1018
|
}
|
|
1009
|
-
async function extractTarball(tarPath, dest, strip = 0) {
|
|
1010
|
-
await tar.x({ file: tarPath, cwd: dest, strip });
|
|
1019
|
+
async function extractTarball(tarPath, dest, strip = 0, filter) {
|
|
1020
|
+
await tar.x({ file: tarPath, cwd: dest, strip, ...filter ? { filter: (p) => filter(p) } : {} });
|
|
1021
|
+
}
|
|
1022
|
+
async function readZipEntry(zipPath, match) {
|
|
1023
|
+
const zip = new import_node_stream_zip.default.async({ file: zipPath });
|
|
1024
|
+
try {
|
|
1025
|
+
const entry = Object.values(await zip.entries()).find((e) => !e.isDirectory && match(e.name));
|
|
1026
|
+
return entry ? await zip.entryData(entry) : void 0;
|
|
1027
|
+
} finally {
|
|
1028
|
+
await zip.close();
|
|
1029
|
+
}
|
|
1011
1030
|
}
|
|
1012
1031
|
|
|
1013
1032
|
// src/sdk/list.ts
|
|
@@ -1113,34 +1132,7 @@ async function downloadAndInstallSdk(opts) {
|
|
|
1113
1132
|
`Expected folder '${osFolder}' not found in extracted SDK. Tarball layout may have changed.`
|
|
1114
1133
|
);
|
|
1115
1134
|
}
|
|
1116
|
-
|
|
1117
|
-
const componentsStart = 60;
|
|
1118
|
-
const componentsBudget = 35;
|
|
1119
|
-
const n = zipFiles.length;
|
|
1120
|
-
if (n === 0) {
|
|
1121
|
-
progress?.report({ message: "No SDK component ZIPs found.", increment: componentsBudget });
|
|
1122
|
-
} else {
|
|
1123
|
-
progress?.report({ message: "Extracting SDK components...", increment: 0 });
|
|
1124
|
-
}
|
|
1125
|
-
const base = n > 0 ? Math.floor(componentsBudget / n) : 0;
|
|
1126
|
-
let rem = n > 0 ? componentsBudget % n : 0;
|
|
1127
|
-
let cursor = componentsStart;
|
|
1128
|
-
for (const zipFile of zipFiles) {
|
|
1129
|
-
checkCancelled();
|
|
1130
|
-
logger.info(`Extracting component ${zipFile}`);
|
|
1131
|
-
const zipPath = path10.join(osContentPath, zipFile);
|
|
1132
|
-
const thisBudget = base + (rem > 0 ? 1 : 0);
|
|
1133
|
-
if (rem > 0) rem--;
|
|
1134
|
-
await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });
|
|
1135
|
-
cursor += thisBudget;
|
|
1136
|
-
fs10.unlinkSync(zipPath);
|
|
1137
|
-
}
|
|
1138
|
-
progress?.report({ message: "Finalizing installation...", increment: 0 });
|
|
1139
|
-
if (fs10.existsSync(sdkInstallDir)) {
|
|
1140
|
-
fs10.rmSync(sdkInstallDir, { recursive: true, force: true });
|
|
1141
|
-
}
|
|
1142
|
-
movePath(osContentPath, sdkInstallDir);
|
|
1143
|
-
progress?.report({ message: "Finalizing installation...", increment: 3 });
|
|
1135
|
+
await installComponents({ osContentPath, sdkInstallDir, progress, logger, start: 60, range: 35, checkCancelled });
|
|
1144
1136
|
progress?.report({ message: "Cleaning up...", increment: 0 });
|
|
1145
1137
|
removeTempWorkDir(tmpDir, tmpRoot);
|
|
1146
1138
|
progress?.report({ message: "Cleaning up...", increment: 2 });
|
|
@@ -1151,6 +1143,115 @@ async function downloadAndInstallSdk(opts) {
|
|
|
1151
1143
|
throw wrapped;
|
|
1152
1144
|
}
|
|
1153
1145
|
}
|
|
1146
|
+
async function installComponents(opts) {
|
|
1147
|
+
const { osContentPath, sdkInstallDir, progress, logger, checkCancelled } = opts;
|
|
1148
|
+
const zipFiles = fs10.readdirSync(osContentPath).filter((n2) => n2.endsWith(".zip"));
|
|
1149
|
+
const n = zipFiles.length;
|
|
1150
|
+
if (n === 0) {
|
|
1151
|
+
progress?.report({ message: "No SDK component ZIPs found.", increment: opts.range });
|
|
1152
|
+
} else {
|
|
1153
|
+
progress?.report({ message: "Extracting SDK components...", increment: 0 });
|
|
1154
|
+
}
|
|
1155
|
+
const base = n > 0 ? Math.floor(opts.range / n) : 0;
|
|
1156
|
+
let rem = n > 0 ? opts.range % n : 0;
|
|
1157
|
+
let cursor = opts.start;
|
|
1158
|
+
for (const zipFile of zipFiles) {
|
|
1159
|
+
checkCancelled();
|
|
1160
|
+
logger.info(`Extracting component ${zipFile}`);
|
|
1161
|
+
const zipPath = path10.join(osContentPath, zipFile);
|
|
1162
|
+
const thisBudget = base + (rem > 0 ? 1 : 0);
|
|
1163
|
+
if (rem > 0) rem--;
|
|
1164
|
+
await extractZipWithProgress({ zipPath, dest: osContentPath, progress, start: cursor, range: thisBudget, logger });
|
|
1165
|
+
cursor += thisBudget;
|
|
1166
|
+
fs10.unlinkSync(zipPath);
|
|
1167
|
+
}
|
|
1168
|
+
progress?.report({ message: "Finalizing installation...", increment: 0 });
|
|
1169
|
+
if (fs10.existsSync(sdkInstallDir)) {
|
|
1170
|
+
fs10.rmSync(sdkInstallDir, { recursive: true, force: true });
|
|
1171
|
+
}
|
|
1172
|
+
movePath(osContentPath, sdkInstallDir);
|
|
1173
|
+
progress?.report({ message: "Finalizing installation...", increment: 3 });
|
|
1174
|
+
}
|
|
1175
|
+
async function installSdkFromArchive(opts) {
|
|
1176
|
+
const { config, archivePath, progress, abortSignal } = opts;
|
|
1177
|
+
const logger = opts.logger ?? noopLogger;
|
|
1178
|
+
if (!fs10.statSync(archivePath, { throwIfNoEntry: false })?.isFile()) {
|
|
1179
|
+
throw new OniroError(`SDK archive not found: ${archivePath}`);
|
|
1180
|
+
}
|
|
1181
|
+
const osFolder = getOsFolder();
|
|
1182
|
+
const what = `the SDK install from '${path10.basename(archivePath)}'`;
|
|
1183
|
+
const sdkRoot = getSdkRootDir(config);
|
|
1184
|
+
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
1185
|
+
config,
|
|
1186
|
+
override: opts.tmpDir,
|
|
1187
|
+
installRoot: sdkRoot,
|
|
1188
|
+
prefix: "oniro-sdk-",
|
|
1189
|
+
logger
|
|
1190
|
+
});
|
|
1191
|
+
const extractDir = path10.join(tmpDir, "extract");
|
|
1192
|
+
fs10.mkdirSync(extractDir);
|
|
1193
|
+
const checkCancelled = () => {
|
|
1194
|
+
if (abortSignal?.aborted) throw new CancelledError();
|
|
1195
|
+
};
|
|
1196
|
+
try {
|
|
1197
|
+
progress?.report({ message: "Extracting SDK archive (this may take a while)...", increment: 0 });
|
|
1198
|
+
await extractTarball(archivePath, extractDir, 0, (p) => p.split("/").includes(osFolder));
|
|
1199
|
+
progress?.report({ message: "Extracting SDK archive (this may take a while)...", increment: 40 });
|
|
1200
|
+
checkCancelled();
|
|
1201
|
+
const osContentPath = findSdkOsDir(extractDir, osFolder);
|
|
1202
|
+
if (!osContentPath) {
|
|
1203
|
+
throw new OniroError(
|
|
1204
|
+
`No '${osFolder}' SDK components (a '${osFolder}' folder of ZIPs) found in ${archivePath}. Is it an OpenHarmony SDK archive for this OS?`
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
const { api, version } = await readSdkComponentsMeta(osContentPath);
|
|
1208
|
+
const sdkInstallDir = path10.join(sdkRoot, osFolder, api);
|
|
1209
|
+
if (fs10.existsSync(sdkInstallDir) && !opts.force) {
|
|
1210
|
+
throw new OniroError(
|
|
1211
|
+
`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.`
|
|
1212
|
+
);
|
|
1213
|
+
}
|
|
1214
|
+
fs10.mkdirSync(path10.dirname(sdkInstallDir), { recursive: true });
|
|
1215
|
+
await installComponents({ osContentPath, sdkInstallDir, progress, logger, start: 40, range: 55, checkCancelled });
|
|
1216
|
+
progress?.report({ message: "Cleaning up...", increment: 0 });
|
|
1217
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
1218
|
+
progress?.report({ message: "Cleaning up...", increment: 2 });
|
|
1219
|
+
return { api, version, dir: sdkInstallDir };
|
|
1220
|
+
} catch (err) {
|
|
1221
|
+
removeTempWorkDir(tmpDir, tmpRoot);
|
|
1222
|
+
throw toSpaceError(err, tmpRoot, what);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
function findSdkOsDir(root, osFolder, maxDepth = 4) {
|
|
1226
|
+
let level = [root];
|
|
1227
|
+
for (let depth = 0; depth < maxDepth && level.length > 0; depth++) {
|
|
1228
|
+
const next = [];
|
|
1229
|
+
for (const dir of level) {
|
|
1230
|
+
for (const entry of fs10.readdirSync(dir, { withFileTypes: true })) {
|
|
1231
|
+
if (!entry.isDirectory()) continue;
|
|
1232
|
+
const p = path10.join(dir, entry.name);
|
|
1233
|
+
if (entry.name === osFolder && fs10.readdirSync(p).some((n) => n.endsWith(".zip"))) return p;
|
|
1234
|
+
next.push(p);
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
level = next;
|
|
1238
|
+
}
|
|
1239
|
+
return void 0;
|
|
1240
|
+
}
|
|
1241
|
+
async function readSdkComponentsMeta(dir) {
|
|
1242
|
+
const zips = fs10.readdirSync(dir).filter((n) => n.endsWith(".zip")).sort((a, b) => Number(b.startsWith("ets-")) - Number(a.startsWith("ets-")));
|
|
1243
|
+
for (const name of zips) {
|
|
1244
|
+
const data = await readZipEntry(path10.join(dir, name), (e) => /^[^/]+\/oh-uni-package\.json$/.test(e));
|
|
1245
|
+
if (!data) continue;
|
|
1246
|
+
try {
|
|
1247
|
+
const pkg = JSON.parse(data.toString("utf8"));
|
|
1248
|
+
const api = String(pkg.apiVersion ?? "");
|
|
1249
|
+
if (/^\d+$/.test(api)) return { api, version: String(pkg.version ?? "") };
|
|
1250
|
+
} catch {
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
throw new OniroError("No SDK component in the archive declares a numeric apiVersion (oh-uni-package.json).");
|
|
1254
|
+
}
|
|
1154
1255
|
|
|
1155
1256
|
// src/cmdTools/install.ts
|
|
1156
1257
|
var fs11 = __toESM(require("fs"), 1);
|
|
@@ -2242,12 +2343,13 @@ async function listDevices(config, opts = {}) {
|
|
|
2242
2343
|
});
|
|
2243
2344
|
return parseDeviceList(res.stdout);
|
|
2244
2345
|
}
|
|
2346
|
+
function isUsableDevice(device) {
|
|
2347
|
+
return device.status === "Connected" || device.status === "Unknown";
|
|
2348
|
+
}
|
|
2245
2349
|
async function selectDevice(config, serial, opts = {}) {
|
|
2246
2350
|
const resolved = resolveDeviceSerial(serial);
|
|
2247
2351
|
if (resolved) return resolved;
|
|
2248
|
-
const usable = (await listDevices(config, opts)).filter(
|
|
2249
|
-
(d) => d.status === "Connected" || d.status === "Unknown"
|
|
2250
|
-
);
|
|
2352
|
+
const usable = (await listDevices(config, opts)).filter(isUsableDevice);
|
|
2251
2353
|
if (usable.length === 1) return usable[0].serial;
|
|
2252
2354
|
if (usable.length === 0) {
|
|
2253
2355
|
throw new OniroError("No connected device found. Connect a device/emulator or set ONIRO_DEVICE_SERIAL.");
|
|
@@ -2438,9 +2540,13 @@ function moduleOfHap(hapFileName) {
|
|
|
2438
2540
|
const dash = hapFileName.indexOf("-");
|
|
2439
2541
|
return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
|
|
2440
2542
|
}
|
|
2543
|
+
function isAppProjectRoot(dir) {
|
|
2544
|
+
return fs17.existsSync(path18.join(dir, "AppScope", "app.json5"));
|
|
2545
|
+
}
|
|
2441
2546
|
async function discoverHaps(opts) {
|
|
2442
2547
|
const { projectDir } = opts;
|
|
2443
2548
|
const maxDepth = opts.maxDepth ?? 8;
|
|
2549
|
+
const skipNestedProjects = isAppProjectRoot(projectDir);
|
|
2444
2550
|
const result = {};
|
|
2445
2551
|
const walk = async (dir, depth) => {
|
|
2446
2552
|
if (depth > maxDepth) return;
|
|
@@ -2449,6 +2555,7 @@ async function discoverHaps(opts) {
|
|
|
2449
2555
|
const full = path18.join(dir, e.name);
|
|
2450
2556
|
if (e.isDirectory()) {
|
|
2451
2557
|
if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
|
|
2558
|
+
if (skipNestedProjects && isAppProjectRoot(full)) continue;
|
|
2452
2559
|
await walk(full, depth + 1);
|
|
2453
2560
|
} else if (e.isFile() && e.name.endsWith(".hap")) {
|
|
2454
2561
|
const moduleName = moduleOfHap(e.name);
|
|
@@ -3640,6 +3747,54 @@ async function resolveProcessId(config, bundle, deviceSerial) {
|
|
|
3640
3747
|
const proc = await findRunningProcess({ config, bundle, deviceSerial });
|
|
3641
3748
|
return proc?.pid;
|
|
3642
3749
|
}
|
|
3750
|
+
async function readDeviceClock(config, deviceSerial) {
|
|
3751
|
+
try {
|
|
3752
|
+
const res = await shell({ config, command: "date +%Y-%m-%dT%H:%M:%S", deviceSerial, timeoutMs: 1e4 });
|
|
3753
|
+
const m = res.code === 0 ? /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/.exec(res.stdout) : null;
|
|
3754
|
+
if (!m) return null;
|
|
3755
|
+
const [year, month, day, hour, minute, second] = m.slice(1).map(Number);
|
|
3756
|
+
return Date.UTC(year, month - 1, day, hour, minute, second);
|
|
3757
|
+
} catch {
|
|
3758
|
+
return null;
|
|
3759
|
+
}
|
|
3760
|
+
}
|
|
3761
|
+
function hilogTimeMs(time, referenceMs) {
|
|
3762
|
+
const m = /^(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})\.(\d{3})$/.exec(time);
|
|
3763
|
+
if (!m) return null;
|
|
3764
|
+
const [month, day, hour, minute, second, ms] = m.slice(1).map(Number);
|
|
3765
|
+
const year = new Date(referenceMs).getUTCFullYear();
|
|
3766
|
+
let best = null;
|
|
3767
|
+
for (const y of [year - 1, year, year + 1]) {
|
|
3768
|
+
const t = Date.UTC(y, month - 1, day, hour, minute, second, ms);
|
|
3769
|
+
if (best === null || Math.abs(t - referenceMs) < Math.abs(best - referenceMs)) best = t;
|
|
3770
|
+
}
|
|
3771
|
+
return best;
|
|
3772
|
+
}
|
|
3773
|
+
async function recentEntryFilter(opts) {
|
|
3774
|
+
const passAll = { test: () => true, afterReconnect: async () => {
|
|
3775
|
+
} };
|
|
3776
|
+
const lookbackMs = opts.lookbackMs ?? 0;
|
|
3777
|
+
if (lookbackMs === Infinity) return passAll;
|
|
3778
|
+
const startedAt = Date.now();
|
|
3779
|
+
const now = await readDeviceClock(opts.config, opts.deviceSerial);
|
|
3780
|
+
if (now === null) {
|
|
3781
|
+
opts.logger.warn("Could not read the device clock, so lines already in the log buffer can match too.");
|
|
3782
|
+
return passAll;
|
|
3783
|
+
}
|
|
3784
|
+
let since = now - (Date.now() - startedAt) - lookbackMs;
|
|
3785
|
+
return {
|
|
3786
|
+
test: (entry) => {
|
|
3787
|
+
if (since === null) return true;
|
|
3788
|
+
const t = hilogTimeMs(entry.time, now);
|
|
3789
|
+
return t === null || t >= since;
|
|
3790
|
+
},
|
|
3791
|
+
afterReconnect: async () => {
|
|
3792
|
+
if (since === null) return;
|
|
3793
|
+
const later = await readDeviceClock(opts.config, opts.deviceSerial);
|
|
3794
|
+
if (later !== null && later < since) since = null;
|
|
3795
|
+
}
|
|
3796
|
+
};
|
|
3797
|
+
}
|
|
3643
3798
|
function waitForLog(opts) {
|
|
3644
3799
|
return new Promise((resolve7, reject) => {
|
|
3645
3800
|
const deadline = Date.now() + opts.timeoutMs;
|
|
@@ -3647,6 +3802,8 @@ function waitForLog(opts) {
|
|
|
3647
3802
|
let child = null;
|
|
3648
3803
|
let reconnectTimer;
|
|
3649
3804
|
let buf = "";
|
|
3805
|
+
let recent = { test: () => true, afterReconnect: async () => {
|
|
3806
|
+
} };
|
|
3650
3807
|
const cleanup = () => {
|
|
3651
3808
|
clearTimeout(timer);
|
|
3652
3809
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
@@ -3687,7 +3844,7 @@ function waitForLog(opts) {
|
|
|
3687
3844
|
buf = lines.pop() ?? "";
|
|
3688
3845
|
for (const line of lines) {
|
|
3689
3846
|
const entry = parseHilogLine(line);
|
|
3690
|
-
if (entry && opts.pattern.test(entryText(entry))) {
|
|
3847
|
+
if (entry && recent.test(entry) && opts.pattern.test(entryText(entry))) {
|
|
3691
3848
|
finish(entry);
|
|
3692
3849
|
return;
|
|
3693
3850
|
}
|
|
@@ -3697,13 +3854,21 @@ function waitForLog(opts) {
|
|
|
3697
3854
|
if (settled || child !== stream) return;
|
|
3698
3855
|
child = null;
|
|
3699
3856
|
if (Date.now() < deadline) {
|
|
3700
|
-
reconnectTimer = setTimeout(() => void
|
|
3857
|
+
reconnectTimer = setTimeout(() => void recent.afterReconnect().then(spawnStream).catch(failWith), 1e3);
|
|
3701
3858
|
}
|
|
3702
3859
|
};
|
|
3703
3860
|
stream.once("close", onEnd);
|
|
3704
3861
|
stream.once("error", onEnd);
|
|
3705
3862
|
};
|
|
3706
|
-
void
|
|
3863
|
+
void (async () => {
|
|
3864
|
+
recent = await recentEntryFilter({
|
|
3865
|
+
config: opts.config,
|
|
3866
|
+
deviceSerial: opts.deviceSerial,
|
|
3867
|
+
lookbackMs: opts.lookbackMs,
|
|
3868
|
+
logger: opts.logger ?? noopLogger
|
|
3869
|
+
});
|
|
3870
|
+
await spawnStream();
|
|
3871
|
+
})().catch(failWith);
|
|
3707
3872
|
});
|
|
3708
3873
|
}
|
|
3709
3874
|
function watchLog(opts) {
|
|
@@ -3712,6 +3877,8 @@ function watchLog(opts) {
|
|
|
3712
3877
|
let settled = false;
|
|
3713
3878
|
let child = null;
|
|
3714
3879
|
let buf = "";
|
|
3880
|
+
let recent = { test: () => true, afterReconnect: async () => {
|
|
3881
|
+
} };
|
|
3715
3882
|
const cleanup = () => {
|
|
3716
3883
|
clearTimeout(timer);
|
|
3717
3884
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
@@ -3735,6 +3902,13 @@ function watchLog(opts) {
|
|
|
3735
3902
|
const timer = setTimeout(done, opts.durationMs);
|
|
3736
3903
|
opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
3737
3904
|
void (async () => {
|
|
3905
|
+
recent = await recentEntryFilter({
|
|
3906
|
+
config: opts.config,
|
|
3907
|
+
deviceSerial: opts.deviceSerial,
|
|
3908
|
+
lookbackMs: opts.lookbackMs,
|
|
3909
|
+
logger: opts.logger ?? noopLogger
|
|
3910
|
+
});
|
|
3911
|
+
if (settled) return;
|
|
3738
3912
|
const processId = await resolveProcessId(opts.config, opts.bundle, opts.deviceSerial);
|
|
3739
3913
|
if (settled) return;
|
|
3740
3914
|
const stream = streamHilog({ config: opts.config, processId, domain: opts.domain, deviceSerial: opts.deviceSerial });
|
|
@@ -3745,7 +3919,7 @@ function watchLog(opts) {
|
|
|
3745
3919
|
buf = lines.pop() ?? "";
|
|
3746
3920
|
for (const line of lines) {
|
|
3747
3921
|
const entry = parseHilogLine(line);
|
|
3748
|
-
if (entry && opts.pattern.test(entryText(entry))) matches.push(entry);
|
|
3922
|
+
if (entry && recent.test(entry) && opts.pattern.test(entryText(entry))) matches.push(entry);
|
|
3749
3923
|
}
|
|
3750
3924
|
});
|
|
3751
3925
|
})().catch((err) => {
|
|
@@ -4030,6 +4204,8 @@ async function ensureOhModules(opts) {
|
|
|
4030
4204
|
}
|
|
4031
4205
|
|
|
4032
4206
|
// src/build/codelinter.ts
|
|
4207
|
+
var fs26 = __toESM(require("fs"), 1);
|
|
4208
|
+
var path26 = __toESM(require("path"), 1);
|
|
4033
4209
|
var FINDING_RE = /^(.*?):(\d+):(?:(\d+):)?\s*(error|warning|warn|suggestion|info)\b[:\s-]*(.*)$/i;
|
|
4034
4210
|
var TRAILING_CODE_RE = /[([]([\w@/.\-]+)[)\]]\s*$/;
|
|
4035
4211
|
var FILE_HEADER_RE = /^(.+\.\w+)\((\d+)\)$/;
|
|
@@ -4116,6 +4292,16 @@ function parseCodelinterReport(output) {
|
|
|
4116
4292
|
function parseCodelinterFindings(output) {
|
|
4117
4293
|
return parseCodelinterReport(output).findings;
|
|
4118
4294
|
}
|
|
4295
|
+
var PROJECT_ROOT_FILES = [
|
|
4296
|
+
["build-profile.json5"],
|
|
4297
|
+
["hvigorfile.ts", "hvigorfile.js"],
|
|
4298
|
+
[path26.join("hvigor", "hvigor-config.json5")]
|
|
4299
|
+
];
|
|
4300
|
+
function missingProjectRootFiles(projectDir) {
|
|
4301
|
+
return PROJECT_ROOT_FILES.filter((names) => !names.some((f) => fs26.existsSync(path26.join(projectDir, f)))).map(
|
|
4302
|
+
(names) => names[0]
|
|
4303
|
+
);
|
|
4304
|
+
}
|
|
4119
4305
|
async function runCodelinter(opts) {
|
|
4120
4306
|
const res = await runProcess({
|
|
4121
4307
|
command: getCmdToolsBin(opts.config, "codelinter"),
|
|
@@ -4133,7 +4319,7 @@ async function runCodelinter(opts) {
|
|
|
4133
4319
|
var DIAGNOSIS_OUTPUT_LIMIT = 2e6;
|
|
4134
4320
|
function diagnoseBuildFailure(output) {
|
|
4135
4321
|
if (/is not exported from Kit|has no exported member .*@systemapi/i.test(output)) {
|
|
4136
|
-
return
|
|
4322
|
+
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\`).`;
|
|
4137
4323
|
}
|
|
4138
4324
|
if (/00308018|SDK path does not exist|SDK license agreement is not accepted/i.test(output)) {
|
|
4139
4325
|
return "hvigor cannot find the SDK the project compiles against: check `oniro-app sdk list` against compileSdkVersion.";
|
|
@@ -4205,21 +4391,21 @@ function isValidBundleName(bundleName) {
|
|
|
4205
4391
|
}
|
|
4206
4392
|
|
|
4207
4393
|
// src/project/templates.ts
|
|
4208
|
-
var
|
|
4209
|
-
var
|
|
4394
|
+
var fs27 = __toESM(require("fs"), 1);
|
|
4395
|
+
var path27 = __toESM(require("path"), 1);
|
|
4210
4396
|
function toHumanTemplateName(folderName) {
|
|
4211
4397
|
return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
4212
4398
|
}
|
|
4213
4399
|
function listTemplates(templateRoot) {
|
|
4214
|
-
if (!
|
|
4215
|
-
const entries =
|
|
4400
|
+
if (!fs27.existsSync(templateRoot)) return [];
|
|
4401
|
+
const entries = fs27.readdirSync(templateRoot, { withFileTypes: true });
|
|
4216
4402
|
return entries.filter((e) => e.isDirectory()).map((e) => {
|
|
4217
|
-
const dir =
|
|
4218
|
-
const metaPath =
|
|
4403
|
+
const dir = path27.join(templateRoot, e.name);
|
|
4404
|
+
const metaPath = path27.join(dir, "template.json");
|
|
4219
4405
|
let meta = {};
|
|
4220
|
-
if (
|
|
4406
|
+
if (fs27.existsSync(metaPath)) {
|
|
4221
4407
|
try {
|
|
4222
|
-
meta = JSON.parse(
|
|
4408
|
+
meta = JSON.parse(fs27.readFileSync(metaPath, "utf8"));
|
|
4223
4409
|
} catch {
|
|
4224
4410
|
}
|
|
4225
4411
|
}
|
|
@@ -4234,57 +4420,57 @@ function listTemplates(templateRoot) {
|
|
|
4234
4420
|
function validateTemplateLayout(templateDir, defaultModuleName) {
|
|
4235
4421
|
const required = [
|
|
4236
4422
|
"build-profile.json5",
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4423
|
+
path27.join("AppScope", "app.json5"),
|
|
4424
|
+
path27.join(defaultModuleName, "src", "main", "module.json5"),
|
|
4425
|
+
path27.join(defaultModuleName, "oh-package.json5"),
|
|
4240
4426
|
"hvigorfile.ts"
|
|
4241
4427
|
];
|
|
4242
|
-
return required.filter((rel) => !
|
|
4428
|
+
return required.filter((rel) => !fs27.existsSync(path27.join(templateDir, rel)));
|
|
4243
4429
|
}
|
|
4244
4430
|
|
|
4245
4431
|
// src/project/createScaffold.ts
|
|
4246
|
-
var
|
|
4247
|
-
var
|
|
4432
|
+
var fs29 = __toESM(require("fs"), 1);
|
|
4433
|
+
var path28 = __toESM(require("path"), 1);
|
|
4248
4434
|
|
|
4249
4435
|
// src/project/jsonHelpers.ts
|
|
4250
|
-
var
|
|
4436
|
+
var fs28 = __toESM(require("fs"), 1);
|
|
4251
4437
|
var import_json55 = __toESM(require("json5"), 1);
|
|
4252
4438
|
function readJson5File(filePath) {
|
|
4253
|
-
return import_json55.default.parse(
|
|
4439
|
+
return import_json55.default.parse(fs28.readFileSync(filePath, "utf8"));
|
|
4254
4440
|
}
|
|
4255
4441
|
function writeJson5File(filePath, value) {
|
|
4256
|
-
|
|
4442
|
+
fs28.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
4257
4443
|
}
|
|
4258
4444
|
function readJsonFile(filePath) {
|
|
4259
|
-
return JSON.parse(
|
|
4445
|
+
return JSON.parse(fs28.readFileSync(filePath, "utf8"));
|
|
4260
4446
|
}
|
|
4261
4447
|
function writeJsonFile(filePath, value) {
|
|
4262
|
-
|
|
4448
|
+
fs28.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
4263
4449
|
}
|
|
4264
4450
|
|
|
4265
4451
|
// src/project/createScaffold.ts
|
|
4266
4452
|
var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
|
|
4267
4453
|
async function pathExists(p) {
|
|
4268
4454
|
try {
|
|
4269
|
-
await
|
|
4455
|
+
await fs29.promises.access(p);
|
|
4270
4456
|
return true;
|
|
4271
4457
|
} catch {
|
|
4272
4458
|
return false;
|
|
4273
4459
|
}
|
|
4274
4460
|
}
|
|
4275
4461
|
async function copyDirRecursive(srcDir, destDir) {
|
|
4276
|
-
await
|
|
4277
|
-
const entries = await
|
|
4462
|
+
await fs29.promises.mkdir(destDir, { recursive: true });
|
|
4463
|
+
const entries = await fs29.promises.readdir(srcDir, { withFileTypes: true });
|
|
4278
4464
|
for (const entry of entries) {
|
|
4279
|
-
const src =
|
|
4280
|
-
const dest =
|
|
4465
|
+
const src = path28.join(srcDir, entry.name);
|
|
4466
|
+
const dest = path28.join(destDir, entry.name);
|
|
4281
4467
|
if (entry.isDirectory()) {
|
|
4282
4468
|
await copyDirRecursive(src, dest);
|
|
4283
4469
|
} else if (entry.isSymbolicLink()) {
|
|
4284
4470
|
continue;
|
|
4285
4471
|
} else if (entry.isFile()) {
|
|
4286
4472
|
if (entry.name === "template.json") continue;
|
|
4287
|
-
await
|
|
4473
|
+
await fs29.promises.copyFile(src, dest);
|
|
4288
4474
|
}
|
|
4289
4475
|
}
|
|
4290
4476
|
}
|
|
@@ -4292,9 +4478,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
|
|
|
4292
4478
|
const stack = [projectDir];
|
|
4293
4479
|
while (stack.length > 0) {
|
|
4294
4480
|
const currentDir = stack.pop();
|
|
4295
|
-
const entries = await
|
|
4481
|
+
const entries = await fs29.promises.readdir(currentDir, { withFileTypes: true });
|
|
4296
4482
|
for (const entry of entries) {
|
|
4297
|
-
const fullPath =
|
|
4483
|
+
const fullPath = path28.join(currentDir, entry.name);
|
|
4298
4484
|
if (entry.isDirectory()) {
|
|
4299
4485
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
4300
4486
|
stack.push(fullPath);
|
|
@@ -4316,23 +4502,23 @@ function toJavaPropertiesPath(p) {
|
|
|
4316
4502
|
function createOrUpdateLocalProperties(projectDir, sdkDir) {
|
|
4317
4503
|
const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
|
|
4318
4504
|
`;
|
|
4319
|
-
|
|
4505
|
+
fs29.writeFileSync(path28.join(projectDir, "local.properties"), content, "utf8");
|
|
4320
4506
|
}
|
|
4321
4507
|
function renameIfExists(fromPath, toPath) {
|
|
4322
|
-
if (
|
|
4323
|
-
|
|
4508
|
+
if (fs29.existsSync(fromPath) && fromPath !== toPath) {
|
|
4509
|
+
fs29.renameSync(fromPath, toPath);
|
|
4324
4510
|
}
|
|
4325
4511
|
}
|
|
4326
4512
|
function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
4327
|
-
const appJsonPath =
|
|
4328
|
-
if (
|
|
4513
|
+
const appJsonPath = path28.join(projectDir, "AppScope", "app.json5");
|
|
4514
|
+
if (fs29.existsSync(appJsonPath)) {
|
|
4329
4515
|
const appJson = readJson5File(appJsonPath);
|
|
4330
4516
|
appJson.app = appJson.app ?? {};
|
|
4331
4517
|
appJson.app.bundleName = args.bundleName;
|
|
4332
4518
|
writeJson5File(appJsonPath, appJson);
|
|
4333
4519
|
}
|
|
4334
|
-
const stringsPath =
|
|
4335
|
-
if (
|
|
4520
|
+
const stringsPath = path28.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
|
|
4521
|
+
if (fs29.existsSync(stringsPath)) {
|
|
4336
4522
|
const strings = readJsonFile(stringsPath);
|
|
4337
4523
|
if (Array.isArray(strings.string)) {
|
|
4338
4524
|
const appName = strings.string.find((s) => s.name === "app_name");
|
|
@@ -4340,8 +4526,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
4340
4526
|
}
|
|
4341
4527
|
writeJsonFile(stringsPath, strings);
|
|
4342
4528
|
}
|
|
4343
|
-
const buildProfilePath =
|
|
4344
|
-
if (
|
|
4529
|
+
const buildProfilePath = path28.join(projectDir, "build-profile.json5");
|
|
4530
|
+
if (fs29.existsSync(buildProfilePath)) {
|
|
4345
4531
|
const buildProfile = readJson5File(buildProfilePath);
|
|
4346
4532
|
buildProfile.app = buildProfile.app ?? {};
|
|
4347
4533
|
if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
|
|
@@ -4354,23 +4540,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
4354
4540
|
}
|
|
4355
4541
|
writeJson5File(buildProfilePath, buildProfile);
|
|
4356
4542
|
}
|
|
4357
|
-
const moduleJsonPath =
|
|
4358
|
-
if (
|
|
4543
|
+
const moduleJsonPath = path28.join(projectDir, args.moduleName, "src", "main", "module.json5");
|
|
4544
|
+
if (fs29.existsSync(moduleJsonPath)) {
|
|
4359
4545
|
const moduleJson = readJson5File(moduleJsonPath);
|
|
4360
4546
|
moduleJson.module = moduleJson.module ?? {};
|
|
4361
4547
|
moduleJson.module.name = args.moduleName;
|
|
4362
4548
|
writeJson5File(moduleJsonPath, moduleJson);
|
|
4363
4549
|
}
|
|
4364
|
-
const moduleOhPackagePath =
|
|
4365
|
-
if (
|
|
4550
|
+
const moduleOhPackagePath = path28.join(projectDir, args.moduleName, "oh-package.json5");
|
|
4551
|
+
if (fs29.existsSync(moduleOhPackagePath)) {
|
|
4366
4552
|
const pkg = readJson5File(moduleOhPackagePath);
|
|
4367
4553
|
pkg.name = args.moduleName;
|
|
4368
4554
|
writeJson5File(moduleOhPackagePath, pkg);
|
|
4369
4555
|
}
|
|
4370
|
-
const vscodeDir =
|
|
4371
|
-
|
|
4556
|
+
const vscodeDir = path28.join(projectDir, ".vscode");
|
|
4557
|
+
fs29.mkdirSync(vscodeDir, { recursive: true });
|
|
4372
4558
|
const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
|
|
4373
|
-
writeJsonFile(
|
|
4559
|
+
writeJsonFile(path28.join(vscodeDir, "settings.json"), {
|
|
4374
4560
|
"oniro.hapPath": hapPath,
|
|
4375
4561
|
"files.associations": { "*.json5": "jsonc" }
|
|
4376
4562
|
});
|
|
@@ -4387,7 +4573,7 @@ async function createScaffold(opts) {
|
|
|
4387
4573
|
if (!opts.location || !await pathExists(opts.location)) {
|
|
4388
4574
|
throw new OniroError(`Location does not exist: ${opts.location}`);
|
|
4389
4575
|
}
|
|
4390
|
-
const templateDir =
|
|
4576
|
+
const templateDir = path28.join(opts.templateRoot, opts.templateId);
|
|
4391
4577
|
if (!await pathExists(templateDir)) {
|
|
4392
4578
|
throw new OniroError(`Template not found: ${templateDir}`);
|
|
4393
4579
|
}
|
|
@@ -4422,17 +4608,17 @@ async function createScaffold(opts) {
|
|
|
4422
4608
|
}
|
|
4423
4609
|
}
|
|
4424
4610
|
}
|
|
4425
|
-
const projectDir =
|
|
4611
|
+
const projectDir = path28.join(opts.location, opts.projectName);
|
|
4426
4612
|
if (await pathExists(projectDir)) {
|
|
4427
4613
|
if (!opts.overwrite) {
|
|
4428
4614
|
throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
|
|
4429
4615
|
}
|
|
4430
|
-
await
|
|
4616
|
+
await fs29.promises.rm(projectDir, { recursive: true, force: true });
|
|
4431
4617
|
}
|
|
4432
4618
|
logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
|
|
4433
4619
|
await copyDirRecursive(templateDir, projectDir);
|
|
4434
4620
|
if (moduleName !== defaultModuleName) {
|
|
4435
|
-
renameIfExists(
|
|
4621
|
+
renameIfExists(path28.join(projectDir, defaultModuleName), path28.join(projectDir, moduleName));
|
|
4436
4622
|
}
|
|
4437
4623
|
updateTemplateConfigs(
|
|
4438
4624
|
projectDir,
|
|
@@ -4449,11 +4635,11 @@ async function createScaffold(opts) {
|
|
|
4449
4635
|
}
|
|
4450
4636
|
|
|
4451
4637
|
// src/project/listModules.ts
|
|
4452
|
-
var
|
|
4453
|
-
var
|
|
4638
|
+
var fs30 = __toESM(require("fs"), 1);
|
|
4639
|
+
var path29 = __toESM(require("path"), 1);
|
|
4454
4640
|
function listModules(opts) {
|
|
4455
|
-
const buildProfile =
|
|
4456
|
-
if (!
|
|
4641
|
+
const buildProfile = path29.join(opts.projectDir, "build-profile.json5");
|
|
4642
|
+
if (!fs30.existsSync(buildProfile)) {
|
|
4457
4643
|
throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
|
|
4458
4644
|
}
|
|
4459
4645
|
const parsed = readJson5File(buildProfile);
|
|
@@ -4465,12 +4651,12 @@ function listModules(opts) {
|
|
|
4465
4651
|
}
|
|
4466
4652
|
|
|
4467
4653
|
// src/project/abilities.ts
|
|
4468
|
-
var
|
|
4469
|
-
var
|
|
4654
|
+
var fs31 = __toESM(require("fs"), 1);
|
|
4655
|
+
var path30 = __toESM(require("path"), 1);
|
|
4470
4656
|
function listAbilities(opts) {
|
|
4471
4657
|
const moduleName = opts.moduleName ?? "entry";
|
|
4472
|
-
const moduleJsonPath =
|
|
4473
|
-
if (!
|
|
4658
|
+
const moduleJsonPath = path30.join(opts.projectDir, moduleName, "src", "main", "module.json5");
|
|
4659
|
+
if (!fs31.existsSync(moduleJsonPath)) {
|
|
4474
4660
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
4475
4661
|
}
|
|
4476
4662
|
const parsed = readJson5File(moduleJsonPath);
|
|
@@ -4478,12 +4664,12 @@ function listAbilities(opts) {
|
|
|
4478
4664
|
}
|
|
4479
4665
|
|
|
4480
4666
|
// src/project/prepareSigning.ts
|
|
4481
|
-
var
|
|
4482
|
-
var
|
|
4667
|
+
var fs32 = __toESM(require("fs"), 1);
|
|
4668
|
+
var path31 = __toESM(require("path"), 1);
|
|
4483
4669
|
function hasSigningArtifacts(dir) {
|
|
4484
|
-
if (!
|
|
4485
|
-
const buildProfile =
|
|
4486
|
-
if (!
|
|
4670
|
+
if (!fs32.existsSync(path31.join(dir, "signatures"))) return false;
|
|
4671
|
+
const buildProfile = path31.join(dir, "build-profile.json5");
|
|
4672
|
+
if (!fs32.existsSync(buildProfile)) return false;
|
|
4487
4673
|
try {
|
|
4488
4674
|
const parsed = readJson5File(buildProfile);
|
|
4489
4675
|
return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
|
|
@@ -4586,8 +4772,25 @@ async function diffHapAssets(opts) {
|
|
|
4586
4772
|
}
|
|
4587
4773
|
|
|
4588
4774
|
// src/install/apply.ts
|
|
4589
|
-
var
|
|
4590
|
-
var
|
|
4775
|
+
var fs33 = __toESM(require("fs"), 1);
|
|
4776
|
+
var path32 = __toESM(require("path"), 1);
|
|
4777
|
+
|
|
4778
|
+
// src/install/hapBundleName.ts
|
|
4779
|
+
function bundleNameFromHapConfig(text) {
|
|
4780
|
+
try {
|
|
4781
|
+
const parsed = JSON.parse(text.replace(/^/, ""));
|
|
4782
|
+
const name = parsed.app?.bundleName;
|
|
4783
|
+
return typeof name === "string" && name ? name : null;
|
|
4784
|
+
} catch {
|
|
4785
|
+
return null;
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4788
|
+
async function readHapBundleName(hapPath) {
|
|
4789
|
+
const config = await readZipEntry(hapPath, (n) => n === "module.json") ?? await readZipEntry(hapPath, (n) => n === "config.json");
|
|
4790
|
+
return config ? bundleNameFromHapConfig(config.toString("utf8")) : null;
|
|
4791
|
+
}
|
|
4792
|
+
|
|
4793
|
+
// src/install/apply.ts
|
|
4591
4794
|
function decideInstallMethod(s) {
|
|
4592
4795
|
if (!s.signInfoInconsistent) return "replace";
|
|
4593
4796
|
if (s.isSystemBundle && !s.allowUninstall) return "refuse";
|
|
@@ -4608,7 +4811,7 @@ async function pidOf(config, bundle, deviceSerial) {
|
|
|
4608
4811
|
async function resolveHap(opts, logger) {
|
|
4609
4812
|
let hap;
|
|
4610
4813
|
if (opts.hapPath) {
|
|
4611
|
-
const hapPath = !
|
|
4814
|
+
const hapPath = !path32.isAbsolute(opts.hapPath) && opts.projectDir ? path32.join(opts.projectDir, opts.hapPath) : opts.hapPath;
|
|
4612
4815
|
hap = existingHapOrUnsigned(hapPath);
|
|
4613
4816
|
if (!hap) throw new OniroError(`HAP not found at ${hapPath}.`);
|
|
4614
4817
|
} else {
|
|
@@ -4617,7 +4820,7 @@ async function resolveHap(opts, logger) {
|
|
|
4617
4820
|
if (!picked) throw new OniroError(`No HAP found${opts.module ? ` for module ${opts.module}` : ""}. Build first.`);
|
|
4618
4821
|
hap = { path: picked.path, fallback: !picked.signed };
|
|
4619
4822
|
}
|
|
4620
|
-
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${
|
|
4823
|
+
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path32.basename(hap.path)}.`);
|
|
4621
4824
|
return hap;
|
|
4622
4825
|
}
|
|
4623
4826
|
async function applyChanges(opts) {
|
|
@@ -4627,9 +4830,18 @@ async function applyChanges(opts) {
|
|
|
4627
4830
|
const allowUninstall = opts.allowUninstall ?? false;
|
|
4628
4831
|
const hap = await resolveHap(opts, logger);
|
|
4629
4832
|
const hapPath = hap.path;
|
|
4833
|
+
const hapBundle = await readHapBundleName(hapPath).catch((err) => {
|
|
4834
|
+
logger.debug(`bundle name check skipped: ${err.message}`);
|
|
4835
|
+
return null;
|
|
4836
|
+
});
|
|
4837
|
+
if (hapBundle && hapBundle !== bundle) {
|
|
4838
|
+
throw new OniroError(
|
|
4839
|
+
`${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.`
|
|
4840
|
+
);
|
|
4841
|
+
}
|
|
4630
4842
|
logger.info(`installing ${hapPath}`);
|
|
4631
4843
|
let assetsChanged = false;
|
|
4632
|
-
if (opts.installedHapPath &&
|
|
4844
|
+
if (opts.installedHapPath && fs33.existsSync(opts.installedHapPath)) {
|
|
4633
4845
|
try {
|
|
4634
4846
|
const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
|
|
4635
4847
|
assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
|
|
@@ -4662,7 +4874,7 @@ async function applyChanges(opts) {
|
|
|
4662
4874
|
}
|
|
4663
4875
|
if (!await isBundleInstalled({ config, bundle, deviceSerial })) {
|
|
4664
4876
|
throw new OniroError(
|
|
4665
|
-
`hdc reported ${
|
|
4877
|
+
`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).`
|
|
4666
4878
|
);
|
|
4667
4879
|
}
|
|
4668
4880
|
let postInstallPid = await pidOf(config, bundle, deviceSerial);
|
|
@@ -4739,9 +4951,9 @@ var AUTH_PATHS = {
|
|
|
4739
4951
|
};
|
|
4740
4952
|
|
|
4741
4953
|
// src/harmonyos/auth/tokenStore.ts
|
|
4742
|
-
var
|
|
4954
|
+
var fs34 = __toESM(require("fs"), 1);
|
|
4743
4955
|
var os11 = __toESM(require("os"), 1);
|
|
4744
|
-
var
|
|
4956
|
+
var path33 = __toESM(require("path"), 1);
|
|
4745
4957
|
var crypto3 = __toESM(require("crypto"), 1);
|
|
4746
4958
|
var ALGORITHM = "aes-256-gcm";
|
|
4747
4959
|
var KEY_LENGTH = 32;
|
|
@@ -4777,7 +4989,7 @@ function permissionHint(dir) {
|
|
|
4777
4989
|
}
|
|
4778
4990
|
function ensureDir(dir) {
|
|
4779
4991
|
try {
|
|
4780
|
-
|
|
4992
|
+
fs34.mkdirSync(dir, { recursive: true, mode: DIR_MODE });
|
|
4781
4993
|
} catch (err) {
|
|
4782
4994
|
if (err.code === "EACCES") {
|
|
4783
4995
|
throw new OniroError(permissionHint(dir), err);
|
|
@@ -4788,17 +5000,17 @@ function ensureDir(dir) {
|
|
|
4788
5000
|
function createTokenStore(opts) {
|
|
4789
5001
|
const logger = opts.logger ?? noopLogger;
|
|
4790
5002
|
const authDir = opts.config.get("harmonyosAuthDir", defaultPaths.harmonyosAuthDir());
|
|
4791
|
-
const tokenPath =
|
|
4792
|
-
const keyPath =
|
|
5003
|
+
const tokenPath = path33.join(authDir, TOKEN_FILE);
|
|
5004
|
+
const keyPath = path33.join(os11.homedir(), ".local", "share", "oniro-app", "keys", KEY_FILE);
|
|
4793
5005
|
function loadOrCreateKey() {
|
|
4794
|
-
if (
|
|
4795
|
-
const existing =
|
|
5006
|
+
if (fs34.existsSync(keyPath)) {
|
|
5007
|
+
const existing = fs34.readFileSync(keyPath);
|
|
4796
5008
|
if (existing.length === KEY_LENGTH) return existing;
|
|
4797
5009
|
logger.warn("[harmonyos] The token key file was malformed; regenerating (you will need to log in again).");
|
|
4798
5010
|
}
|
|
4799
|
-
ensureDir(
|
|
5011
|
+
ensureDir(path33.dirname(keyPath));
|
|
4800
5012
|
const key = crypto3.randomBytes(KEY_LENGTH);
|
|
4801
|
-
|
|
5013
|
+
fs34.writeFileSync(keyPath, key, { mode: FILE_MODE });
|
|
4802
5014
|
return key;
|
|
4803
5015
|
}
|
|
4804
5016
|
return {
|
|
@@ -4808,12 +5020,12 @@ function createTokenStore(opts) {
|
|
|
4808
5020
|
const payload = Buffer.from(JSON.stringify(session), "utf8");
|
|
4809
5021
|
const blob = encrypt2(loadOrCreateKey(), payload);
|
|
4810
5022
|
ensureDir(authDir);
|
|
4811
|
-
|
|
5023
|
+
fs34.writeFileSync(tokenPath, JSON.stringify(blob, null, 2), { mode: FILE_MODE });
|
|
4812
5024
|
},
|
|
4813
5025
|
load() {
|
|
4814
|
-
if (!
|
|
5026
|
+
if (!fs34.existsSync(tokenPath)) return null;
|
|
4815
5027
|
try {
|
|
4816
|
-
const blob = JSON.parse(
|
|
5028
|
+
const blob = JSON.parse(fs34.readFileSync(tokenPath, "utf8"));
|
|
4817
5029
|
if (!isEncryptedBlob(blob)) return null;
|
|
4818
5030
|
const { jwtToken, siteId } = JSON.parse(decrypt2(loadOrCreateKey(), blob).toString("utf8"));
|
|
4819
5031
|
return typeof jwtToken === "string" && jwtToken && typeof siteId === "string" ? { jwtToken, siteId } : null;
|
|
@@ -4825,7 +5037,7 @@ function createTokenStore(opts) {
|
|
|
4825
5037
|
}
|
|
4826
5038
|
logger.debug(`[harmonyos] Discarding unreadable token at ${tokenPath}.`);
|
|
4827
5039
|
try {
|
|
4828
|
-
|
|
5040
|
+
fs34.rmSync(tokenPath, { force: true });
|
|
4829
5041
|
} catch {
|
|
4830
5042
|
}
|
|
4831
5043
|
return null;
|
|
@@ -4833,7 +5045,7 @@ function createTokenStore(opts) {
|
|
|
4833
5045
|
},
|
|
4834
5046
|
clear() {
|
|
4835
5047
|
try {
|
|
4836
|
-
|
|
5048
|
+
fs34.rmSync(tokenPath, { force: true });
|
|
4837
5049
|
} catch (err) {
|
|
4838
5050
|
throw new OniroError(`Failed to remove ${tokenPath}.`, err);
|
|
4839
5051
|
}
|
|
@@ -5269,7 +5481,7 @@ var SIGNING_ERRORS = {
|
|
|
5269
5481
|
DEVICE_ADD: "AppGallery Connect did not register the device.",
|
|
5270
5482
|
DEVICE_LIMIT: "This team has reached its device limit. Remove an unused device in AppGallery Connect and retry.",
|
|
5271
5483
|
DEVICE_NAME_REPEAT: "A device with that name is already registered. Retry.",
|
|
5272
|
-
DEVICE_NONE: "
|
|
5484
|
+
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.",
|
|
5273
5485
|
PROFILE_ADD: "AppGallery Connect did not issue the provisioning profile.",
|
|
5274
5486
|
PROFILE_NAME_REPEAT: "A provisioning profile with that name already exists in AppGallery Connect. Retry.",
|
|
5275
5487
|
PROVISION_LIMIT: "This team has reached its debug-profile limit. Delete unused profiles in AppGallery Connect and retry.",
|
|
@@ -5314,7 +5526,7 @@ function mapAgcError(operation, statusCode, reasonPhrase, body) {
|
|
|
5314
5526
|
}
|
|
5315
5527
|
|
|
5316
5528
|
// src/harmonyos/signing/profile.ts
|
|
5317
|
-
var
|
|
5529
|
+
var fs35 = __toESM(require("fs"), 1);
|
|
5318
5530
|
var import_node_crypto3 = require("crypto");
|
|
5319
5531
|
var import_node_forge = __toESM(require("node-forge"), 1);
|
|
5320
5532
|
function extractProfileJson(buffer) {
|
|
@@ -5346,7 +5558,7 @@ function extractProfileJson(buffer) {
|
|
|
5346
5558
|
function readProvisionProfile(profilePath) {
|
|
5347
5559
|
let raw;
|
|
5348
5560
|
try {
|
|
5349
|
-
const json = extractProfileJson(
|
|
5561
|
+
const json = extractProfileJson(fs35.readFileSync(profilePath));
|
|
5350
5562
|
if (!json) return null;
|
|
5351
5563
|
raw = JSON.parse(json);
|
|
5352
5564
|
} catch {
|
|
@@ -5375,7 +5587,7 @@ function parseCertificate(pem) {
|
|
|
5375
5587
|
}
|
|
5376
5588
|
function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
|
|
5377
5589
|
try {
|
|
5378
|
-
const der = import_node_forge.default.util.createBuffer(
|
|
5590
|
+
const der = import_node_forge.default.util.createBuffer(fs35.readFileSync(p12Path).toString("binary"));
|
|
5379
5591
|
const p12 = import_node_forge.default.pkcs12.pkcs12FromAsn1(import_node_forge.default.asn1.fromDer(der), keyPwd);
|
|
5380
5592
|
const certBag = import_node_forge.default.pki.oids.certBag ?? "1.2.840.113549.1.12.10.1.3";
|
|
5381
5593
|
const wanted = certificate.publicKey.export({ type: "spki", format: "der" });
|
|
@@ -5391,7 +5603,7 @@ function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
|
|
|
5391
5603
|
}
|
|
5392
5604
|
}
|
|
5393
5605
|
function verifySigningMaterial(opts) {
|
|
5394
|
-
const pems =
|
|
5606
|
+
const pems = fs35.readFileSync(opts.cerPath, "utf8").match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g);
|
|
5395
5607
|
const chain = (pems ?? []).map(parseCertificate);
|
|
5396
5608
|
const leaf = chain.find((c) => !c.ca) ?? chain.at(-1);
|
|
5397
5609
|
if (!leaf) throw new AgcError(SIGNING_ERRORS.CERT_INVALID);
|
|
@@ -5410,14 +5622,14 @@ function verifySigningMaterial(opts) {
|
|
|
5410
5622
|
|
|
5411
5623
|
// src/harmonyos/signing/autoSign.ts
|
|
5412
5624
|
var crypto9 = __toESM(require("crypto"), 1);
|
|
5413
|
-
var
|
|
5414
|
-
var
|
|
5625
|
+
var fs40 = __toESM(require("fs"), 1);
|
|
5626
|
+
var path39 = __toESM(require("path"), 1);
|
|
5415
5627
|
var import_json57 = __toESM(require("json5"), 1);
|
|
5416
5628
|
|
|
5417
5629
|
// src/harmonyos/signing/agc.ts
|
|
5418
5630
|
var crypto6 = __toESM(require("crypto"), 1);
|
|
5419
|
-
var
|
|
5420
|
-
var
|
|
5631
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
5632
|
+
var path34 = __toESM(require("path"), 1);
|
|
5421
5633
|
var ENDPOINTS = {
|
|
5422
5634
|
CERT_LIST: "/api/cps/harmony-cert-manage/v1/cert/list",
|
|
5423
5635
|
CERT_ADD: "/api/cps/harmony-cert-manage/v1/cert/add",
|
|
@@ -5503,8 +5715,8 @@ function createAgcClient(http3, auth) {
|
|
|
5503
5715
|
if (target.sha256 && actual !== target.sha256.toLowerCase()) {
|
|
5504
5716
|
throw new ChecksumMismatchError(target.sha256, actual);
|
|
5505
5717
|
}
|
|
5506
|
-
|
|
5507
|
-
|
|
5718
|
+
fs36.mkdirSync(path34.dirname(dest), { recursive: true, mode: 448 });
|
|
5719
|
+
fs36.writeFileSync(dest, buffer, { mode: 384 });
|
|
5508
5720
|
}
|
|
5509
5721
|
};
|
|
5510
5722
|
}
|
|
@@ -5518,21 +5730,31 @@ function parseDeviceKind(stdout) {
|
|
|
5518
5730
|
}
|
|
5519
5731
|
async function collectLocalDevices(config, logger) {
|
|
5520
5732
|
const devices = [];
|
|
5733
|
+
const skipped = [];
|
|
5521
5734
|
for (const target of await listDevices(config, { logger, timeoutMs: 15e3 })) {
|
|
5522
|
-
|
|
5735
|
+
const skip = (why) => {
|
|
5736
|
+
logger.warn(`[harmonyos] ${target.serial} ${why}`);
|
|
5737
|
+
skipped.push(target.serial);
|
|
5738
|
+
};
|
|
5739
|
+
if (!isUsableDevice(target)) {
|
|
5740
|
+
skip(
|
|
5741
|
+
target.status === "Unauthorized" ? "is unauthorized; accept the debugging prompt on the device to register it." : `is ${target.status.toLowerCase()}; skipping it.`
|
|
5742
|
+
);
|
|
5743
|
+
continue;
|
|
5744
|
+
}
|
|
5523
5745
|
const shell2 = async (...args) => (await hdcExec({ config, deviceSerial: target.serial, args: ["shell", ...args], timeoutMs: 15e3, logger })).stdout;
|
|
5524
5746
|
try {
|
|
5525
5747
|
const udid = parseUdid(await shell2("bm", "get", "-u"));
|
|
5526
5748
|
if (!udid) {
|
|
5527
|
-
|
|
5749
|
+
skip("did not report a UDID (`bm get -u`), so it cannot be registered.");
|
|
5528
5750
|
continue;
|
|
5529
5751
|
}
|
|
5530
5752
|
devices.push({ serial: target.serial, udid, kind: parseDeviceKind(await shell2("getprop", "hw_sc.build.os.deviceType")) });
|
|
5531
5753
|
} catch (err) {
|
|
5532
|
-
|
|
5754
|
+
skip(`could not be read: ${err.message}`);
|
|
5533
5755
|
}
|
|
5534
5756
|
}
|
|
5535
|
-
return devices;
|
|
5757
|
+
return { devices, skipped };
|
|
5536
5758
|
}
|
|
5537
5759
|
async function registerDevices(agc, connected, logger) {
|
|
5538
5760
|
let devices = await agc.listDevices();
|
|
@@ -5545,32 +5767,27 @@ async function registerDevices(agc, connected, logger) {
|
|
|
5545
5767
|
if (unregistered.length > 0) devices = await agc.listDevices();
|
|
5546
5768
|
const deviceIds = devices.map((d) => d.id);
|
|
5547
5769
|
if (deviceIds.length === 0) throw new AgcError(SIGNING_ERRORS.DEVICE_NONE);
|
|
5548
|
-
if (connected.length === 0) {
|
|
5549
|
-
logger.warn(
|
|
5550
|
-
`[harmonyos] No device is connected; the profile will name the ${deviceIds.length} device(s) already registered to this team.`
|
|
5551
|
-
);
|
|
5552
|
-
}
|
|
5553
5770
|
return deviceIds;
|
|
5554
5771
|
}
|
|
5555
5772
|
|
|
5556
5773
|
// src/harmonyos/signing/keystore.ts
|
|
5557
5774
|
var crypto7 = __toESM(require("crypto"), 1);
|
|
5558
|
-
var
|
|
5559
|
-
var
|
|
5775
|
+
var fs38 = __toESM(require("fs"), 1);
|
|
5776
|
+
var path36 = __toESM(require("path"), 1);
|
|
5560
5777
|
|
|
5561
5778
|
// src/harmonyos/java.ts
|
|
5562
|
-
var
|
|
5563
|
-
var
|
|
5779
|
+
var fs37 = __toESM(require("fs"), 1);
|
|
5780
|
+
var path35 = __toESM(require("path"), 1);
|
|
5564
5781
|
var JAVA_BIN = process.platform === "win32" ? "java.exe" : "java";
|
|
5565
5782
|
function findJava(sdk, env = process.env) {
|
|
5566
5783
|
const candidates = [
|
|
5567
|
-
env.JAVA_HOME &&
|
|
5568
|
-
sdk &&
|
|
5784
|
+
env.JAVA_HOME && path35.join(env.JAVA_HOME, "bin", JAVA_BIN),
|
|
5785
|
+
sdk && path35.join(sdk.installRoot, "jbr", "bin", JAVA_BIN),
|
|
5569
5786
|
// macOS: the JBR is itself a bundle inside Studio's Contents.
|
|
5570
|
-
sdk &&
|
|
5571
|
-
...(env.PATH ?? "").split(
|
|
5787
|
+
sdk && path35.join(sdk.installRoot, "jbr", "Contents", "Home", "bin", JAVA_BIN),
|
|
5788
|
+
...(env.PATH ?? "").split(path35.delimiter).map((dir) => dir && path35.join(dir, JAVA_BIN))
|
|
5572
5789
|
];
|
|
5573
|
-
const found = candidates.find((c) => !!c &&
|
|
5790
|
+
const found = candidates.find((c) => !!c && fs37.existsSync(c));
|
|
5574
5791
|
if (found) return found;
|
|
5575
5792
|
throw new OniroError(
|
|
5576
5793
|
"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."
|
|
@@ -5584,13 +5801,13 @@ function redactArgs(args) {
|
|
|
5584
5801
|
return args.map((arg, i) => args[i - 1] === "-keyPwd" || args[i - 1] === "-keystorePwd" ? "******" : arg);
|
|
5585
5802
|
}
|
|
5586
5803
|
async function generateKeystoreAndCsr(opts) {
|
|
5587
|
-
const jar =
|
|
5588
|
-
if (!
|
|
5804
|
+
const jar = path36.join(opts.sdk.sdkPath, "default", "openharmony", "toolchains", "lib", "hap-sign-tool.jar");
|
|
5805
|
+
if (!fs38.existsSync(jar)) {
|
|
5589
5806
|
throw new OniroError(`hap-sign-tool.jar not found at ${jar}; the HarmonyOS SDK looks incomplete.`);
|
|
5590
5807
|
}
|
|
5591
5808
|
const java = findJava(opts.sdk);
|
|
5592
5809
|
const keyPwd = crypto7.randomBytes(12).toString("base64url").replaceAll(/[-_]/g, "");
|
|
5593
|
-
|
|
5810
|
+
fs38.mkdirSync(path36.dirname(opts.p12Path), { recursive: true, mode: 448 });
|
|
5594
5811
|
const run = async (what, args) => {
|
|
5595
5812
|
const argv = ["-jar", jar, ...args, "-keyAlias", KEY_ALIAS, "-keystoreFile", opts.p12Path, "-keystorePwd", keyPwd, "-keyPwd", keyPwd];
|
|
5596
5813
|
opts.logger.debug(`[harmonyos] ${java} ${redactArgs(argv).join(" ")}`);
|
|
@@ -5604,28 +5821,28 @@ ${detail}` : ""}`);
|
|
|
5604
5821
|
opts.logger.info("[harmonyos] Generating the local keystore and certificate signing request...");
|
|
5605
5822
|
await run("generate the key pair", ["generate-keypair", "-keyAlg", "ECC", "-keySize", "NIST-P-256"]);
|
|
5606
5823
|
await run("generate the CSR", ["generate-csr", "-subject", "CN=DebugKey", "-signAlg", SIGN_ALG, "-outFile", opts.csrPath]);
|
|
5607
|
-
return { keyPwd, csr:
|
|
5824
|
+
return { keyPwd, csr: fs38.readFileSync(opts.csrPath, "utf8") };
|
|
5608
5825
|
}
|
|
5609
5826
|
|
|
5610
5827
|
// src/harmonyos/signing/paths.ts
|
|
5611
5828
|
var crypto8 = __toESM(require("crypto"), 1);
|
|
5612
|
-
var
|
|
5829
|
+
var path37 = __toESM(require("path"), 1);
|
|
5613
5830
|
function sanitizeNamePart(raw) {
|
|
5614
5831
|
const safe = (raw?.trim() ?? "").replace(/[\\/:*?"<>|=.-]+/g, "_");
|
|
5615
5832
|
return safe.slice(0, 64) || "default";
|
|
5616
5833
|
}
|
|
5617
5834
|
function resolveSigningMaterialPaths(config, productName, projectRoot) {
|
|
5618
5835
|
const hash = crypto8.createHash("sha256").update(projectRoot, "utf8").digest("base64url").replaceAll(/[-_]/g, "");
|
|
5619
|
-
const base =
|
|
5836
|
+
const base = path37.join(
|
|
5620
5837
|
config.get("harmonyosSigningDir", defaultPaths.harmonyosSigningDir()),
|
|
5621
|
-
`${sanitizeNamePart(productName)}_${
|
|
5838
|
+
`${sanitizeNamePart(productName)}_${path37.basename(projectRoot)}_${hash}=`
|
|
5622
5839
|
);
|
|
5623
5840
|
return { p12Path: `${base}.p12`, csrPath: `${base}.csr`, cerPath: `${base}.cer`, profilePath: `${base}.p7b` };
|
|
5624
5841
|
}
|
|
5625
5842
|
|
|
5626
5843
|
// src/harmonyos/signing/project.ts
|
|
5627
|
-
var
|
|
5628
|
-
var
|
|
5844
|
+
var fs39 = __toESM(require("fs"), 1);
|
|
5845
|
+
var path38 = __toESM(require("path"), 1);
|
|
5629
5846
|
var import_json56 = __toESM(require("json5"), 1);
|
|
5630
5847
|
|
|
5631
5848
|
// src/harmonyos/signing/aclPermissionList.ts
|
|
@@ -5693,9 +5910,9 @@ var ACL_PERMISSIONS = /* @__PURE__ */ new Set([
|
|
|
5693
5910
|
|
|
5694
5911
|
// src/harmonyos/signing/project.ts
|
|
5695
5912
|
function readRequestedPermissions(moduleConfigPath) {
|
|
5696
|
-
if (!
|
|
5913
|
+
if (!fs39.existsSync(moduleConfigPath)) return [];
|
|
5697
5914
|
try {
|
|
5698
|
-
const parsed = import_json56.default.parse(
|
|
5915
|
+
const parsed = import_json56.default.parse(fs39.readFileSync(moduleConfigPath, "utf-8"));
|
|
5699
5916
|
return (parsed.module?.requestPermissions ?? []).map((p) => p?.name).filter((n) => typeof n === "string" && n.length > 0);
|
|
5700
5917
|
} catch {
|
|
5701
5918
|
return [];
|
|
@@ -5704,10 +5921,10 @@ function readRequestedPermissions(moduleConfigPath) {
|
|
|
5704
5921
|
function collectAclPermissions(projectDir, logger = noopLogger) {
|
|
5705
5922
|
const requested = /* @__PURE__ */ new Set();
|
|
5706
5923
|
for (const module2 of listModules({ projectDir })) {
|
|
5707
|
-
const moduleRoot =
|
|
5924
|
+
const moduleRoot = path38.resolve(projectDir, module2.srcPath);
|
|
5708
5925
|
for (const sourceSet of ["main", "ohosTest"]) {
|
|
5709
5926
|
for (const name of readRequestedPermissions(
|
|
5710
|
-
|
|
5927
|
+
path38.join(moduleRoot, "src", sourceSet, "module.json5")
|
|
5711
5928
|
)) {
|
|
5712
5929
|
requested.add(name);
|
|
5713
5930
|
}
|
|
@@ -5723,7 +5940,7 @@ function collectAclPermissions(projectDir, logger = noopLogger) {
|
|
|
5723
5940
|
// src/harmonyos/signing/autoSign.ts
|
|
5724
5941
|
function shouldRegenerate(input) {
|
|
5725
5942
|
if (input.force) return "--force was passed";
|
|
5726
|
-
const missing = Object.values(input.paths).find((file) => !
|
|
5943
|
+
const missing = Object.values(input.paths).find((file) => !fs40.existsSync(file));
|
|
5727
5944
|
if (missing) return `${missing} is missing`;
|
|
5728
5945
|
const config = input.buildProfile.app?.signingConfigs?.find((c) => c.name === input.productName);
|
|
5729
5946
|
if (config?.type !== "HarmonyOS" || config.material?.profile !== input.paths.profilePath) {
|
|
@@ -5762,16 +5979,16 @@ function writeSigningConfig(opts) {
|
|
|
5762
5979
|
for (const product of app.products ?? []) {
|
|
5763
5980
|
if (product.name === opts.productName) product.signingConfig = opts.productName;
|
|
5764
5981
|
}
|
|
5765
|
-
|
|
5982
|
+
fs40.writeFileSync(opts.buildProfilePath, JSON.stringify(opts.buildProfile, null, 2));
|
|
5766
5983
|
}
|
|
5767
5984
|
async function harmonyOsAutoSign(opts) {
|
|
5768
5985
|
const logger = opts.logger ?? noopLogger;
|
|
5769
5986
|
const productName = opts.productName ?? "default";
|
|
5770
|
-
const projectDir =
|
|
5771
|
-
const buildProfilePath =
|
|
5987
|
+
const projectDir = path39.resolve(opts.projectDir);
|
|
5988
|
+
const buildProfilePath = path39.join(projectDir, "build-profile.json5");
|
|
5772
5989
|
let buildProfile;
|
|
5773
5990
|
try {
|
|
5774
|
-
buildProfile = import_json57.default.parse(
|
|
5991
|
+
buildProfile = import_json57.default.parse(fs40.readFileSync(buildProfilePath, "utf-8"));
|
|
5775
5992
|
} catch (err) {
|
|
5776
5993
|
throw new OniroError(`Could not read ${buildProfilePath}: ${err.message}`, err);
|
|
5777
5994
|
}
|
|
@@ -5786,7 +6003,7 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5786
6003
|
const aclPermissions = collectAclPermissions(projectDir, logger);
|
|
5787
6004
|
const paths = resolveSigningMaterialPaths(opts.config, productName, projectDir);
|
|
5788
6005
|
logger.info(`[harmonyos] Signing ${bundleName} (product '${productName}', team ${auth.teamId}).`);
|
|
5789
|
-
const
|
|
6006
|
+
const local = await collectLocalDevices(opts.config, logger);
|
|
5790
6007
|
const result = (regenerated) => ({
|
|
5791
6008
|
bundleName,
|
|
5792
6009
|
teamId: auth.teamId,
|
|
@@ -5800,7 +6017,7 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5800
6017
|
productName,
|
|
5801
6018
|
bundleName,
|
|
5802
6019
|
teamId: auth.teamId,
|
|
5803
|
-
connectedUdids:
|
|
6020
|
+
connectedUdids: local.devices.map((d) => d.udid),
|
|
5804
6021
|
aclPermissions,
|
|
5805
6022
|
force: opts.force
|
|
5806
6023
|
});
|
|
@@ -5810,8 +6027,12 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5810
6027
|
}
|
|
5811
6028
|
logger.info(`[harmonyos] Regenerating signing material: ${reason}.`);
|
|
5812
6029
|
const agc = createAgcClient(opts.http ?? createHttpClient({ logger }), auth);
|
|
5813
|
-
const deviceIds = await registerDevices(agc,
|
|
5814
|
-
|
|
6030
|
+
const deviceIds = await registerDevices(agc, local.devices, logger);
|
|
6031
|
+
if (local.devices.length === 0) {
|
|
6032
|
+
const cause = local.skipped.length > 0 ? "No connected device could be registered" : "No device is connected";
|
|
6033
|
+
logger.warn(`[harmonyos] ${cause}; the profile will name the ${deviceIds.length} device(s) already registered to this team.`);
|
|
6034
|
+
}
|
|
6035
|
+
for (const file of Object.values(paths)) fs40.rmSync(file, { force: true });
|
|
5815
6036
|
const certName = `oniro_debug_${auth.teamId.replace(/[\\/.:]/g, "")}.cer`;
|
|
5816
6037
|
const stale = (await agc.listCertificates()).find((c) => c.certName === certName);
|
|
5817
6038
|
if (stale) {
|
|
@@ -5842,10 +6063,10 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5842
6063
|
try {
|
|
5843
6064
|
verifySigningMaterial({ ...paths, keyAlias: KEY_ALIAS, keyPwd });
|
|
5844
6065
|
} catch (err) {
|
|
5845
|
-
|
|
6066
|
+
fs40.rmSync(paths.profilePath, { force: true });
|
|
5846
6067
|
throw err;
|
|
5847
6068
|
}
|
|
5848
|
-
const materialDir =
|
|
6069
|
+
const materialDir = path39.join(path39.dirname(paths.p12Path), "material");
|
|
5849
6070
|
try {
|
|
5850
6071
|
getKey(materialDir);
|
|
5851
6072
|
} catch {
|
|
@@ -5857,7 +6078,7 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5857
6078
|
}
|
|
5858
6079
|
|
|
5859
6080
|
// src/index.ts
|
|
5860
|
-
var VERSION = "0.
|
|
6081
|
+
var VERSION = "0.15.1";
|
|
5861
6082
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5862
6083
|
0 && (module.exports = {
|
|
5863
6084
|
ALL_SDKS,
|
|
@@ -5872,6 +6093,7 @@ var VERSION = "0.14.1";
|
|
|
5872
6093
|
HUAWEI_SITES,
|
|
5873
6094
|
INSTALL_TMP_DIRNAME,
|
|
5874
6095
|
InsufficientSpaceError,
|
|
6096
|
+
OHOS_DAILY_BUILDS_URL,
|
|
5875
6097
|
OHOS_URL_BASE,
|
|
5876
6098
|
OniroError,
|
|
5877
6099
|
SIGNING_ERRORS,
|
|
@@ -5892,6 +6114,7 @@ var VERSION = "0.14.1";
|
|
|
5892
6114
|
buildHvigorwArgs,
|
|
5893
6115
|
buildInputCommand,
|
|
5894
6116
|
buildRawTouchCommand,
|
|
6117
|
+
bundleNameFromHapConfig,
|
|
5895
6118
|
captureBurst,
|
|
5896
6119
|
captureLog,
|
|
5897
6120
|
cleanCodelinterOutput,
|
|
@@ -5945,6 +6168,7 @@ var VERSION = "0.14.1";
|
|
|
5945
6168
|
findLayoutNodes,
|
|
5946
6169
|
findMissingProjectSdk,
|
|
5947
6170
|
findRunningProcess,
|
|
6171
|
+
findSdkOsDir,
|
|
5948
6172
|
flattenLayout,
|
|
5949
6173
|
forceStop,
|
|
5950
6174
|
formatBytes,
|
|
@@ -5978,16 +6202,19 @@ var VERSION = "0.14.1";
|
|
|
5978
6202
|
hdcTargetArgs,
|
|
5979
6203
|
hdcTargetArgsFor,
|
|
5980
6204
|
hideKeyboard,
|
|
6205
|
+
hilogTimeMs,
|
|
5981
6206
|
installApp,
|
|
5982
6207
|
installCmdTools,
|
|
5983
6208
|
installEmulator,
|
|
5984
6209
|
installFailureReason,
|
|
6210
|
+
installSdkFromArchive,
|
|
5985
6211
|
isBundleInstalled,
|
|
5986
6212
|
isCmdToolsInstalled,
|
|
5987
6213
|
isEmulatorInstalled,
|
|
5988
6214
|
isOutOfSpaceError,
|
|
5989
6215
|
isRamBackedPath,
|
|
5990
6216
|
isUnsignedHap,
|
|
6217
|
+
isUsableDevice,
|
|
5991
6218
|
isValidBundleName,
|
|
5992
6219
|
isValidProjectName,
|
|
5993
6220
|
killProcessTree,
|
|
@@ -5998,6 +6225,7 @@ var VERSION = "0.14.1";
|
|
|
5998
6225
|
listRunningProcesses,
|
|
5999
6226
|
listTemplates,
|
|
6000
6227
|
locateTarget,
|
|
6228
|
+
missingProjectRootFiles,
|
|
6001
6229
|
needsCmdWrapper,
|
|
6002
6230
|
nonInteractivePrompter,
|
|
6003
6231
|
noopLogger,
|
|
@@ -6021,9 +6249,11 @@ var VERSION = "0.14.1";
|
|
|
6021
6249
|
pickTarget,
|
|
6022
6250
|
prepareSigning,
|
|
6023
6251
|
pruneLayout,
|
|
6252
|
+
readHapBundleName,
|
|
6024
6253
|
readJson5File,
|
|
6025
6254
|
readJsonFile,
|
|
6026
6255
|
readProvisionProfile,
|
|
6256
|
+
readZipEntry,
|
|
6027
6257
|
reboot,
|
|
6028
6258
|
recvFile,
|
|
6029
6259
|
removeCmdTools,
|