@oniroproject/core 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -9
- package/dist/index.cjs +804 -306
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +275 -24
- package/dist/index.d.ts +275 -24
- package/dist/index.js +780 -306
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -50,7 +50,9 @@ __export(index_exports, {
|
|
|
50
50
|
TargetNotFoundError: () => TargetNotFoundError,
|
|
51
51
|
UnsupportedPlatformError: () => UnsupportedPlatformError,
|
|
52
52
|
VERSION: () => VERSION,
|
|
53
|
+
appSandboxDir: () => appSandboxDir,
|
|
53
54
|
applyChanges: () => applyChanges,
|
|
55
|
+
assertDevicePath: () => assertDevicePath,
|
|
54
56
|
assertLayoutSelector: () => assertLayoutSelector,
|
|
55
57
|
attemptHdcConnection: () => attemptHdcConnection,
|
|
56
58
|
buildCmdWrapper: () => buildCmdWrapper,
|
|
@@ -61,6 +63,8 @@ __export(index_exports, {
|
|
|
61
63
|
buildInputCommand: () => buildInputCommand,
|
|
62
64
|
buildRawTouchCommand: () => buildRawTouchCommand,
|
|
63
65
|
captureBurst: () => captureBurst,
|
|
66
|
+
captureLog: () => captureLog,
|
|
67
|
+
cleanCodelinterOutput: () => cleanCodelinterOutput,
|
|
64
68
|
consoleLogger: () => consoleLogger,
|
|
65
69
|
createHarmonyOsSession: () => createHarmonyOsSession,
|
|
66
70
|
createInstallTempDir: () => createInstallTempDir,
|
|
@@ -76,9 +80,12 @@ __export(index_exports, {
|
|
|
76
80
|
defaultPaths: () => defaultPaths,
|
|
77
81
|
describeLayoutNode: () => describeLayoutNode,
|
|
78
82
|
detectAaStartFailure: () => detectAaStartFailure,
|
|
83
|
+
detectCmdToolsFlavour: () => detectCmdToolsFlavour,
|
|
84
|
+
detectInstallFailure: () => detectInstallFailure,
|
|
79
85
|
detectProjectSdkVersion: () => detectProjectSdkVersion,
|
|
80
86
|
detectRuntimeOs: () => detectRuntimeOs,
|
|
81
87
|
detectSigningConfigNames: () => detectSigningConfigNames,
|
|
88
|
+
diagnoseBuildFailure: () => diagnoseBuildFailure,
|
|
82
89
|
diffEntryNames: () => diffEntryNames,
|
|
83
90
|
diffHapAssets: () => diffHapAssets,
|
|
84
91
|
discoverHaps: () => discoverHaps,
|
|
@@ -91,11 +98,13 @@ __export(index_exports, {
|
|
|
91
98
|
dumpWindow: () => dumpWindow,
|
|
92
99
|
encryptPwd: () => encryptPwd,
|
|
93
100
|
ensureFreeSpace: () => ensureFreeSpace,
|
|
101
|
+
ensureInstallOk: () => ensureInstallOk,
|
|
94
102
|
ensureOhModules: () => ensureOhModules,
|
|
95
103
|
ensureOk: () => ensureOk,
|
|
96
104
|
ensureRemoteOk: () => ensureRemoteOk,
|
|
97
105
|
escapeCmdArgument: () => escapeCmdArgument,
|
|
98
106
|
escapeCmdCommand: () => escapeCmdCommand,
|
|
107
|
+
existingHapOrUnsigned: () => existingHapOrUnsigned,
|
|
99
108
|
extractTarball: () => extractTarball,
|
|
100
109
|
extractZipWithProgress: () => extractZipWithProgress,
|
|
101
110
|
findAppProcessId: () => findAppProcessId,
|
|
@@ -104,6 +113,7 @@ __export(index_exports, {
|
|
|
104
113
|
findHarmonyOsSdk: () => findHarmonyOsSdk,
|
|
105
114
|
findKeyboardWindow: () => findKeyboardWindow,
|
|
106
115
|
findLayoutNodes: () => findLayoutNodes,
|
|
116
|
+
findMissingProjectSdk: () => findMissingProjectSdk,
|
|
107
117
|
findRunningProcess: () => findRunningProcess,
|
|
108
118
|
flattenLayout: () => flattenLayout,
|
|
109
119
|
forceStop: () => forceStop,
|
|
@@ -117,6 +127,7 @@ __export(index_exports, {
|
|
|
117
127
|
getDeviceInfo: () => getDeviceInfo,
|
|
118
128
|
getDisplaySize: () => getDisplaySize,
|
|
119
129
|
getEmulatorDir: () => getEmulatorDir,
|
|
130
|
+
getEmulatorStatus: () => getEmulatorStatus,
|
|
120
131
|
getFreeSpaceBytes: () => getFreeSpaceBytes,
|
|
121
132
|
getHdcPath: () => getHdcPath,
|
|
122
133
|
getHvigorwPath: () => getHvigorwPath,
|
|
@@ -132,15 +143,21 @@ __export(index_exports, {
|
|
|
132
143
|
getSupportedSdksForUi: () => getSupportedSdksForUi,
|
|
133
144
|
harmonyOsAutoSign: () => harmonyOsAutoSign,
|
|
134
145
|
harmonyOsSdkLabelForApi: () => harmonyOsSdkLabelForApi,
|
|
146
|
+
hdcClientFailure: () => hdcClientFailure,
|
|
135
147
|
hdcExec: () => hdcExec,
|
|
148
|
+
hdcTargetArgs: () => hdcTargetArgs,
|
|
149
|
+
hdcTargetArgsFor: () => hdcTargetArgsFor,
|
|
136
150
|
hideKeyboard: () => hideKeyboard,
|
|
137
151
|
installApp: () => installApp,
|
|
138
152
|
installCmdTools: () => installCmdTools,
|
|
139
153
|
installEmulator: () => installEmulator,
|
|
154
|
+
installFailureReason: () => installFailureReason,
|
|
155
|
+
isBundleInstalled: () => isBundleInstalled,
|
|
140
156
|
isCmdToolsInstalled: () => isCmdToolsInstalled,
|
|
141
157
|
isEmulatorInstalled: () => isEmulatorInstalled,
|
|
142
158
|
isOutOfSpaceError: () => isOutOfSpaceError,
|
|
143
159
|
isRamBackedPath: () => isRamBackedPath,
|
|
160
|
+
isUnsignedHap: () => isUnsignedHap,
|
|
144
161
|
isValidBundleName: () => isValidBundleName,
|
|
145
162
|
isValidProjectName: () => isValidProjectName,
|
|
146
163
|
killProcessTree: () => killProcessTree,
|
|
@@ -155,16 +172,21 @@ __export(index_exports, {
|
|
|
155
172
|
nonInteractivePrompter: () => nonInteractivePrompter,
|
|
156
173
|
noopLogger: () => noopLogger,
|
|
157
174
|
noopProgress: () => noopProgress,
|
|
175
|
+
normaliseLocalPath: () => normaliseLocalPath,
|
|
158
176
|
paramGet: () => paramGet,
|
|
177
|
+
paramGetMany: () => paramGetMany,
|
|
159
178
|
paramSet: () => paramSet,
|
|
160
179
|
parseBounds: () => parseBounds,
|
|
161
180
|
parseCodelinterFindings: () => parseCodelinterFindings,
|
|
181
|
+
parseCodelinterReport: () => parseCodelinterReport,
|
|
162
182
|
parseDeviceList: () => parseDeviceList,
|
|
163
183
|
parseHilogLine: () => parseHilogLine,
|
|
164
184
|
parseImeBundles: () => parseImeBundles,
|
|
165
185
|
parseMainAbilityFromBmDump: () => parseMainAbilityFromBmDump,
|
|
186
|
+
parseParamValues: () => parseParamValues,
|
|
166
187
|
parseRemoteExit: () => parseRemoteExit,
|
|
167
188
|
performInput: () => performInput,
|
|
189
|
+
pickHap: () => pickHap,
|
|
168
190
|
pickSigningKind: () => pickSigningKind,
|
|
169
191
|
pickTarget: () => pickTarget,
|
|
170
192
|
prepareSigning: () => prepareSigning,
|
|
@@ -179,6 +201,7 @@ __export(index_exports, {
|
|
|
179
201
|
removeSdk: () => removeSdk,
|
|
180
202
|
removeTempWorkDir: () => removeTempWorkDir,
|
|
181
203
|
requireHarmonyOsSdk: () => requireHarmonyOsSdk,
|
|
204
|
+
resolveDeviceSerial: () => resolveDeviceSerial,
|
|
182
205
|
resolveKeyEvent: () => resolveKeyEvent,
|
|
183
206
|
resolveTmpRoot: () => resolveTmpRoot,
|
|
184
207
|
runCodelinter: () => runCodelinter,
|
|
@@ -203,6 +226,7 @@ __export(index_exports, {
|
|
|
203
226
|
toLongPath: () => toLongPath,
|
|
204
227
|
toSpaceError: () => toSpaceError,
|
|
205
228
|
uninstallApp: () => uninstallApp,
|
|
229
|
+
unsignedHapRejection: () => unsignedHapRejection,
|
|
206
230
|
validateTemplateLayout: () => validateTemplateLayout,
|
|
207
231
|
verifySha256: () => verifySha256,
|
|
208
232
|
waitForBoot: () => waitForBoot,
|
|
@@ -309,14 +333,19 @@ var OniroError = class extends Error {
|
|
|
309
333
|
cause;
|
|
310
334
|
};
|
|
311
335
|
var SdkNotInstalledError = class extends OniroError {
|
|
312
|
-
|
|
313
|
-
|
|
336
|
+
/** `version` is the release that ships `api` (e.g. `6.0` for API 20), when one is known. */
|
|
337
|
+
constructor(api, expectedPath, version) {
|
|
338
|
+
super(
|
|
339
|
+
`SDK API ${api} is not installed at ${expectedPath}.` + (version ? ` Install it with \`oniro-app sdk install ${version}\`.` : "")
|
|
340
|
+
);
|
|
314
341
|
this.api = api;
|
|
315
342
|
this.expectedPath = expectedPath;
|
|
343
|
+
this.version = version;
|
|
316
344
|
this.name = "SdkNotInstalledError";
|
|
317
345
|
}
|
|
318
346
|
api;
|
|
319
347
|
expectedPath;
|
|
348
|
+
version;
|
|
320
349
|
};
|
|
321
350
|
var CmdToolsNotInstalledError = class extends OniroError {
|
|
322
351
|
constructor(expectedPath) {
|
|
@@ -592,6 +621,24 @@ function isProjectLocalHvigorwWorking(projectDir) {
|
|
|
592
621
|
var fs3 = __toESM(require("fs"), 1);
|
|
593
622
|
var path4 = __toESM(require("path"), 1);
|
|
594
623
|
var import_json5 = __toESM(require("json5"), 1);
|
|
624
|
+
function localPropertiesSdkDir(projectRoot) {
|
|
625
|
+
try {
|
|
626
|
+
const content = fs3.readFileSync(path4.join(projectRoot, "local.properties"), "utf-8");
|
|
627
|
+
const m = /^\s*sdk\.dir\s*[=:]\s*(.+?)\s*$/m.exec(content);
|
|
628
|
+
return m ? m[1].replace(/\\(.)/g, "$1") : void 0;
|
|
629
|
+
} catch {
|
|
630
|
+
return void 0;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
function findMissingProjectSdk(config, projectRoot) {
|
|
634
|
+
const api = detectProjectSdkVersion(projectRoot);
|
|
635
|
+
if (api === void 0) return null;
|
|
636
|
+
const expected = path4.join(getOhosBaseSdkHome(config), String(api));
|
|
637
|
+
if (fs3.existsSync(expected)) return null;
|
|
638
|
+
const localSdkDir = localPropertiesSdkDir(projectRoot);
|
|
639
|
+
if (localSdkDir && fs3.existsSync(path4.join(localSdkDir, String(api)))) return null;
|
|
640
|
+
return new SdkNotInstalledError(String(api), expected, ALL_SDKS.find((s) => s.api === String(api))?.version);
|
|
641
|
+
}
|
|
595
642
|
function detectProjectSdkVersion(projectRoot, logger = noopLogger) {
|
|
596
643
|
const buildProfilePath = path4.join(projectRoot, "build-profile.json5");
|
|
597
644
|
if (!fs3.existsSync(buildProfilePath)) {
|
|
@@ -777,14 +824,14 @@ var pipelineAsync = (0, import_node_util.promisify)(import_node_stream.pipeline)
|
|
|
777
824
|
async function downloadFile(opts) {
|
|
778
825
|
const { url, dest, progress, abortSignal } = opts;
|
|
779
826
|
const proto = url.startsWith("https") ? https : http;
|
|
780
|
-
return new Promise((
|
|
827
|
+
return new Promise((resolve7, reject) => {
|
|
781
828
|
const s = Math.max(0, Math.min(100, opts.start ?? 0));
|
|
782
829
|
const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));
|
|
783
830
|
let settled = false;
|
|
784
831
|
const done = (err) => {
|
|
785
832
|
if (settled) return;
|
|
786
833
|
settled = true;
|
|
787
|
-
err ? reject(err) :
|
|
834
|
+
err ? reject(err) : resolve7();
|
|
788
835
|
};
|
|
789
836
|
if (abortSignal?.aborted) {
|
|
790
837
|
done(new CancelledError("Download cancelled before start."));
|
|
@@ -1271,21 +1318,27 @@ async function installCmdTools(opts) {
|
|
|
1271
1318
|
removeTempWorkDir(tmpDir, tmpRoot);
|
|
1272
1319
|
}
|
|
1273
1320
|
}
|
|
1321
|
+
function detectCmdToolsFlavour(cmdToolsPath) {
|
|
1322
|
+
return fs11.existsSync(path12.join(cmdToolsPath, "sdk", "default", "hms")) ? "HarmonyOS" : "OpenHarmony";
|
|
1323
|
+
}
|
|
1274
1324
|
function getCmdToolsStatus(config) {
|
|
1275
1325
|
const cmdPath = getCmdToolsPath(config);
|
|
1326
|
+
const hdcPath = getHdcPath(config);
|
|
1327
|
+
const base = { path: cmdPath, hdc: { path: hdcPath, exists: fs11.existsSync(hdcPath) } };
|
|
1276
1328
|
const binDir = path12.join(cmdPath, "bin");
|
|
1277
1329
|
const candidates = os7.platform() === "win32" ? ["ohpm.exe", "ohpm.cmd", "ohpm.bat", "ohpm"] : ["ohpm"];
|
|
1278
1330
|
const bin = candidates.map((c) => path12.join(binDir, c)).find((p) => fs11.existsSync(p));
|
|
1279
1331
|
if (!bin) {
|
|
1280
|
-
return { installed: false, status: "Not installed" };
|
|
1332
|
+
return { installed: false, status: "Not installed", ...base };
|
|
1281
1333
|
}
|
|
1334
|
+
const installed = { installed: true, ...base, flavour: detectCmdToolsFlavour(cmdPath) };
|
|
1282
1335
|
try {
|
|
1283
1336
|
const versionFile = path12.join(cmdPath, "version.txt");
|
|
1284
1337
|
if (fs11.existsSync(versionFile)) {
|
|
1285
1338
|
const content = fs11.readFileSync(versionFile, "utf8");
|
|
1286
1339
|
for (const line of content.split(/\r?\n/)) {
|
|
1287
1340
|
const m = line.match(/^\s*#\s*Version:\s*(.+)$/);
|
|
1288
|
-
if (m?.[1]) return { installed
|
|
1341
|
+
if (m?.[1]) return { ...installed, status: `Installed (${m[1].trim()})` };
|
|
1289
1342
|
}
|
|
1290
1343
|
}
|
|
1291
1344
|
} catch {
|
|
@@ -1299,9 +1352,9 @@ function getCmdToolsStatus(config) {
|
|
|
1299
1352
|
});
|
|
1300
1353
|
if (res.error || res.status !== 0) throw res.error ?? new Error(`exit ${String(res.status)}`);
|
|
1301
1354
|
const version = res.stdout.trim();
|
|
1302
|
-
return { installed
|
|
1355
|
+
return { ...installed, status: `Installed (${version})` };
|
|
1303
1356
|
} catch {
|
|
1304
|
-
return { installed
|
|
1357
|
+
return { ...installed, status: "Installed (version unknown)" };
|
|
1305
1358
|
}
|
|
1306
1359
|
}
|
|
1307
1360
|
function isCmdToolsInstalled(config) {
|
|
@@ -1591,6 +1644,9 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
|
|
|
1591
1644
|
profileTemplate.acls = profileTemplate.acls ?? {};
|
|
1592
1645
|
profileTemplate.acls["allowed-acls"] = options.acls;
|
|
1593
1646
|
}
|
|
1647
|
+
if (options.appPrivilegeCapabilities !== void 0) {
|
|
1648
|
+
profileTemplate["app-privilege-capabilities"] = options.appPrivilegeCapabilities;
|
|
1649
|
+
}
|
|
1594
1650
|
fs13.writeFileSync(profileTemplatePath, JSON.stringify(profileTemplate, null, 2));
|
|
1595
1651
|
}
|
|
1596
1652
|
function generateP7bFile(projectDir, paths, logger, passwords) {
|
|
@@ -1680,6 +1736,12 @@ function updateBuildProfile(projectDir, kind, logger, passwords) {
|
|
|
1680
1736
|
storeFile: "./signatures/OpenHarmony.p12"
|
|
1681
1737
|
}
|
|
1682
1738
|
}));
|
|
1739
|
+
for (const product of buildProfile.app.products ?? []) {
|
|
1740
|
+
if (typeof product.signingConfig !== "string" || product.signingConfig === "") {
|
|
1741
|
+
product.signingConfig = configNames[0];
|
|
1742
|
+
logger.info(`[sign] Pointing a product with no signingConfig at "${configNames[0]}".`);
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1683
1745
|
fs13.writeFileSync(buildProfilePath, JSON.stringify(buildProfile, null, 2));
|
|
1684
1746
|
}
|
|
1685
1747
|
function prepareMaterialDirectory(projectDir, logger) {
|
|
@@ -1711,7 +1773,7 @@ function generateSigningConfigs(options) {
|
|
|
1711
1773
|
}
|
|
1712
1774
|
const sdkPath = path14.join(sdkHome, String(sdkVersion));
|
|
1713
1775
|
if (!fs13.existsSync(sdkPath)) {
|
|
1714
|
-
throw new
|
|
1776
|
+
throw new SdkNotInstalledError(String(sdkVersion), sdkPath, ALL_SDKS.find((s) => s.api === String(sdkVersion))?.version);
|
|
1715
1777
|
}
|
|
1716
1778
|
const paths = {
|
|
1717
1779
|
signTool: path14.join(sdkPath, "toolchains/lib/hap-sign-tool.jar"),
|
|
@@ -1723,7 +1785,11 @@ function generateSigningConfigs(options) {
|
|
|
1723
1785
|
const passwords = options.passwords ?? DEFAULT_PASSWORDS;
|
|
1724
1786
|
logger.info("[sign] Starting signing configuration generation...");
|
|
1725
1787
|
copyFilesToProject(projectDir, paths, kind, logger, options.applicationCertPath);
|
|
1726
|
-
modifyProfileTemplate(projectDir, apl, appFeature, logger, {
|
|
1788
|
+
modifyProfileTemplate(projectDir, apl, appFeature, logger, {
|
|
1789
|
+
kind,
|
|
1790
|
+
acls: options.acls,
|
|
1791
|
+
appPrivilegeCapabilities: options.appPrivilegeCapabilities
|
|
1792
|
+
});
|
|
1727
1793
|
generateP7bFile(projectDir, paths, logger, passwords);
|
|
1728
1794
|
prepareMaterialDirectory(projectDir, logger);
|
|
1729
1795
|
updateBuildProfile(projectDir, kind, logger, passwords);
|
|
@@ -1790,7 +1856,7 @@ function runProcess(opts) {
|
|
|
1790
1856
|
const { command, args, cwd, env, onOutput } = opts;
|
|
1791
1857
|
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
1792
1858
|
const { abortSignal } = opts;
|
|
1793
|
-
return new Promise((
|
|
1859
|
+
return new Promise((resolve7, reject) => {
|
|
1794
1860
|
if (abortSignal?.aborted) {
|
|
1795
1861
|
reject(new CancelledError(`Command aborted before start: ${command}`));
|
|
1796
1862
|
return;
|
|
@@ -1855,21 +1921,41 @@ ${stderr.trim()}` : "")
|
|
|
1855
1921
|
);
|
|
1856
1922
|
return;
|
|
1857
1923
|
}
|
|
1858
|
-
|
|
1924
|
+
resolve7({ code: code ?? -1, stdout, stderr });
|
|
1859
1925
|
});
|
|
1860
1926
|
});
|
|
1861
1927
|
}
|
|
1862
|
-
function
|
|
1928
|
+
function resolveDeviceSerial(explicit, env = process.env) {
|
|
1929
|
+
if (explicit && explicit !== "auto") return explicit;
|
|
1930
|
+
const fromEnv = env.ONIRO_DEVICE_SERIAL || env.DEVICE_SERIAL;
|
|
1931
|
+
return fromEnv && fromEnv !== "auto" ? fromEnv : void 0;
|
|
1932
|
+
}
|
|
1933
|
+
function hdcTargetArgs(explicit) {
|
|
1934
|
+
const serial = resolveDeviceSerial(explicit);
|
|
1935
|
+
return serial ? ["-t", serial] : [];
|
|
1936
|
+
}
|
|
1937
|
+
var HOST_COMMANDS = /* @__PURE__ */ new Set(["list", "tconn", "start", "kill", "version", "checkserver"]);
|
|
1938
|
+
function hdcTargetArgsFor(args, explicit) {
|
|
1939
|
+
if (HOST_COMMANDS.has(args[0] ?? "")) return explicit ? ["-t", explicit] : [];
|
|
1940
|
+
return hdcTargetArgs(explicit);
|
|
1941
|
+
}
|
|
1942
|
+
function hdcClientFailure(output) {
|
|
1943
|
+
const first = output.split(/\r?\n/).find((l) => l.trim() !== "")?.trim() ?? "";
|
|
1944
|
+
return first.startsWith("[Fail]") ? first : null;
|
|
1945
|
+
}
|
|
1946
|
+
async function hdcExec(opts) {
|
|
1863
1947
|
const hdc = getHdcPath(opts.config);
|
|
1864
|
-
const
|
|
1865
|
-
return runProcess({
|
|
1948
|
+
const res = await runProcess({
|
|
1866
1949
|
command: hdc,
|
|
1867
|
-
args:
|
|
1950
|
+
args: [...hdcTargetArgsFor(opts.args, opts.deviceSerial), ...opts.args],
|
|
1868
1951
|
timeoutMs: opts.timeoutMs,
|
|
1869
1952
|
abortSignal: opts.abortSignal,
|
|
1870
1953
|
onOutput: opts.onOutput,
|
|
1871
1954
|
logger: opts.logger
|
|
1872
1955
|
});
|
|
1956
|
+
if (res.code === 0 && hdcClientFailure(`${res.stdout}
|
|
1957
|
+
${res.stderr}`)) return { ...res, code: 1 };
|
|
1958
|
+
return res;
|
|
1873
1959
|
}
|
|
1874
1960
|
function shell(opts) {
|
|
1875
1961
|
const { command, ...rest } = opts;
|
|
@@ -1877,10 +1963,15 @@ function shell(opts) {
|
|
|
1877
1963
|
}
|
|
1878
1964
|
function ensureOk(result, command) {
|
|
1879
1965
|
if (result.code !== 0) {
|
|
1880
|
-
throw new CommandFailedError(command, result.code, result.stderr.trim());
|
|
1966
|
+
throw new CommandFailedError(command, result.code, withTargetHint(result.stderr.trim() || result.stdout.trim()));
|
|
1881
1967
|
}
|
|
1882
1968
|
return result;
|
|
1883
1969
|
}
|
|
1970
|
+
function withTargetHint(detail) {
|
|
1971
|
+
if (!/need connect-key|Not match target/i.test(detail)) return detail;
|
|
1972
|
+
return `${detail}
|
|
1973
|
+
More than one target is connected, or the serial is unknown: pass --device <serial> or set ONIRO_DEVICE_SERIAL to one listed by \`oniro-app devices\`.`;
|
|
1974
|
+
}
|
|
1884
1975
|
var REMOTE_RC_RE = /__ONIRO_RC=(-?\d+)__/g;
|
|
1885
1976
|
function parseRemoteExit(stdout) {
|
|
1886
1977
|
let code = null;
|
|
@@ -1897,7 +1988,7 @@ async function shellChecked(opts) {
|
|
|
1897
1988
|
}
|
|
1898
1989
|
function ensureRemoteOk(result, command) {
|
|
1899
1990
|
if (result.code !== 0) {
|
|
1900
|
-
throw new CommandFailedError(command, result.code, result.stderr.trim() || result.stdout.trim());
|
|
1991
|
+
throw new CommandFailedError(command, result.code, withTargetHint(result.stderr.trim() || result.stdout.trim()));
|
|
1901
1992
|
}
|
|
1902
1993
|
return result;
|
|
1903
1994
|
}
|
|
@@ -1983,11 +2074,11 @@ async function startEmulator(opts) {
|
|
|
1983
2074
|
fs16.writeFileSync(PID_FILE, String(child.pid));
|
|
1984
2075
|
child.unref();
|
|
1985
2076
|
logger.info(`Emulator launched (PID ${child.pid}). Logs: ${logPath}`);
|
|
1986
|
-
const earlyExit = new Promise((
|
|
1987
|
-
child.once("exit", (code) =>
|
|
1988
|
-
child.once("error", () =>
|
|
2077
|
+
const earlyExit = new Promise((resolve7) => {
|
|
2078
|
+
child.once("exit", (code) => resolve7(code));
|
|
2079
|
+
child.once("error", () => resolve7(-1));
|
|
1989
2080
|
});
|
|
1990
|
-
const liveness = new Promise((
|
|
2081
|
+
const liveness = new Promise((resolve7) => setTimeout(() => resolve7("alive"), 2e3));
|
|
1991
2082
|
const outcome = await Promise.race([earlyExit, liveness]);
|
|
1992
2083
|
if (outcome !== "alive") {
|
|
1993
2084
|
const tail = readTail(logPath, 4e3);
|
|
@@ -2067,6 +2158,43 @@ async function stopEmulator(logger = noopLogger) {
|
|
|
2067
2158
|
if (err) logger.warn(`Could not remove PID file: ${err.message}`);
|
|
2068
2159
|
});
|
|
2069
2160
|
}
|
|
2161
|
+
async function isQemuRunning(logger) {
|
|
2162
|
+
if (os8.platform() !== "win32") {
|
|
2163
|
+
try {
|
|
2164
|
+
const pid = Number(fs16.readFileSync(PID_FILE, "utf8").trim());
|
|
2165
|
+
if (Number.isFinite(pid) && pid > 0) {
|
|
2166
|
+
process.kill(pid, 0);
|
|
2167
|
+
return true;
|
|
2168
|
+
}
|
|
2169
|
+
} catch {
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
const [cmd, ...args] = os8.platform() === "win32" ? ["tasklist", "/FI", "IMAGENAME eq qemu-system-x86_64.exe", "/NH"] : ["pgrep", "-f", "qemu-system-x86_64"];
|
|
2173
|
+
try {
|
|
2174
|
+
const res = await runProcess({ command: cmd, args, timeoutMs: 1e4, logger });
|
|
2175
|
+
return os8.platform() === "win32" ? /qemu-system-x86_64/i.test(res.stdout) : res.code === 0;
|
|
2176
|
+
} catch {
|
|
2177
|
+
return false;
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
async function getEmulatorStatus(config, opts = {}) {
|
|
2181
|
+
const logger = opts.logger ?? noopLogger;
|
|
2182
|
+
const address = opts.address ?? "127.0.0.1:55555";
|
|
2183
|
+
const dir = getEmulatorDir(config);
|
|
2184
|
+
let connected = false;
|
|
2185
|
+
try {
|
|
2186
|
+
const targets = await hdcExec({ config, args: ["list", "targets", "-v"], timeoutMs: 1e4, logger });
|
|
2187
|
+
connected = targets.stdout.split("\n").some((l) => l.trim().startsWith(address) && /\bConnected\b/.test(l));
|
|
2188
|
+
} catch {
|
|
2189
|
+
}
|
|
2190
|
+
return {
|
|
2191
|
+
installed: isEmulatorInstalled(config),
|
|
2192
|
+
dir,
|
|
2193
|
+
running: await isQemuRunning(logger),
|
|
2194
|
+
address,
|
|
2195
|
+
connected
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2070
2198
|
|
|
2071
2199
|
// src/hdc/devices.ts
|
|
2072
2200
|
var STATUS_TOKENS = /* @__PURE__ */ new Set([
|
|
@@ -2105,9 +2233,8 @@ async function listDevices(config, opts = {}) {
|
|
|
2105
2233
|
return parseDeviceList(res.stdout);
|
|
2106
2234
|
}
|
|
2107
2235
|
async function selectDevice(config, serial, opts = {}) {
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
if (envSerial && envSerial !== "auto") return envSerial;
|
|
2236
|
+
const resolved = resolveDeviceSerial(serial);
|
|
2237
|
+
if (resolved) return resolved;
|
|
2111
2238
|
const usable = (await listDevices(config, opts)).filter(
|
|
2112
2239
|
(d) => d.status === "Connected" || d.status === "Unknown"
|
|
2113
2240
|
);
|
|
@@ -2121,6 +2248,7 @@ async function selectDevice(config, serial, opts = {}) {
|
|
|
2121
2248
|
}
|
|
2122
2249
|
|
|
2123
2250
|
// src/hdc/param.ts
|
|
2251
|
+
var PARAM_MISSING_RE = /^Get parameter ".*" fail!/;
|
|
2124
2252
|
async function paramGet(config, key, opts = {}) {
|
|
2125
2253
|
const res = await shell({
|
|
2126
2254
|
config,
|
|
@@ -2130,7 +2258,30 @@ async function paramGet(config, key, opts = {}) {
|
|
|
2130
2258
|
logger: opts.logger
|
|
2131
2259
|
});
|
|
2132
2260
|
ensureOk(res, `hdc shell param get ${key}`);
|
|
2133
|
-
|
|
2261
|
+
const value = res.stdout.trim();
|
|
2262
|
+
if (PARAM_MISSING_RE.test(value)) throw new OniroError(`System parameter ${key} is not set: ${value}`);
|
|
2263
|
+
return value;
|
|
2264
|
+
}
|
|
2265
|
+
var PARAM_SEPARATOR = "__ONIRO_PARAM__";
|
|
2266
|
+
function parseParamValues(keys, stdout) {
|
|
2267
|
+
const parts = stdout.split(PARAM_SEPARATOR);
|
|
2268
|
+
const values = {};
|
|
2269
|
+
keys.forEach((key, i) => {
|
|
2270
|
+
const value = parts[i]?.trim();
|
|
2271
|
+
values[key] = value && !PARAM_MISSING_RE.test(value) ? value : void 0;
|
|
2272
|
+
});
|
|
2273
|
+
return values;
|
|
2274
|
+
}
|
|
2275
|
+
async function paramGetMany(config, keys, opts = {}) {
|
|
2276
|
+
const res = await shell({
|
|
2277
|
+
config,
|
|
2278
|
+
command: keys.map((k) => `param get ${k}; echo ${PARAM_SEPARATOR}`).join("; "),
|
|
2279
|
+
deviceSerial: opts.deviceSerial,
|
|
2280
|
+
timeoutMs: opts.timeoutMs ?? 1e4,
|
|
2281
|
+
logger: opts.logger
|
|
2282
|
+
});
|
|
2283
|
+
ensureOk(res, "hdc shell param get \u2026");
|
|
2284
|
+
return parseParamValues(keys, res.stdout);
|
|
2134
2285
|
}
|
|
2135
2286
|
async function paramSet(config, key, value, opts = {}) {
|
|
2136
2287
|
const res = await shell({
|
|
@@ -2144,29 +2295,66 @@ async function paramSet(config, key, value, opts = {}) {
|
|
|
2144
2295
|
}
|
|
2145
2296
|
|
|
2146
2297
|
// src/hdc/files.ts
|
|
2298
|
+
var path17 = __toESM(require("path"), 1);
|
|
2299
|
+
function normaliseLocalPath(local) {
|
|
2300
|
+
const abs = path17.resolve(local);
|
|
2301
|
+
const long = toLongPath(abs);
|
|
2302
|
+
return long !== abs ? long : path17.join(toLongPath(path17.dirname(abs)), path17.basename(abs));
|
|
2303
|
+
}
|
|
2304
|
+
function assertDevicePath(remote) {
|
|
2305
|
+
if (/^[A-Za-z]:[\\/]/.test(remote)) {
|
|
2306
|
+
throw new OniroError(
|
|
2307
|
+
`The device path ${remote} is a Windows path. Git Bash rewrites arguments that start with /: run the command with MSYS_NO_PATHCONV=1, or from PowerShell or cmd.`
|
|
2308
|
+
);
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
function appSandboxDir(bundle) {
|
|
2312
|
+
return `/data/app/el2/100/base/${bundle}`;
|
|
2313
|
+
}
|
|
2314
|
+
function shQuote(s) {
|
|
2315
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
2316
|
+
}
|
|
2147
2317
|
async function sendFile(opts) {
|
|
2318
|
+
assertDevicePath(opts.remote);
|
|
2319
|
+
const local = normaliseLocalPath(opts.local);
|
|
2320
|
+
const sandbox = opts.bundle ? appSandboxDir(opts.bundle) : void 0;
|
|
2321
|
+
const remote = sandbox && !opts.remote.startsWith("/") ? path17.posix.join(sandbox, opts.remote) : opts.remote;
|
|
2322
|
+
if (sandbox && !remote.startsWith(`${sandbox}/`)) {
|
|
2323
|
+
throw new OniroError(`${remote} is outside the sandbox of ${opts.bundle} (${sandbox}).`);
|
|
2324
|
+
}
|
|
2325
|
+
const device = { config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger };
|
|
2326
|
+
if (sandbox) {
|
|
2327
|
+
const mkdir = `mkdir -p ${shQuote(path17.posix.dirname(remote))}`;
|
|
2328
|
+
ensureRemoteOk(await shellChecked({ ...device, command: mkdir }), `hdc shell ${mkdir}`);
|
|
2329
|
+
}
|
|
2148
2330
|
const res = await hdcExec({
|
|
2149
|
-
|
|
2150
|
-
args: ["file", "send",
|
|
2151
|
-
deviceSerial: opts.deviceSerial,
|
|
2331
|
+
...device,
|
|
2332
|
+
args: ["file", "send", local, remote],
|
|
2152
2333
|
timeoutMs: opts.timeoutMs ?? 6e5,
|
|
2153
2334
|
abortSignal: opts.abortSignal,
|
|
2154
|
-
onOutput: opts.onOutput
|
|
2155
|
-
logger: opts.logger
|
|
2335
|
+
onOutput: opts.onOutput
|
|
2156
2336
|
});
|
|
2157
|
-
ensureOk(res, `hdc file send ${
|
|
2337
|
+
ensureOk(res, `hdc file send ${local} ${remote}`);
|
|
2338
|
+
if (sandbox) {
|
|
2339
|
+
const top = path17.posix.join(sandbox, path17.posix.relative(sandbox, remote).split("/")[0]);
|
|
2340
|
+
const chown = `chown -R "$(stat -c %u:%g ${shQuote(sandbox)})" ${shQuote(top)}`;
|
|
2341
|
+
ensureRemoteOk(await shellChecked({ ...device, command: chown }), `hdc shell ${chown}`);
|
|
2342
|
+
}
|
|
2343
|
+
return remote;
|
|
2158
2344
|
}
|
|
2159
2345
|
async function recvFile(opts) {
|
|
2346
|
+
assertDevicePath(opts.remote);
|
|
2347
|
+
const local = normaliseLocalPath(opts.local);
|
|
2160
2348
|
const res = await hdcExec({
|
|
2161
2349
|
config: opts.config,
|
|
2162
|
-
args: ["file", "recv", opts.remote,
|
|
2350
|
+
args: ["file", "recv", opts.remote, local],
|
|
2163
2351
|
deviceSerial: opts.deviceSerial,
|
|
2164
2352
|
timeoutMs: opts.timeoutMs ?? 6e5,
|
|
2165
2353
|
abortSignal: opts.abortSignal,
|
|
2166
2354
|
onOutput: opts.onOutput,
|
|
2167
2355
|
logger: opts.logger
|
|
2168
2356
|
});
|
|
2169
|
-
ensureOk(res, `hdc file recv ${opts.remote} ${
|
|
2357
|
+
ensureOk(res, `hdc file recv ${opts.remote} ${local}`);
|
|
2170
2358
|
}
|
|
2171
2359
|
|
|
2172
2360
|
// src/hdc/display.ts
|
|
@@ -2186,7 +2374,7 @@ async function getDisplaySize(config, opts = {}) {
|
|
|
2186
2374
|
|
|
2187
2375
|
// src/hdc/wait.ts
|
|
2188
2376
|
function delay(ms, signal) {
|
|
2189
|
-
return new Promise((
|
|
2377
|
+
return new Promise((resolve7, reject) => {
|
|
2190
2378
|
if (signal?.aborted) {
|
|
2191
2379
|
reject(new CancelledError("Wait cancelled."));
|
|
2192
2380
|
return;
|
|
@@ -2201,7 +2389,7 @@ function delay(ms, signal) {
|
|
|
2201
2389
|
};
|
|
2202
2390
|
const timer = setTimeout(() => {
|
|
2203
2391
|
cleanup();
|
|
2204
|
-
|
|
2392
|
+
resolve7();
|
|
2205
2393
|
}, ms);
|
|
2206
2394
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2207
2395
|
});
|
|
@@ -2230,20 +2418,73 @@ async function waitForCondition(opts) {
|
|
|
2230
2418
|
}
|
|
2231
2419
|
|
|
2232
2420
|
// src/hdc/app.ts
|
|
2233
|
-
var
|
|
2421
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
2422
|
+
var path20 = __toESM(require("path"), 1);
|
|
2423
|
+
|
|
2424
|
+
// src/build/discoverHaps.ts
|
|
2425
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
2234
2426
|
var path18 = __toESM(require("path"), 1);
|
|
2427
|
+
function moduleOfHap(hapFileName) {
|
|
2428
|
+
const dash = hapFileName.indexOf("-");
|
|
2429
|
+
return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
|
|
2430
|
+
}
|
|
2431
|
+
async function discoverHaps(opts) {
|
|
2432
|
+
const { projectDir } = opts;
|
|
2433
|
+
const maxDepth = opts.maxDepth ?? 8;
|
|
2434
|
+
const result = {};
|
|
2435
|
+
const walk = async (dir, depth) => {
|
|
2436
|
+
if (depth > maxDepth) return;
|
|
2437
|
+
const entries = await fs17.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
2438
|
+
for (const e of entries) {
|
|
2439
|
+
const full = path18.join(dir, e.name);
|
|
2440
|
+
if (e.isDirectory()) {
|
|
2441
|
+
if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
|
|
2442
|
+
await walk(full, depth + 1);
|
|
2443
|
+
} else if (e.isFile() && e.name.endsWith(".hap")) {
|
|
2444
|
+
const moduleName = moduleOfHap(e.name);
|
|
2445
|
+
const bucket = result[moduleName] ??= { signed: [], unsigned: [] };
|
|
2446
|
+
if (e.name.includes("unsigned")) bucket.unsigned.push(full);
|
|
2447
|
+
else if (e.name.includes("signed")) bucket.signed.push(full);
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
};
|
|
2451
|
+
await walk(projectDir, 0);
|
|
2452
|
+
const mtime = (p) => fs17.statSync(p).mtimeMs;
|
|
2453
|
+
for (const bucket of Object.values(result)) {
|
|
2454
|
+
bucket.signed.sort((a, b) => mtime(b) - mtime(a));
|
|
2455
|
+
bucket.unsigned.sort((a, b) => mtime(b) - mtime(a));
|
|
2456
|
+
}
|
|
2457
|
+
return result;
|
|
2458
|
+
}
|
|
2459
|
+
function pickHap(haps, module2) {
|
|
2460
|
+
const pick = (name) => {
|
|
2461
|
+
const signed = haps[name]?.signed[0];
|
|
2462
|
+
if (signed) return { module: name, path: signed, signed: true };
|
|
2463
|
+
const unsigned = haps[name]?.unsigned[0];
|
|
2464
|
+
return unsigned ? { module: name, path: unsigned, signed: false } : null;
|
|
2465
|
+
};
|
|
2466
|
+
if (module2) return pick(module2);
|
|
2467
|
+
const names = Object.keys(haps);
|
|
2468
|
+
const withSigned = names.filter((n) => haps[n].signed.length > 0);
|
|
2469
|
+
const candidates = withSigned.length > 0 ? withSigned : names.filter((n) => haps[n].unsigned.length > 0);
|
|
2470
|
+
if (candidates.length === 0) return null;
|
|
2471
|
+
if (candidates.length > 1) {
|
|
2472
|
+
throw new OniroError(`Multiple modules have built HAPs (${candidates.join(", ")}). Pass a module to choose.`);
|
|
2473
|
+
}
|
|
2474
|
+
return pick(candidates[0]);
|
|
2475
|
+
}
|
|
2235
2476
|
|
|
2236
2477
|
// src/hdc/project.ts
|
|
2237
|
-
var
|
|
2238
|
-
var
|
|
2478
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
2479
|
+
var path19 = __toESM(require("path"), 1);
|
|
2239
2480
|
var import_json53 = __toESM(require("json5"), 1);
|
|
2240
2481
|
function readJson5(filePath) {
|
|
2241
|
-
const content =
|
|
2482
|
+
const content = fs18.readFileSync(filePath, "utf-8");
|
|
2242
2483
|
return import_json53.default.parse(content);
|
|
2243
2484
|
}
|
|
2244
2485
|
function getBundleName(projectDir) {
|
|
2245
|
-
const appJsonPath =
|
|
2246
|
-
if (!
|
|
2486
|
+
const appJsonPath = path19.join(projectDir, "AppScope", "app.json5");
|
|
2487
|
+
if (!fs18.existsSync(appJsonPath)) {
|
|
2247
2488
|
throw new OniroError(`Could not find app.json5 at ${appJsonPath}`);
|
|
2248
2489
|
}
|
|
2249
2490
|
const appJson = readJson5(appJsonPath);
|
|
@@ -2253,8 +2494,8 @@ function getBundleName(projectDir) {
|
|
|
2253
2494
|
return appJson.app.bundleName;
|
|
2254
2495
|
}
|
|
2255
2496
|
function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
2256
|
-
const moduleJsonPath =
|
|
2257
|
-
if (!
|
|
2497
|
+
const moduleJsonPath = path19.join(projectDir, moduleName, "src", "main", "module.json5");
|
|
2498
|
+
if (!fs18.existsSync(moduleJsonPath)) {
|
|
2258
2499
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
2259
2500
|
}
|
|
2260
2501
|
const moduleJson = readJson5(moduleJsonPath);
|
|
@@ -2274,13 +2515,67 @@ function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
|
2274
2515
|
}
|
|
2275
2516
|
|
|
2276
2517
|
// src/hdc/app.ts
|
|
2518
|
+
function detectInstallFailure(output) {
|
|
2519
|
+
return /\[Fail\]|msg:\s*error|error:\s*failed to install|code:\s*95\d{5}/i.test(output) ? output.trim() : null;
|
|
2520
|
+
}
|
|
2521
|
+
function isUnsignedHap(hapPath) {
|
|
2522
|
+
return path20.basename(hapPath).includes("unsigned");
|
|
2523
|
+
}
|
|
2524
|
+
function installFailureReason(output) {
|
|
2525
|
+
const code = /code:\s*(\d+)/i.exec(output);
|
|
2526
|
+
if (!code) return output.trim().split(/\r?\n/)[0] ?? "";
|
|
2527
|
+
const message = /error:\s*([^\r\n]+)/i.exec(output.slice(code.index + code[0].length))?.[1]?.trim().replace(/\.$/, "");
|
|
2528
|
+
return message ? `code ${code[1]}: ${message}` : `code ${code[1]}`;
|
|
2529
|
+
}
|
|
2530
|
+
function unsignedHapRejection(output, hap) {
|
|
2531
|
+
const name = path20.basename(hap.path);
|
|
2532
|
+
const reason = installFailureReason(output);
|
|
2533
|
+
const what = hap.fallback ? `No signed HAP was found, so the unsigned ${name} was tried, and the target rejected it (${reason}).` : `The target rejected the unsigned ${name} (${reason}).`;
|
|
2534
|
+
if (!/9568320|signature|pkcs7/i.test(reason)) return what;
|
|
2535
|
+
return `${what} This target installs only signed HAPs. Sign the project for it, build again, and install the signed HAP: \`oniro-app sign\` for an OpenHarmony device or the Oniro emulator, \`oniro-app sign --harmonyos\` for a HarmonyOS device.`;
|
|
2536
|
+
}
|
|
2537
|
+
function ensureInstallOk(result, command, hap) {
|
|
2538
|
+
const output = `${result.stdout}
|
|
2539
|
+
${result.stderr}`;
|
|
2540
|
+
if (hap && isUnsignedHap(hap.path) && /code:\s*95\d{5}/i.test(output)) {
|
|
2541
|
+
throw new OniroError(unsignedHapRejection(output, hap), new CommandFailedError(command, result.code || 1, output.trim()));
|
|
2542
|
+
}
|
|
2543
|
+
ensureOk(result, command);
|
|
2544
|
+
const failure = detectInstallFailure(output);
|
|
2545
|
+
if (failure) throw new CommandFailedError(command, 1, failure);
|
|
2546
|
+
return result;
|
|
2547
|
+
}
|
|
2548
|
+
function existingHapOrUnsigned(hapPath) {
|
|
2549
|
+
if (fs19.existsSync(hapPath)) return { path: hapPath };
|
|
2550
|
+
const sibling = hapPath.replace(/-signed\.hap$/i, "-unsigned.hap");
|
|
2551
|
+
return sibling !== hapPath && fs19.existsSync(sibling) ? { path: sibling, fallback: true } : void 0;
|
|
2552
|
+
}
|
|
2553
|
+
async function resolveInstallHap(opts, logger) {
|
|
2554
|
+
const warnIfFallback = (hap) => {
|
|
2555
|
+
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path20.basename(hap.path)}.`);
|
|
2556
|
+
return hap;
|
|
2557
|
+
};
|
|
2558
|
+
const configured = opts.hapPath ?? opts.config.get("hapPath", "");
|
|
2559
|
+
const relative3 = configured || defaultPaths.hapPath;
|
|
2560
|
+
const hapPath = path20.isAbsolute(relative3) ? relative3 : path20.join(opts.projectDir, relative3);
|
|
2561
|
+
if (configured) {
|
|
2562
|
+
const hap = existingHapOrUnsigned(hapPath);
|
|
2563
|
+
if (!hap) throw new OniroError(`HAP file not found at: ${hapPath}. Build the app first.`);
|
|
2564
|
+
return warnIfFallback(hap);
|
|
2565
|
+
}
|
|
2566
|
+
if (fs19.existsSync(hapPath)) return { path: hapPath };
|
|
2567
|
+
const haps = await discoverHaps({ projectDir: opts.projectDir });
|
|
2568
|
+
const anySigned = Object.values(haps).some((m) => m.signed.length > 0);
|
|
2569
|
+
const entryUnsigned = anySigned ? void 0 : existingHapOrUnsigned(hapPath);
|
|
2570
|
+
if (entryUnsigned) return warnIfFallback(entryUnsigned);
|
|
2571
|
+
const picked = pickHap(haps);
|
|
2572
|
+
if (!picked) throw new OniroError(`No HAP found under ${opts.projectDir}. Build the app first (\`oniro-app build\`).`);
|
|
2573
|
+
return warnIfFallback({ path: picked.path, fallback: !picked.signed });
|
|
2574
|
+
}
|
|
2277
2575
|
async function installApp(opts) {
|
|
2278
2576
|
const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
|
|
2279
|
-
const
|
|
2280
|
-
const hapPath =
|
|
2281
|
-
if (!fs18.existsSync(hapPath)) {
|
|
2282
|
-
throw new OniroError(`HAP file not found at: ${hapPath}. Build and sign the app first.`);
|
|
2283
|
-
}
|
|
2577
|
+
const hap = await resolveInstallHap(opts, logger);
|
|
2578
|
+
const hapPath = hap.path;
|
|
2284
2579
|
const result = await hdcExec({
|
|
2285
2580
|
config: opts.config,
|
|
2286
2581
|
args: ["install", hapPath],
|
|
@@ -2289,7 +2584,7 @@ async function installApp(opts) {
|
|
|
2289
2584
|
});
|
|
2290
2585
|
if (result.stdout.trim()) logger.info(result.stdout.trim());
|
|
2291
2586
|
if (result.stderr.trim()) logger.warn(result.stderr.trim());
|
|
2292
|
-
|
|
2587
|
+
ensureInstallOk(result, `hdc install ${hapPath}`, hap);
|
|
2293
2588
|
let bundleName = "";
|
|
2294
2589
|
try {
|
|
2295
2590
|
bundleName = getBundleName(opts.projectDir);
|
|
@@ -2297,6 +2592,18 @@ async function installApp(opts) {
|
|
|
2297
2592
|
}
|
|
2298
2593
|
return { installed: true, bundleName, hapPath, output: `${result.stdout}${result.stderr}`.trim() };
|
|
2299
2594
|
}
|
|
2595
|
+
async function isBundleInstalled(opts) {
|
|
2596
|
+
const safe = opts.bundle.replace(/'/g, `'\\''`);
|
|
2597
|
+
const res = await shell({
|
|
2598
|
+
config: opts.config,
|
|
2599
|
+
command: `bm dump -n '${safe}'`,
|
|
2600
|
+
deviceSerial: opts.deviceSerial,
|
|
2601
|
+
timeoutMs: opts.timeoutMs ?? 15e3,
|
|
2602
|
+
logger: opts.logger
|
|
2603
|
+
});
|
|
2604
|
+
ensureOk(res, `hdc shell bm dump -n ${opts.bundle}`);
|
|
2605
|
+
return res.stdout.includes("{") && !/failed to get information/i.test(res.stdout);
|
|
2606
|
+
}
|
|
2300
2607
|
function detectAaStartFailure(output) {
|
|
2301
2608
|
return /failed to start ability|Error Code:\s*\d|Error Message:/i.test(output) ? output.trim() : null;
|
|
2302
2609
|
}
|
|
@@ -2367,10 +2674,10 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2367
2674
|
const logger = options.logger ?? noopLogger;
|
|
2368
2675
|
const timeoutMs = options.timeoutMs ?? 1e3;
|
|
2369
2676
|
const hdc = getHdcPath(config);
|
|
2370
|
-
return new Promise((
|
|
2677
|
+
return new Promise((resolve7, reject) => {
|
|
2371
2678
|
let proc;
|
|
2372
2679
|
try {
|
|
2373
|
-
proc = spawnCompat(hdc, ["track-jpid"]);
|
|
2680
|
+
proc = spawnCompat(hdc, [...hdcTargetArgs(options.deviceSerial), "track-jpid"]);
|
|
2374
2681
|
} catch (err) {
|
|
2375
2682
|
reject(new OniroError(`Failed to spawn ${hdc}: ${err instanceof Error ? err.message : String(err)}`, err));
|
|
2376
2683
|
return;
|
|
@@ -2387,7 +2694,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2387
2694
|
if (options.targetProcessName && name === options.targetProcessName && !resolved) {
|
|
2388
2695
|
resolved = true;
|
|
2389
2696
|
killProcessTree(proc);
|
|
2390
|
-
|
|
2697
|
+
resolve7(pid);
|
|
2391
2698
|
return;
|
|
2392
2699
|
}
|
|
2393
2700
|
}
|
|
@@ -2408,7 +2715,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2408
2715
|
if (options.targetProcessName) {
|
|
2409
2716
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
2410
2717
|
} else {
|
|
2411
|
-
|
|
2718
|
+
resolve7(processes);
|
|
2412
2719
|
}
|
|
2413
2720
|
}, timeoutMs);
|
|
2414
2721
|
proc.on("close", () => {
|
|
@@ -2418,7 +2725,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2418
2725
|
if (options.targetProcessName) {
|
|
2419
2726
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
2420
2727
|
} else {
|
|
2421
|
-
|
|
2728
|
+
resolve7(processes);
|
|
2422
2729
|
}
|
|
2423
2730
|
});
|
|
2424
2731
|
});
|
|
@@ -2440,7 +2747,11 @@ async function findRunningProcess(opts) {
|
|
|
2440
2747
|
const pid = res.stdout.trim().split(/\s+/).filter(Boolean)[0];
|
|
2441
2748
|
if (res.code === 0 && pid && /^\d+$/.test(pid)) return { pid, name: opts.bundle };
|
|
2442
2749
|
try {
|
|
2443
|
-
const list = await listRunningProcesses(opts.config, {
|
|
2750
|
+
const list = await listRunningProcesses(opts.config, {
|
|
2751
|
+
timeoutMs: 1200,
|
|
2752
|
+
deviceSerial: opts.deviceSerial,
|
|
2753
|
+
logger: opts.logger
|
|
2754
|
+
});
|
|
2444
2755
|
if (Array.isArray(list)) {
|
|
2445
2756
|
const mine = (name) => name === opts.bundle || name.startsWith(`${opts.bundle}/`) || name.startsWith(`${opts.bundle}:`);
|
|
2446
2757
|
const match = list.find((p) => p.name === opts.bundle) ?? list.find((p) => mine(p.name));
|
|
@@ -2583,12 +2894,12 @@ async function reboot(opts) {
|
|
|
2583
2894
|
}
|
|
2584
2895
|
|
|
2585
2896
|
// src/hdc/screen.ts
|
|
2586
|
-
var
|
|
2897
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
2587
2898
|
var os9 = __toESM(require("os"), 1);
|
|
2588
|
-
var
|
|
2899
|
+
var path21 = __toESM(require("path"), 1);
|
|
2589
2900
|
var import_node_crypto = require("crypto");
|
|
2590
2901
|
function tmpName(ext) {
|
|
2591
|
-
return
|
|
2902
|
+
return path21.join(os9.tmpdir(), `oniro_screen_${(0, import_node_crypto.randomBytes)(6).toString("hex")}.${ext}`);
|
|
2592
2903
|
}
|
|
2593
2904
|
async function takeScreenshot(opts) {
|
|
2594
2905
|
const remote = "/data/local/tmp/oniro_screenshot.jpeg";
|
|
@@ -2598,11 +2909,11 @@ async function takeScreenshot(opts) {
|
|
|
2598
2909
|
const local = tmpName("jpeg");
|
|
2599
2910
|
try {
|
|
2600
2911
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
2601
|
-
const pixels = await
|
|
2912
|
+
const pixels = await fs20.promises.readFile(local);
|
|
2602
2913
|
const size = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial }) ?? { width: 0, height: 0 };
|
|
2603
2914
|
return { pixels, width: size.width, height: size.height };
|
|
2604
2915
|
} finally {
|
|
2605
|
-
|
|
2916
|
+
fs20.promises.unlink(local).catch(() => {
|
|
2606
2917
|
});
|
|
2607
2918
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
2608
2919
|
});
|
|
@@ -2621,9 +2932,9 @@ async function captureBurst(opts) {
|
|
|
2621
2932
|
const local = tmpName(`burst_${i}.jpeg`);
|
|
2622
2933
|
try {
|
|
2623
2934
|
await recvFile({ config: opts.config, remote: `${remoteDir}/f${i}.jpeg`, local, deviceSerial: opts.deviceSerial });
|
|
2624
|
-
frames.push(await
|
|
2935
|
+
frames.push(await fs20.promises.readFile(local));
|
|
2625
2936
|
} finally {
|
|
2626
|
-
|
|
2937
|
+
fs20.promises.unlink(local).catch(() => {
|
|
2627
2938
|
});
|
|
2628
2939
|
}
|
|
2629
2940
|
}
|
|
@@ -2798,9 +3109,9 @@ async function sendRawTouch(opts) {
|
|
|
2798
3109
|
}
|
|
2799
3110
|
|
|
2800
3111
|
// src/hdc/dump.ts
|
|
2801
|
-
var
|
|
3112
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
2802
3113
|
var os10 = __toESM(require("os"), 1);
|
|
2803
|
-
var
|
|
3114
|
+
var path22 = __toESM(require("path"), 1);
|
|
2804
3115
|
var import_node_crypto2 = require("crypto");
|
|
2805
3116
|
|
|
2806
3117
|
// src/hdc/ime.ts
|
|
@@ -3063,10 +3374,10 @@ async function dumpLayout(opts) {
|
|
|
3063
3374
|
if (!m) throw new OniroError(`Could not parse dumpLayout output:
|
|
3064
3375
|
${dump.stdout}`);
|
|
3065
3376
|
const remote = m[1];
|
|
3066
|
-
const local =
|
|
3377
|
+
const local = path22.join(os10.tmpdir(), `oniro_layout_${(0, import_node_crypto2.randomBytes)(6).toString("hex")}.json`);
|
|
3067
3378
|
try {
|
|
3068
3379
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
3069
|
-
const parsed = JSON.parse(await
|
|
3380
|
+
const parsed = JSON.parse(await fs21.promises.readFile(local, "utf8"));
|
|
3070
3381
|
const display = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial });
|
|
3071
3382
|
if (opts.prune === false) {
|
|
3072
3383
|
return { display, tree: parsed };
|
|
@@ -3079,7 +3390,7 @@ ${dump.stdout}`);
|
|
|
3079
3390
|
const keyboard = kb ? { shown: true, bundle: kb.bundle, ...kb.b ? { b: kb.b } : {} } : { shown: false };
|
|
3080
3391
|
return { display, tree, keyboard };
|
|
3081
3392
|
} finally {
|
|
3082
|
-
|
|
3393
|
+
fs21.promises.unlink(local).catch(() => {
|
|
3083
3394
|
});
|
|
3084
3395
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
3085
3396
|
});
|
|
@@ -3089,7 +3400,7 @@ ${dump.stdout}`);
|
|
|
3089
3400
|
// src/hdc/uiActions.ts
|
|
3090
3401
|
var FOCUS_SETTLE_MS = 400;
|
|
3091
3402
|
var KEYBOARD_SETTLE_MS = 400;
|
|
3092
|
-
var sleep = (ms) => new Promise((
|
|
3403
|
+
var sleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
3093
3404
|
function targetTree(layout) {
|
|
3094
3405
|
const kb = layout.keyboard;
|
|
3095
3406
|
return kb?.shown && kb.bundle ? withoutWindow(layout.tree, kb.bundle) : layout.tree;
|
|
@@ -3242,13 +3553,14 @@ async function waitForTarget(opts) {
|
|
|
3242
3553
|
}
|
|
3243
3554
|
|
|
3244
3555
|
// src/hdc/hilog.ts
|
|
3556
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
3245
3557
|
function setHilogLevel(opts) {
|
|
3246
3558
|
const logger = opts.logger ?? noopLogger;
|
|
3247
3559
|
const hdc = getHdcPath(opts.config);
|
|
3248
|
-
return new Promise((
|
|
3560
|
+
return new Promise((resolve7, reject) => {
|
|
3249
3561
|
let child;
|
|
3250
3562
|
try {
|
|
3251
|
-
child = spawnCompat(hdc, ["shell", "hilog", "-b", opts.level]);
|
|
3563
|
+
child = spawnCompat(hdc, [...hdcTargetArgs(opts.deviceSerial), "shell", "hilog", "-b", opts.level]);
|
|
3252
3564
|
} catch (err) {
|
|
3253
3565
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3254
3566
|
logger.error(`[hilog] failed to spawn hdc: ${msg}`);
|
|
@@ -3265,7 +3577,7 @@ function setHilogLevel(opts) {
|
|
|
3265
3577
|
});
|
|
3266
3578
|
child.once("close", (code) => {
|
|
3267
3579
|
if (code === 0) {
|
|
3268
|
-
|
|
3580
|
+
resolve7();
|
|
3269
3581
|
} else {
|
|
3270
3582
|
const msg = stderr.trim() || `hdc shell hilog -b ${opts.level} exited with code ${code}`;
|
|
3271
3583
|
logger.error(`[hilog] ${msg}`);
|
|
@@ -3276,8 +3588,7 @@ function setHilogLevel(opts) {
|
|
|
3276
3588
|
}
|
|
3277
3589
|
function streamHilog(opts) {
|
|
3278
3590
|
const hdc = getHdcPath(opts.config);
|
|
3279
|
-
const args = [];
|
|
3280
|
-
if (opts.deviceSerial) args.push("-t", opts.deviceSerial);
|
|
3591
|
+
const args = [...hdcTargetArgs(opts.deviceSerial)];
|
|
3281
3592
|
args.push("shell", "hilog");
|
|
3282
3593
|
if (opts.processId && opts.processId.trim() !== "") {
|
|
3283
3594
|
args.push("-P", opts.processId.trim());
|
|
@@ -3320,7 +3631,7 @@ async function resolveProcessId(config, bundle, deviceSerial) {
|
|
|
3320
3631
|
return proc?.pid;
|
|
3321
3632
|
}
|
|
3322
3633
|
function waitForLog(opts) {
|
|
3323
|
-
return new Promise((
|
|
3634
|
+
return new Promise((resolve7, reject) => {
|
|
3324
3635
|
const deadline = Date.now() + opts.timeoutMs;
|
|
3325
3636
|
let settled = false;
|
|
3326
3637
|
let child = null;
|
|
@@ -3339,7 +3650,7 @@ function waitForLog(opts) {
|
|
|
3339
3650
|
if (settled) return;
|
|
3340
3651
|
settled = true;
|
|
3341
3652
|
cleanup();
|
|
3342
|
-
|
|
3653
|
+
resolve7(entry);
|
|
3343
3654
|
};
|
|
3344
3655
|
const fail = (err) => {
|
|
3345
3656
|
if (settled) return;
|
|
@@ -3386,7 +3697,7 @@ function waitForLog(opts) {
|
|
|
3386
3697
|
});
|
|
3387
3698
|
}
|
|
3388
3699
|
function watchLog(opts) {
|
|
3389
|
-
return new Promise((
|
|
3700
|
+
return new Promise((resolve7, reject) => {
|
|
3390
3701
|
const matches = [];
|
|
3391
3702
|
let settled = false;
|
|
3392
3703
|
let child = null;
|
|
@@ -3403,7 +3714,7 @@ function watchLog(opts) {
|
|
|
3403
3714
|
if (settled) return;
|
|
3404
3715
|
settled = true;
|
|
3405
3716
|
cleanup();
|
|
3406
|
-
|
|
3717
|
+
resolve7(opts.dedup === false ? matches : dedupEntries(matches));
|
|
3407
3718
|
};
|
|
3408
3719
|
const onAbort = () => {
|
|
3409
3720
|
if (settled) return;
|
|
@@ -3435,6 +3746,94 @@ function watchLog(opts) {
|
|
|
3435
3746
|
});
|
|
3436
3747
|
});
|
|
3437
3748
|
}
|
|
3749
|
+
async function captureLog(opts) {
|
|
3750
|
+
const logger = opts.logger ?? noopLogger;
|
|
3751
|
+
if (opts.clear) {
|
|
3752
|
+
const res = await shell({ config: opts.config, command: "hilog -r", deviceSerial: opts.deviceSerial, timeoutMs: 1e4, logger });
|
|
3753
|
+
ensureOk(res, "hdc shell hilog -r");
|
|
3754
|
+
}
|
|
3755
|
+
const fd = fs22.openSync(opts.file, "a");
|
|
3756
|
+
let lines = 0;
|
|
3757
|
+
let reconnects = 0;
|
|
3758
|
+
try {
|
|
3759
|
+
await new Promise((resolve7, reject) => {
|
|
3760
|
+
const deadline = opts.durationMs !== void 0 ? Date.now() + opts.durationMs : Infinity;
|
|
3761
|
+
let settled = false;
|
|
3762
|
+
let child = null;
|
|
3763
|
+
let reconnectTimer;
|
|
3764
|
+
let buf = "";
|
|
3765
|
+
let open = true;
|
|
3766
|
+
const write = (line) => {
|
|
3767
|
+
if (!open || opts.pattern && !opts.pattern.test(line)) return;
|
|
3768
|
+
fs22.writeSync(fd, `${line}
|
|
3769
|
+
`);
|
|
3770
|
+
lines++;
|
|
3771
|
+
};
|
|
3772
|
+
const cleanup = () => {
|
|
3773
|
+
if (timer) clearTimeout(timer);
|
|
3774
|
+
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
3775
|
+
opts.abortSignal?.removeEventListener("abort", finish);
|
|
3776
|
+
if (buf.trim()) write(buf.trimEnd());
|
|
3777
|
+
buf = "";
|
|
3778
|
+
open = false;
|
|
3779
|
+
if (child) {
|
|
3780
|
+
child.stdout.removeAllListeners("data");
|
|
3781
|
+
killProcessTree(child);
|
|
3782
|
+
child = null;
|
|
3783
|
+
}
|
|
3784
|
+
};
|
|
3785
|
+
function finish() {
|
|
3786
|
+
if (settled) return;
|
|
3787
|
+
settled = true;
|
|
3788
|
+
cleanup();
|
|
3789
|
+
resolve7();
|
|
3790
|
+
}
|
|
3791
|
+
const fail = (err) => {
|
|
3792
|
+
if (settled) return;
|
|
3793
|
+
settled = true;
|
|
3794
|
+
cleanup();
|
|
3795
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
3796
|
+
};
|
|
3797
|
+
const timer = opts.durationMs !== void 0 ? setTimeout(finish, opts.durationMs) : void 0;
|
|
3798
|
+
if (opts.abortSignal?.aborted) {
|
|
3799
|
+
finish();
|
|
3800
|
+
return;
|
|
3801
|
+
}
|
|
3802
|
+
opts.abortSignal?.addEventListener("abort", finish, { once: true });
|
|
3803
|
+
const spawnStream = () => {
|
|
3804
|
+
if (settled) return;
|
|
3805
|
+
const stream = streamHilog({ config: opts.config, domain: opts.domain, deviceSerial: opts.deviceSerial });
|
|
3806
|
+
child = stream;
|
|
3807
|
+
stream.stdout.on("data", (d) => {
|
|
3808
|
+
buf += d.toString();
|
|
3809
|
+
const parts = buf.split(/\r?\n/);
|
|
3810
|
+
buf = parts.pop() ?? "";
|
|
3811
|
+
for (const line of parts) write(line);
|
|
3812
|
+
});
|
|
3813
|
+
const onEnd = () => {
|
|
3814
|
+
if (settled || child !== stream) return;
|
|
3815
|
+
child = null;
|
|
3816
|
+
if (Date.now() >= deadline) return;
|
|
3817
|
+
reconnects++;
|
|
3818
|
+
logger.warn(`[hilog] stream ended; reconnecting (${reconnects}).`);
|
|
3819
|
+
reconnectTimer = setTimeout(() => {
|
|
3820
|
+
try {
|
|
3821
|
+
spawnStream();
|
|
3822
|
+
} catch (err) {
|
|
3823
|
+
fail(err);
|
|
3824
|
+
}
|
|
3825
|
+
}, 2e3);
|
|
3826
|
+
};
|
|
3827
|
+
stream.once("close", onEnd);
|
|
3828
|
+
stream.once("error", onEnd);
|
|
3829
|
+
};
|
|
3830
|
+
spawnStream();
|
|
3831
|
+
});
|
|
3832
|
+
} finally {
|
|
3833
|
+
fs22.closeSync(fd);
|
|
3834
|
+
}
|
|
3835
|
+
return { file: opts.file, lines, reconnects };
|
|
3836
|
+
}
|
|
3438
3837
|
async function dumpLog(opts) {
|
|
3439
3838
|
let pipe = "hilog -x";
|
|
3440
3839
|
if (opts.domain !== void 0 && `${opts.domain}` !== "") pipe += ` -D ${opts.domain}`;
|
|
@@ -3459,17 +3858,17 @@ async function dumpLog(opts) {
|
|
|
3459
3858
|
}
|
|
3460
3859
|
|
|
3461
3860
|
// src/build/runHvigorw.ts
|
|
3462
|
-
var
|
|
3463
|
-
var
|
|
3861
|
+
var fs24 = __toESM(require("fs"), 1);
|
|
3862
|
+
var path24 = __toESM(require("path"), 1);
|
|
3464
3863
|
|
|
3465
3864
|
// src/harmonyos/target.ts
|
|
3466
|
-
var
|
|
3467
|
-
var
|
|
3865
|
+
var fs23 = __toESM(require("fs"), 1);
|
|
3866
|
+
var path23 = __toESM(require("path"), 1);
|
|
3468
3867
|
var import_json54 = __toESM(require("json5"), 1);
|
|
3469
3868
|
function detectRuntimeOs(projectDir, productName) {
|
|
3470
3869
|
let products = [];
|
|
3471
3870
|
try {
|
|
3472
|
-
const parsed = import_json54.default.parse(
|
|
3871
|
+
const parsed = import_json54.default.parse(fs23.readFileSync(path23.join(projectDir, "build-profile.json5"), "utf-8"));
|
|
3473
3872
|
if (Array.isArray(parsed.app?.products)) products = parsed.app.products;
|
|
3474
3873
|
} catch {
|
|
3475
3874
|
return "OpenHarmony";
|
|
@@ -3510,7 +3909,7 @@ function runHvigorw(opts) {
|
|
|
3510
3909
|
const { config } = opts;
|
|
3511
3910
|
const projectDir = toLongPath(opts.projectDir);
|
|
3512
3911
|
const logger = opts.logger ?? noopLogger;
|
|
3513
|
-
if (!
|
|
3912
|
+
if (!fs24.existsSync(path24.join(projectDir, "build-profile.json5"))) {
|
|
3514
3913
|
throw new OniroError(`Not an OpenHarmony project: ${projectDir} (build-profile.json5 not found).`);
|
|
3515
3914
|
}
|
|
3516
3915
|
let hvigorw;
|
|
@@ -3522,24 +3921,24 @@ function runHvigorw(opts) {
|
|
|
3522
3921
|
hvigorw = resolved.startsWith(projectDir) ? resolved : findHarmonyOsTool(sdk, "hvigorw") ?? resolved;
|
|
3523
3922
|
logger.info(`[build] Building for HarmonyOS against the SDK at ${sdk.sdkPath}.`);
|
|
3524
3923
|
} else {
|
|
3525
|
-
if (!
|
|
3924
|
+
if (!fs24.existsSync(getCmdToolsPath(config))) {
|
|
3526
3925
|
throw new CmdToolsNotInstalledError(getCmdToolsPath(config));
|
|
3527
3926
|
}
|
|
3528
3927
|
sdkEnv = { OHOS_BASE_SDK_HOME: getOhosBaseSdkHome(config) };
|
|
3529
3928
|
hvigorw = getHvigorwPath(config, projectDir);
|
|
3530
3929
|
}
|
|
3531
|
-
if (!
|
|
3930
|
+
if (!fs24.existsSync(hvigorw)) {
|
|
3532
3931
|
throw new OniroError(`hvigorw wrapper not found at ${hvigorw}.`);
|
|
3533
3932
|
}
|
|
3534
3933
|
const args = buildHvigorwArgs(opts);
|
|
3535
3934
|
if (process.platform !== "win32") {
|
|
3536
3935
|
try {
|
|
3537
|
-
|
|
3936
|
+
fs24.chmodSync(hvigorw, 493);
|
|
3538
3937
|
} catch {
|
|
3539
3938
|
}
|
|
3540
3939
|
}
|
|
3541
3940
|
const env = { ...process.env, ...sdkEnv };
|
|
3542
|
-
return new Promise((
|
|
3941
|
+
return new Promise((resolve7, reject) => {
|
|
3543
3942
|
if (opts.abortSignal?.aborted) {
|
|
3544
3943
|
reject(new CancelledError("hvigorw build cancelled."));
|
|
3545
3944
|
return;
|
|
@@ -3583,46 +3982,15 @@ function runHvigorw(opts) {
|
|
|
3583
3982
|
settled = true;
|
|
3584
3983
|
cleanup();
|
|
3585
3984
|
const exitCode = code ?? 1;
|
|
3586
|
-
if (exitCode === 0)
|
|
3985
|
+
if (exitCode === 0) resolve7({ exitCode });
|
|
3587
3986
|
else reject(new OniroError(`hvigorw exited with code ${exitCode}`));
|
|
3588
3987
|
});
|
|
3589
3988
|
});
|
|
3590
3989
|
}
|
|
3591
3990
|
|
|
3592
|
-
// src/build/discoverHaps.ts
|
|
3593
|
-
var fs23 = __toESM(require("fs"), 1);
|
|
3594
|
-
var path23 = __toESM(require("path"), 1);
|
|
3595
|
-
function moduleOfHap(hapFileName) {
|
|
3596
|
-
const dash = hapFileName.indexOf("-");
|
|
3597
|
-
return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
|
|
3598
|
-
}
|
|
3599
|
-
async function discoverHaps(opts) {
|
|
3600
|
-
const { projectDir } = opts;
|
|
3601
|
-
const maxDepth = opts.maxDepth ?? 8;
|
|
3602
|
-
const result = {};
|
|
3603
|
-
const walk = async (dir, depth) => {
|
|
3604
|
-
if (depth > maxDepth) return;
|
|
3605
|
-
const entries = await fs23.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
3606
|
-
for (const e of entries) {
|
|
3607
|
-
const full = path23.join(dir, e.name);
|
|
3608
|
-
if (e.isDirectory()) {
|
|
3609
|
-
if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
|
|
3610
|
-
await walk(full, depth + 1);
|
|
3611
|
-
} else if (e.isFile() && e.name.endsWith(".hap")) {
|
|
3612
|
-
const moduleName = moduleOfHap(e.name);
|
|
3613
|
-
const bucket = result[moduleName] ??= { signed: [], unsigned: [] };
|
|
3614
|
-
if (e.name.includes("unsigned")) bucket.unsigned.push(full);
|
|
3615
|
-
else if (e.name.includes("signed")) bucket.signed.push(full);
|
|
3616
|
-
}
|
|
3617
|
-
}
|
|
3618
|
-
};
|
|
3619
|
-
await walk(projectDir, 0);
|
|
3620
|
-
return result;
|
|
3621
|
-
}
|
|
3622
|
-
|
|
3623
3991
|
// src/build/ohpm.ts
|
|
3624
|
-
var
|
|
3625
|
-
var
|
|
3992
|
+
var fs25 = __toESM(require("fs"), 1);
|
|
3993
|
+
var path25 = __toESM(require("path"), 1);
|
|
3626
3994
|
function runOhpm(opts) {
|
|
3627
3995
|
return runProcess({
|
|
3628
3996
|
command: opts.ohpmPath ?? getOhpmPath(opts.config),
|
|
@@ -3635,7 +4003,7 @@ function runOhpm(opts) {
|
|
|
3635
4003
|
});
|
|
3636
4004
|
}
|
|
3637
4005
|
async function ensureOhModules(opts) {
|
|
3638
|
-
if (
|
|
4006
|
+
if (fs25.existsSync(path25.join(opts.projectDir, "oh_modules"))) {
|
|
3639
4007
|
return { installed: false };
|
|
3640
4008
|
}
|
|
3641
4009
|
const res = await runOhpm({
|
|
@@ -3652,23 +4020,91 @@ async function ensureOhModules(opts) {
|
|
|
3652
4020
|
}
|
|
3653
4021
|
|
|
3654
4022
|
// src/build/codelinter.ts
|
|
3655
|
-
var FINDING_RE = /^(.*?):(\d+):(
|
|
4023
|
+
var FINDING_RE = /^(.*?):(\d+):(?:(\d+):)?\s*(error|warning|warn|suggestion|info)\b[:\s-]*(.*)$/i;
|
|
3656
4024
|
var TRAILING_CODE_RE = /[([]([\w@/.\-]+)[)\]]\s*$/;
|
|
3657
|
-
|
|
4025
|
+
var FILE_HEADER_RE = /^(.+\.\w+)\((\d+)\)$/;
|
|
4026
|
+
var ROW_RE = /^(\d+):(\d+)\s+(error|warning|warn|suggestion|info)\s+(.*)$/i;
|
|
4027
|
+
var RULE_RE = /^@?[\w.-]+(?:\/[\w.-]+)+$/;
|
|
4028
|
+
var SUMMARY_RE = /Defects:\s*(\d+);\s*Errors:\s*(\d+);\s*Warns:\s*(\d+);\s*Suggestions:\s*(\d+)/i;
|
|
4029
|
+
var NOTICE_RE = /does not match that of the project|error occurred during linting|incomplete report/i;
|
|
4030
|
+
var ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]/g;
|
|
4031
|
+
function cleanCodelinterOutput(output) {
|
|
4032
|
+
return output.replace(ANSI_RE, "").split("\n").map((line) => (line.split("\r").filter((s) => s.trim() !== "").pop() ?? "").trimEnd()).join("\n");
|
|
4033
|
+
}
|
|
4034
|
+
function normaliseSeverity(s) {
|
|
4035
|
+
const lower = s.toLowerCase();
|
|
4036
|
+
return lower === "warn" ? "warning" : lower;
|
|
4037
|
+
}
|
|
4038
|
+
function parseCodelinterReport(output) {
|
|
3658
4039
|
const findings = [];
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
4040
|
+
const notices = [];
|
|
4041
|
+
let summary = null;
|
|
4042
|
+
let file = "";
|
|
4043
|
+
for (const rawLine of cleanCodelinterOutput(output).split("\n")) {
|
|
4044
|
+
const line = rawLine.trim();
|
|
4045
|
+
if (!line) continue;
|
|
4046
|
+
const row = ROW_RE.exec(line);
|
|
4047
|
+
if (row) {
|
|
4048
|
+
if (!file) continue;
|
|
4049
|
+
const columns = row[4].trim().split(/\s{2,}/);
|
|
4050
|
+
const last = columns[columns.length - 1];
|
|
4051
|
+
const code = columns.length > 1 && RULE_RE.test(last) ? last : "";
|
|
4052
|
+
const message = (code ? columns.slice(0, -1) : columns).join(" ").trim();
|
|
4053
|
+
findings.push({
|
|
4054
|
+
file,
|
|
4055
|
+
line: Number(row[1]),
|
|
4056
|
+
column: Number(row[2]),
|
|
4057
|
+
severity: normaliseSeverity(row[3]),
|
|
4058
|
+
code,
|
|
4059
|
+
message
|
|
4060
|
+
});
|
|
4061
|
+
continue;
|
|
4062
|
+
}
|
|
4063
|
+
const header = FILE_HEADER_RE.exec(line);
|
|
4064
|
+
if (header) {
|
|
4065
|
+
file = header[1];
|
|
4066
|
+
continue;
|
|
4067
|
+
}
|
|
4068
|
+
const legacy = FINDING_RE.exec(line);
|
|
4069
|
+
if (legacy) {
|
|
4070
|
+
let message = legacy[5].trim();
|
|
4071
|
+
let code = "";
|
|
4072
|
+
const codeMatch = TRAILING_CODE_RE.exec(message);
|
|
4073
|
+
if (codeMatch) {
|
|
4074
|
+
code = codeMatch[1];
|
|
4075
|
+
message = message.slice(0, codeMatch.index).trim();
|
|
4076
|
+
}
|
|
4077
|
+
const finding = {
|
|
4078
|
+
file: legacy[1].trim(),
|
|
4079
|
+
line: Number(legacy[2]),
|
|
4080
|
+
severity: normaliseSeverity(legacy[4]),
|
|
4081
|
+
code,
|
|
4082
|
+
message
|
|
4083
|
+
};
|
|
4084
|
+
if (legacy[3]) finding.column = Number(legacy[3]);
|
|
4085
|
+
findings.push(finding);
|
|
4086
|
+
continue;
|
|
3668
4087
|
}
|
|
3669
|
-
|
|
4088
|
+
const totals = SUMMARY_RE.exec(line);
|
|
4089
|
+
if (totals) {
|
|
4090
|
+
summary = {
|
|
4091
|
+
defects: Number(totals[1]),
|
|
4092
|
+
errors: Number(totals[2]),
|
|
4093
|
+
warnings: Number(totals[3]),
|
|
4094
|
+
suggestions: Number(totals[4])
|
|
4095
|
+
};
|
|
4096
|
+
continue;
|
|
4097
|
+
}
|
|
4098
|
+
if (/no defects found/i.test(line)) {
|
|
4099
|
+
summary = { defects: 0, errors: 0, warnings: 0, suggestions: 0 };
|
|
4100
|
+
continue;
|
|
4101
|
+
}
|
|
4102
|
+
if (NOTICE_RE.test(line)) notices.push(line);
|
|
3670
4103
|
}
|
|
3671
|
-
return findings;
|
|
4104
|
+
return { findings, summary, notices, incomplete: notices.length > 0 };
|
|
4105
|
+
}
|
|
4106
|
+
function parseCodelinterFindings(output) {
|
|
4107
|
+
return parseCodelinterReport(output).findings;
|
|
3672
4108
|
}
|
|
3673
4109
|
async function runCodelinter(opts) {
|
|
3674
4110
|
const res = await runProcess({
|
|
@@ -3680,16 +4116,28 @@ async function runCodelinter(opts) {
|
|
|
3680
4116
|
logger: opts.logger
|
|
3681
4117
|
});
|
|
3682
4118
|
const raw = `${res.stdout}${res.stderr}`;
|
|
3683
|
-
return { code: res.code,
|
|
4119
|
+
return { code: res.code, ...parseCodelinterReport(raw), raw: cleanCodelinterOutput(raw) };
|
|
3684
4120
|
}
|
|
3685
4121
|
|
|
3686
4122
|
// src/build/buildHap.ts
|
|
4123
|
+
var DIAGNOSIS_OUTPUT_LIMIT = 2e6;
|
|
4124
|
+
function diagnoseBuildFailure(output) {
|
|
4125
|
+
if (/is not exported from Kit|has no exported member .*@systemapi/i.test(output)) {
|
|
4126
|
+
return "The project calls system APIs (`@systemapi`), which the public SDK leaves out. Build against the full OpenHarmony SDK: unpack its components into <root>/<os>/<api> of a separate SDK root and set ONIRO_SDK_ROOT_DIR to that root. Installing such an app also needs privileged signing (`oniro-app sign --apl system_core --acls \u2026 --app-privilege-capabilities \u2026`).";
|
|
4127
|
+
}
|
|
4128
|
+
if (/00308018|SDK path does not exist|SDK license agreement is not accepted/i.test(output)) {
|
|
4129
|
+
return "hvigor cannot find the SDK the project compiles against: check `oniro-app sdk list` against compileSdkVersion.";
|
|
4130
|
+
}
|
|
4131
|
+
return void 0;
|
|
4132
|
+
}
|
|
3687
4133
|
async function buildHap(opts) {
|
|
3688
4134
|
const logger = scopedLogger(opts.logger ?? noopLogger, "build");
|
|
3689
4135
|
const warnings = [];
|
|
3690
4136
|
const start = Date.now();
|
|
3691
4137
|
const projectDir = toLongPath(opts.projectDir);
|
|
3692
4138
|
const isHarmonyOs = detectRuntimeOs(projectDir, opts.product) === "HarmonyOS";
|
|
4139
|
+
const missingSdk = isHarmonyOs ? null : findMissingProjectSdk(opts.config, projectDir);
|
|
4140
|
+
if (missingSdk) throw missingSdk;
|
|
3693
4141
|
if (opts.autoInstallDeps !== false) {
|
|
3694
4142
|
const harmonySdk = isHarmonyOs ? findHarmonyOsSdk({ config: opts.config, logger: opts.logger }) : null;
|
|
3695
4143
|
const r = await ensureOhModules({
|
|
@@ -3702,23 +4150,35 @@ async function buildHap(opts) {
|
|
|
3702
4150
|
});
|
|
3703
4151
|
if (r.installed) logger.info("ran ohpm install --all (oh_modules was missing)");
|
|
3704
4152
|
}
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
4153
|
+
let output = "";
|
|
4154
|
+
let exitCode;
|
|
4155
|
+
try {
|
|
4156
|
+
({ exitCode } = await runHvigorw({
|
|
4157
|
+
config: opts.config,
|
|
4158
|
+
projectDir,
|
|
4159
|
+
product: opts.product,
|
|
4160
|
+
module: opts.module,
|
|
4161
|
+
buildMode: opts.mode,
|
|
4162
|
+
task: opts.task,
|
|
4163
|
+
parallel: opts.parallel,
|
|
4164
|
+
abortSignal: opts.abortSignal,
|
|
4165
|
+
onOutput: (chunk, stream) => {
|
|
4166
|
+
output = (output + chunk).slice(-DIAGNOSIS_OUTPUT_LIMIT);
|
|
4167
|
+
opts.onOutput?.(chunk, stream);
|
|
4168
|
+
},
|
|
4169
|
+
logger: opts.logger
|
|
4170
|
+
}));
|
|
4171
|
+
} catch (err) {
|
|
4172
|
+
const hint = diagnoseBuildFailure(output);
|
|
4173
|
+
if (hint && err instanceof OniroError) throw new OniroError(`${err.message}
|
|
4174
|
+
${hint}`, err);
|
|
4175
|
+
throw err;
|
|
4176
|
+
}
|
|
3717
4177
|
const discoveredHaps = await discoverHaps({ projectDir });
|
|
3718
4178
|
const anySigned = Object.values(discoveredHaps).some((m) => m.signed.length > 0);
|
|
3719
4179
|
if (!anySigned) {
|
|
3720
4180
|
warnings.push(
|
|
3721
|
-
isHarmonyOs ? "No signed HAPs found
|
|
4181
|
+
isHarmonyOs ? "No signed HAPs found. The HarmonyOS emulator installs the unsigned HAP as it is; for a device, run `oniro-app sign --harmonyos` to have AppGallery Connect issue a certificate and profile." : "No signed HAPs found: most OpenHarmony targets reject unsigned HAPs. Run `oniro-app sign` to generate local signing material, then build again."
|
|
3722
4182
|
);
|
|
3723
4183
|
}
|
|
3724
4184
|
return { exitCode, durationMs: Date.now() - start, discoveredHaps, warnings };
|
|
@@ -3735,21 +4195,21 @@ function isValidBundleName(bundleName) {
|
|
|
3735
4195
|
}
|
|
3736
4196
|
|
|
3737
4197
|
// src/project/templates.ts
|
|
3738
|
-
var
|
|
3739
|
-
var
|
|
4198
|
+
var fs26 = __toESM(require("fs"), 1);
|
|
4199
|
+
var path26 = __toESM(require("path"), 1);
|
|
3740
4200
|
function toHumanTemplateName(folderName) {
|
|
3741
4201
|
return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
3742
4202
|
}
|
|
3743
4203
|
function listTemplates(templateRoot) {
|
|
3744
|
-
if (!
|
|
3745
|
-
const entries =
|
|
4204
|
+
if (!fs26.existsSync(templateRoot)) return [];
|
|
4205
|
+
const entries = fs26.readdirSync(templateRoot, { withFileTypes: true });
|
|
3746
4206
|
return entries.filter((e) => e.isDirectory()).map((e) => {
|
|
3747
|
-
const dir =
|
|
3748
|
-
const metaPath =
|
|
4207
|
+
const dir = path26.join(templateRoot, e.name);
|
|
4208
|
+
const metaPath = path26.join(dir, "template.json");
|
|
3749
4209
|
let meta = {};
|
|
3750
|
-
if (
|
|
4210
|
+
if (fs26.existsSync(metaPath)) {
|
|
3751
4211
|
try {
|
|
3752
|
-
meta = JSON.parse(
|
|
4212
|
+
meta = JSON.parse(fs26.readFileSync(metaPath, "utf8"));
|
|
3753
4213
|
} catch {
|
|
3754
4214
|
}
|
|
3755
4215
|
}
|
|
@@ -3764,57 +4224,57 @@ function listTemplates(templateRoot) {
|
|
|
3764
4224
|
function validateTemplateLayout(templateDir, defaultModuleName) {
|
|
3765
4225
|
const required = [
|
|
3766
4226
|
"build-profile.json5",
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
4227
|
+
path26.join("AppScope", "app.json5"),
|
|
4228
|
+
path26.join(defaultModuleName, "src", "main", "module.json5"),
|
|
4229
|
+
path26.join(defaultModuleName, "oh-package.json5"),
|
|
3770
4230
|
"hvigorfile.ts"
|
|
3771
4231
|
];
|
|
3772
|
-
return required.filter((rel) => !
|
|
4232
|
+
return required.filter((rel) => !fs26.existsSync(path26.join(templateDir, rel)));
|
|
3773
4233
|
}
|
|
3774
4234
|
|
|
3775
4235
|
// src/project/createScaffold.ts
|
|
3776
|
-
var
|
|
3777
|
-
var
|
|
4236
|
+
var fs28 = __toESM(require("fs"), 1);
|
|
4237
|
+
var path27 = __toESM(require("path"), 1);
|
|
3778
4238
|
|
|
3779
4239
|
// src/project/jsonHelpers.ts
|
|
3780
|
-
var
|
|
4240
|
+
var fs27 = __toESM(require("fs"), 1);
|
|
3781
4241
|
var import_json55 = __toESM(require("json5"), 1);
|
|
3782
4242
|
function readJson5File(filePath) {
|
|
3783
|
-
return import_json55.default.parse(
|
|
4243
|
+
return import_json55.default.parse(fs27.readFileSync(filePath, "utf8"));
|
|
3784
4244
|
}
|
|
3785
4245
|
function writeJson5File(filePath, value) {
|
|
3786
|
-
|
|
4246
|
+
fs27.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
3787
4247
|
}
|
|
3788
4248
|
function readJsonFile(filePath) {
|
|
3789
|
-
return JSON.parse(
|
|
4249
|
+
return JSON.parse(fs27.readFileSync(filePath, "utf8"));
|
|
3790
4250
|
}
|
|
3791
4251
|
function writeJsonFile(filePath, value) {
|
|
3792
|
-
|
|
4252
|
+
fs27.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
3793
4253
|
}
|
|
3794
4254
|
|
|
3795
4255
|
// src/project/createScaffold.ts
|
|
3796
4256
|
var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
|
|
3797
4257
|
async function pathExists(p) {
|
|
3798
4258
|
try {
|
|
3799
|
-
await
|
|
4259
|
+
await fs28.promises.access(p);
|
|
3800
4260
|
return true;
|
|
3801
4261
|
} catch {
|
|
3802
4262
|
return false;
|
|
3803
4263
|
}
|
|
3804
4264
|
}
|
|
3805
4265
|
async function copyDirRecursive(srcDir, destDir) {
|
|
3806
|
-
await
|
|
3807
|
-
const entries = await
|
|
4266
|
+
await fs28.promises.mkdir(destDir, { recursive: true });
|
|
4267
|
+
const entries = await fs28.promises.readdir(srcDir, { withFileTypes: true });
|
|
3808
4268
|
for (const entry of entries) {
|
|
3809
|
-
const src =
|
|
3810
|
-
const dest =
|
|
4269
|
+
const src = path27.join(srcDir, entry.name);
|
|
4270
|
+
const dest = path27.join(destDir, entry.name);
|
|
3811
4271
|
if (entry.isDirectory()) {
|
|
3812
4272
|
await copyDirRecursive(src, dest);
|
|
3813
4273
|
} else if (entry.isSymbolicLink()) {
|
|
3814
4274
|
continue;
|
|
3815
4275
|
} else if (entry.isFile()) {
|
|
3816
4276
|
if (entry.name === "template.json") continue;
|
|
3817
|
-
await
|
|
4277
|
+
await fs28.promises.copyFile(src, dest);
|
|
3818
4278
|
}
|
|
3819
4279
|
}
|
|
3820
4280
|
}
|
|
@@ -3822,9 +4282,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
|
|
|
3822
4282
|
const stack = [projectDir];
|
|
3823
4283
|
while (stack.length > 0) {
|
|
3824
4284
|
const currentDir = stack.pop();
|
|
3825
|
-
const entries = await
|
|
4285
|
+
const entries = await fs28.promises.readdir(currentDir, { withFileTypes: true });
|
|
3826
4286
|
for (const entry of entries) {
|
|
3827
|
-
const fullPath =
|
|
4287
|
+
const fullPath = path27.join(currentDir, entry.name);
|
|
3828
4288
|
if (entry.isDirectory()) {
|
|
3829
4289
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
3830
4290
|
stack.push(fullPath);
|
|
@@ -3846,23 +4306,23 @@ function toJavaPropertiesPath(p) {
|
|
|
3846
4306
|
function createOrUpdateLocalProperties(projectDir, sdkDir) {
|
|
3847
4307
|
const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
|
|
3848
4308
|
`;
|
|
3849
|
-
|
|
4309
|
+
fs28.writeFileSync(path27.join(projectDir, "local.properties"), content, "utf8");
|
|
3850
4310
|
}
|
|
3851
4311
|
function renameIfExists(fromPath, toPath) {
|
|
3852
|
-
if (
|
|
3853
|
-
|
|
4312
|
+
if (fs28.existsSync(fromPath) && fromPath !== toPath) {
|
|
4313
|
+
fs28.renameSync(fromPath, toPath);
|
|
3854
4314
|
}
|
|
3855
4315
|
}
|
|
3856
4316
|
function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
3857
|
-
const appJsonPath =
|
|
3858
|
-
if (
|
|
4317
|
+
const appJsonPath = path27.join(projectDir, "AppScope", "app.json5");
|
|
4318
|
+
if (fs28.existsSync(appJsonPath)) {
|
|
3859
4319
|
const appJson = readJson5File(appJsonPath);
|
|
3860
4320
|
appJson.app = appJson.app ?? {};
|
|
3861
4321
|
appJson.app.bundleName = args.bundleName;
|
|
3862
4322
|
writeJson5File(appJsonPath, appJson);
|
|
3863
4323
|
}
|
|
3864
|
-
const stringsPath =
|
|
3865
|
-
if (
|
|
4324
|
+
const stringsPath = path27.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
|
|
4325
|
+
if (fs28.existsSync(stringsPath)) {
|
|
3866
4326
|
const strings = readJsonFile(stringsPath);
|
|
3867
4327
|
if (Array.isArray(strings.string)) {
|
|
3868
4328
|
const appName = strings.string.find((s) => s.name === "app_name");
|
|
@@ -3870,8 +4330,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
3870
4330
|
}
|
|
3871
4331
|
writeJsonFile(stringsPath, strings);
|
|
3872
4332
|
}
|
|
3873
|
-
const buildProfilePath =
|
|
3874
|
-
if (
|
|
4333
|
+
const buildProfilePath = path27.join(projectDir, "build-profile.json5");
|
|
4334
|
+
if (fs28.existsSync(buildProfilePath)) {
|
|
3875
4335
|
const buildProfile = readJson5File(buildProfilePath);
|
|
3876
4336
|
buildProfile.app = buildProfile.app ?? {};
|
|
3877
4337
|
if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
|
|
@@ -3884,23 +4344,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
3884
4344
|
}
|
|
3885
4345
|
writeJson5File(buildProfilePath, buildProfile);
|
|
3886
4346
|
}
|
|
3887
|
-
const moduleJsonPath =
|
|
3888
|
-
if (
|
|
4347
|
+
const moduleJsonPath = path27.join(projectDir, args.moduleName, "src", "main", "module.json5");
|
|
4348
|
+
if (fs28.existsSync(moduleJsonPath)) {
|
|
3889
4349
|
const moduleJson = readJson5File(moduleJsonPath);
|
|
3890
4350
|
moduleJson.module = moduleJson.module ?? {};
|
|
3891
4351
|
moduleJson.module.name = args.moduleName;
|
|
3892
4352
|
writeJson5File(moduleJsonPath, moduleJson);
|
|
3893
4353
|
}
|
|
3894
|
-
const moduleOhPackagePath =
|
|
3895
|
-
if (
|
|
4354
|
+
const moduleOhPackagePath = path27.join(projectDir, args.moduleName, "oh-package.json5");
|
|
4355
|
+
if (fs28.existsSync(moduleOhPackagePath)) {
|
|
3896
4356
|
const pkg = readJson5File(moduleOhPackagePath);
|
|
3897
4357
|
pkg.name = args.moduleName;
|
|
3898
4358
|
writeJson5File(moduleOhPackagePath, pkg);
|
|
3899
4359
|
}
|
|
3900
|
-
const vscodeDir =
|
|
3901
|
-
|
|
4360
|
+
const vscodeDir = path27.join(projectDir, ".vscode");
|
|
4361
|
+
fs28.mkdirSync(vscodeDir, { recursive: true });
|
|
3902
4362
|
const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
|
|
3903
|
-
writeJsonFile(
|
|
4363
|
+
writeJsonFile(path27.join(vscodeDir, "settings.json"), {
|
|
3904
4364
|
"oniro.hapPath": hapPath,
|
|
3905
4365
|
"files.associations": { "*.json5": "jsonc" }
|
|
3906
4366
|
});
|
|
@@ -3917,7 +4377,7 @@ async function createScaffold(opts) {
|
|
|
3917
4377
|
if (!opts.location || !await pathExists(opts.location)) {
|
|
3918
4378
|
throw new OniroError(`Location does not exist: ${opts.location}`);
|
|
3919
4379
|
}
|
|
3920
|
-
const templateDir =
|
|
4380
|
+
const templateDir = path27.join(opts.templateRoot, opts.templateId);
|
|
3921
4381
|
if (!await pathExists(templateDir)) {
|
|
3922
4382
|
throw new OniroError(`Template not found: ${templateDir}`);
|
|
3923
4383
|
}
|
|
@@ -3952,17 +4412,17 @@ async function createScaffold(opts) {
|
|
|
3952
4412
|
}
|
|
3953
4413
|
}
|
|
3954
4414
|
}
|
|
3955
|
-
const projectDir =
|
|
4415
|
+
const projectDir = path27.join(opts.location, opts.projectName);
|
|
3956
4416
|
if (await pathExists(projectDir)) {
|
|
3957
4417
|
if (!opts.overwrite) {
|
|
3958
4418
|
throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
|
|
3959
4419
|
}
|
|
3960
|
-
await
|
|
4420
|
+
await fs28.promises.rm(projectDir, { recursive: true, force: true });
|
|
3961
4421
|
}
|
|
3962
4422
|
logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
|
|
3963
4423
|
await copyDirRecursive(templateDir, projectDir);
|
|
3964
4424
|
if (moduleName !== defaultModuleName) {
|
|
3965
|
-
renameIfExists(
|
|
4425
|
+
renameIfExists(path27.join(projectDir, defaultModuleName), path27.join(projectDir, moduleName));
|
|
3966
4426
|
}
|
|
3967
4427
|
updateTemplateConfigs(
|
|
3968
4428
|
projectDir,
|
|
@@ -3979,11 +4439,11 @@ async function createScaffold(opts) {
|
|
|
3979
4439
|
}
|
|
3980
4440
|
|
|
3981
4441
|
// src/project/listModules.ts
|
|
3982
|
-
var
|
|
3983
|
-
var
|
|
4442
|
+
var fs29 = __toESM(require("fs"), 1);
|
|
4443
|
+
var path28 = __toESM(require("path"), 1);
|
|
3984
4444
|
function listModules(opts) {
|
|
3985
|
-
const buildProfile =
|
|
3986
|
-
if (!
|
|
4445
|
+
const buildProfile = path28.join(opts.projectDir, "build-profile.json5");
|
|
4446
|
+
if (!fs29.existsSync(buildProfile)) {
|
|
3987
4447
|
throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
|
|
3988
4448
|
}
|
|
3989
4449
|
const parsed = readJson5File(buildProfile);
|
|
@@ -3995,12 +4455,12 @@ function listModules(opts) {
|
|
|
3995
4455
|
}
|
|
3996
4456
|
|
|
3997
4457
|
// src/project/abilities.ts
|
|
3998
|
-
var
|
|
3999
|
-
var
|
|
4458
|
+
var fs30 = __toESM(require("fs"), 1);
|
|
4459
|
+
var path29 = __toESM(require("path"), 1);
|
|
4000
4460
|
function listAbilities(opts) {
|
|
4001
4461
|
const moduleName = opts.moduleName ?? "entry";
|
|
4002
|
-
const moduleJsonPath =
|
|
4003
|
-
if (!
|
|
4462
|
+
const moduleJsonPath = path29.join(opts.projectDir, moduleName, "src", "main", "module.json5");
|
|
4463
|
+
if (!fs30.existsSync(moduleJsonPath)) {
|
|
4004
4464
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
4005
4465
|
}
|
|
4006
4466
|
const parsed = readJson5File(moduleJsonPath);
|
|
@@ -4008,12 +4468,12 @@ function listAbilities(opts) {
|
|
|
4008
4468
|
}
|
|
4009
4469
|
|
|
4010
4470
|
// src/project/prepareSigning.ts
|
|
4011
|
-
var
|
|
4012
|
-
var
|
|
4471
|
+
var fs31 = __toESM(require("fs"), 1);
|
|
4472
|
+
var path30 = __toESM(require("path"), 1);
|
|
4013
4473
|
function hasSigningArtifacts(dir) {
|
|
4014
|
-
if (!
|
|
4015
|
-
const buildProfile =
|
|
4016
|
-
if (!
|
|
4474
|
+
if (!fs31.existsSync(path30.join(dir, "signatures"))) return false;
|
|
4475
|
+
const buildProfile = path30.join(dir, "build-profile.json5");
|
|
4476
|
+
if (!fs31.existsSync(buildProfile)) return false;
|
|
4017
4477
|
try {
|
|
4018
4478
|
const parsed = readJson5File(buildProfile);
|
|
4019
4479
|
return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
|
|
@@ -4031,6 +4491,7 @@ function prepareSigning(opts) {
|
|
|
4031
4491
|
apl: opts.apl,
|
|
4032
4492
|
appFeature: opts.appFeature,
|
|
4033
4493
|
acls: opts.acls,
|
|
4494
|
+
appPrivilegeCapabilities: opts.appPrivilegeCapabilities,
|
|
4034
4495
|
passwords: opts.passwords,
|
|
4035
4496
|
logger: opts.logger
|
|
4036
4497
|
});
|
|
@@ -4059,19 +4520,31 @@ var PROPS = [
|
|
|
4059
4520
|
["model", "const.product.model"],
|
|
4060
4521
|
["manufacturer", "const.product.manufacturer"],
|
|
4061
4522
|
["brand", "const.product.brand"],
|
|
4523
|
+
["osDistName", "const.product.os.dist.name"],
|
|
4524
|
+
["osDistVersion", "const.product.os.dist.version"],
|
|
4062
4525
|
["osFullName", "const.ohos.fullname"],
|
|
4063
4526
|
["osReleaseType", "const.ohos.releasetype"],
|
|
4064
4527
|
["sdkApiVersion", "const.ohos.apiversion"],
|
|
4065
|
-
["buildVersion", "const.product.software.version"]
|
|
4528
|
+
["buildVersion", "const.product.software.version"],
|
|
4529
|
+
["abi", "const.product.cpu.abilist"],
|
|
4530
|
+
["deviceType", "const.product.devicetype"]
|
|
4066
4531
|
];
|
|
4067
4532
|
async function getDeviceInfo(opts) {
|
|
4068
4533
|
const info = { serial: opts.deviceSerial ?? "(default)", display: null };
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4534
|
+
try {
|
|
4535
|
+
const values = await paramGetMany(
|
|
4536
|
+
opts.config,
|
|
4537
|
+
PROPS.map(([, prop]) => prop),
|
|
4538
|
+
{ deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 1e4, logger: opts.logger }
|
|
4539
|
+
);
|
|
4540
|
+
for (const [field, prop] of PROPS) {
|
|
4541
|
+
const value = values[prop];
|
|
4072
4542
|
if (value) info[field] = value;
|
|
4073
|
-
} catch {
|
|
4074
4543
|
}
|
|
4544
|
+
} catch {
|
|
4545
|
+
}
|
|
4546
|
+
if (info.osDistName || info.osFullName) {
|
|
4547
|
+
info.osFamily = /harmonyos/i.test(info.osDistName ?? "") ? "HarmonyOS" : "OpenHarmony";
|
|
4075
4548
|
}
|
|
4076
4549
|
const screen = await dumpScreen({ config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger });
|
|
4077
4550
|
if (screen) info.display = { width: screen.width, height: screen.height };
|
|
@@ -4103,8 +4576,8 @@ async function diffHapAssets(opts) {
|
|
|
4103
4576
|
}
|
|
4104
4577
|
|
|
4105
4578
|
// src/install/apply.ts
|
|
4106
|
-
var
|
|
4107
|
-
var
|
|
4579
|
+
var fs32 = __toESM(require("fs"), 1);
|
|
4580
|
+
var path31 = __toESM(require("path"), 1);
|
|
4108
4581
|
function decideInstallMethod(s) {
|
|
4109
4582
|
if (!s.signInfoInconsistent) return "replace";
|
|
4110
4583
|
if (s.isSystemBundle && !s.allowUninstall) return "refuse";
|
|
@@ -4122,39 +4595,31 @@ async function pidOf(config, bundle, deviceSerial) {
|
|
|
4122
4595
|
const proc = await findRunningProcess({ config, bundle, deviceSerial });
|
|
4123
4596
|
return proc ? Number(proc.pid) : null;
|
|
4124
4597
|
}
|
|
4125
|
-
async function
|
|
4126
|
-
let
|
|
4127
|
-
if (hapPath) {
|
|
4128
|
-
|
|
4598
|
+
async function resolveHap(opts, logger) {
|
|
4599
|
+
let hap;
|
|
4600
|
+
if (opts.hapPath) {
|
|
4601
|
+
const hapPath = !path31.isAbsolute(opts.hapPath) && opts.projectDir ? path31.join(opts.projectDir, opts.hapPath) : opts.hapPath;
|
|
4602
|
+
hap = existingHapOrUnsigned(hapPath);
|
|
4603
|
+
if (!hap) throw new OniroError(`HAP not found at ${hapPath}.`);
|
|
4129
4604
|
} else {
|
|
4130
4605
|
if (!opts.projectDir) throw new OniroError("applyChanges requires hapPath or projectDir.");
|
|
4131
|
-
const
|
|
4132
|
-
if (opts.module
|
|
4133
|
-
|
|
4134
|
-
if (signed.length === 0) throw new OniroError(`No signed HAP for module ${opts.module}. Build first.`);
|
|
4135
|
-
hapPath = signed[0];
|
|
4136
|
-
} else {
|
|
4137
|
-
const withSigned = Object.entries(haps).filter(([, m]) => m.signed.length > 0);
|
|
4138
|
-
if (withSigned.length === 0) throw new OniroError("No signed HAP found. Build first.");
|
|
4139
|
-
if (withSigned.length > 1) {
|
|
4140
|
-
throw new OniroError(
|
|
4141
|
-
`Multiple modules have signed HAPs (${withSigned.map(([k]) => k).join(", ")}). Pass module to choose.`
|
|
4142
|
-
);
|
|
4143
|
-
}
|
|
4144
|
-
hapPath = withSigned[0][1].signed[0];
|
|
4145
|
-
}
|
|
4606
|
+
const picked = pickHap(await discoverHaps({ projectDir: opts.projectDir }), opts.module);
|
|
4607
|
+
if (!picked) throw new OniroError(`No HAP found${opts.module ? ` for module ${opts.module}` : ""}. Build first.`);
|
|
4608
|
+
hap = { path: picked.path, fallback: !picked.signed };
|
|
4146
4609
|
}
|
|
4147
|
-
if (
|
|
4148
|
-
return
|
|
4610
|
+
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path31.basename(hap.path)}.`);
|
|
4611
|
+
return hap;
|
|
4149
4612
|
}
|
|
4150
4613
|
async function applyChanges(opts) {
|
|
4151
4614
|
const logger = scopedLogger(opts.logger ?? noopLogger, "apply");
|
|
4152
4615
|
const { config, bundle, deviceSerial } = opts;
|
|
4153
4616
|
const isSystemBundle = opts.isSystemBundle ?? false;
|
|
4154
4617
|
const allowUninstall = opts.allowUninstall ?? false;
|
|
4155
|
-
const
|
|
4618
|
+
const hap = await resolveHap(opts, logger);
|
|
4619
|
+
const hapPath = hap.path;
|
|
4620
|
+
logger.info(`installing ${hapPath}`);
|
|
4156
4621
|
let assetsChanged = false;
|
|
4157
|
-
if (opts.installedHapPath &&
|
|
4622
|
+
if (opts.installedHapPath && fs32.existsSync(opts.installedHapPath)) {
|
|
4158
4623
|
try {
|
|
4159
4624
|
const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
|
|
4160
4625
|
assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
|
|
@@ -4175,12 +4640,21 @@ async function applyChanges(opts) {
|
|
|
4175
4640
|
if (decision === "uninstall-install") {
|
|
4176
4641
|
logger.warn(`sign-info inconsistent for ${bundle}; uninstalling then installing fresh.`);
|
|
4177
4642
|
await uninstallApp({ config, bundle, deviceSerial });
|
|
4178
|
-
|
|
4643
|
+
ensureInstallOk(
|
|
4644
|
+
await hdcExec({ config, args: ["install", hapPath], deviceSerial, timeoutMs: 3e5 }),
|
|
4645
|
+
`hdc install ${hapPath}`,
|
|
4646
|
+
hap
|
|
4647
|
+
);
|
|
4179
4648
|
installMethod = "uninstall-install";
|
|
4180
4649
|
} else {
|
|
4181
|
-
|
|
4650
|
+
ensureInstallOk(replaceRes, `hdc install -r ${hapPath}`, hap);
|
|
4182
4651
|
installMethod = "replace";
|
|
4183
4652
|
}
|
|
4653
|
+
if (!await isBundleInstalled({ config, bundle, deviceSerial })) {
|
|
4654
|
+
throw new OniroError(
|
|
4655
|
+
`hdc reported ${path31.basename(hapPath)} as installed, but bm dump does not list ${bundle}. Check that the HAP was built from this project (its bundleName must match).`
|
|
4656
|
+
);
|
|
4657
|
+
}
|
|
4184
4658
|
let postInstallPid = await pidOf(config, bundle, deviceSerial);
|
|
4185
4659
|
const rebootDecision = decideReboot({ assetsChanged, isSystemBundle, preInstallPid, postInstallPid });
|
|
4186
4660
|
let method = installMethod;
|
|
@@ -4255,9 +4729,9 @@ var AUTH_PATHS = {
|
|
|
4255
4729
|
};
|
|
4256
4730
|
|
|
4257
4731
|
// src/harmonyos/auth/tokenStore.ts
|
|
4258
|
-
var
|
|
4732
|
+
var fs33 = __toESM(require("fs"), 1);
|
|
4259
4733
|
var os11 = __toESM(require("os"), 1);
|
|
4260
|
-
var
|
|
4734
|
+
var path32 = __toESM(require("path"), 1);
|
|
4261
4735
|
var crypto3 = __toESM(require("crypto"), 1);
|
|
4262
4736
|
var ALGORITHM = "aes-256-gcm";
|
|
4263
4737
|
var KEY_LENGTH = 32;
|
|
@@ -4293,7 +4767,7 @@ function permissionHint(dir) {
|
|
|
4293
4767
|
}
|
|
4294
4768
|
function ensureDir(dir) {
|
|
4295
4769
|
try {
|
|
4296
|
-
|
|
4770
|
+
fs33.mkdirSync(dir, { recursive: true, mode: DIR_MODE });
|
|
4297
4771
|
} catch (err) {
|
|
4298
4772
|
if (err.code === "EACCES") {
|
|
4299
4773
|
throw new OniroError(permissionHint(dir), err);
|
|
@@ -4304,17 +4778,17 @@ function ensureDir(dir) {
|
|
|
4304
4778
|
function createTokenStore(opts) {
|
|
4305
4779
|
const logger = opts.logger ?? noopLogger;
|
|
4306
4780
|
const authDir = opts.config.get("harmonyosAuthDir", defaultPaths.harmonyosAuthDir());
|
|
4307
|
-
const tokenPath =
|
|
4308
|
-
const keyPath =
|
|
4781
|
+
const tokenPath = path32.join(authDir, TOKEN_FILE);
|
|
4782
|
+
const keyPath = path32.join(os11.homedir(), ".local", "share", "oniro-app", "keys", KEY_FILE);
|
|
4309
4783
|
function loadOrCreateKey() {
|
|
4310
|
-
if (
|
|
4311
|
-
const existing =
|
|
4784
|
+
if (fs33.existsSync(keyPath)) {
|
|
4785
|
+
const existing = fs33.readFileSync(keyPath);
|
|
4312
4786
|
if (existing.length === KEY_LENGTH) return existing;
|
|
4313
4787
|
logger.warn("[harmonyos] The token key file was malformed; regenerating (you will need to log in again).");
|
|
4314
4788
|
}
|
|
4315
|
-
ensureDir(
|
|
4789
|
+
ensureDir(path32.dirname(keyPath));
|
|
4316
4790
|
const key = crypto3.randomBytes(KEY_LENGTH);
|
|
4317
|
-
|
|
4791
|
+
fs33.writeFileSync(keyPath, key, { mode: FILE_MODE });
|
|
4318
4792
|
return key;
|
|
4319
4793
|
}
|
|
4320
4794
|
return {
|
|
@@ -4324,12 +4798,12 @@ function createTokenStore(opts) {
|
|
|
4324
4798
|
const payload = Buffer.from(JSON.stringify(session), "utf8");
|
|
4325
4799
|
const blob = encrypt2(loadOrCreateKey(), payload);
|
|
4326
4800
|
ensureDir(authDir);
|
|
4327
|
-
|
|
4801
|
+
fs33.writeFileSync(tokenPath, JSON.stringify(blob, null, 2), { mode: FILE_MODE });
|
|
4328
4802
|
},
|
|
4329
4803
|
load() {
|
|
4330
|
-
if (!
|
|
4804
|
+
if (!fs33.existsSync(tokenPath)) return null;
|
|
4331
4805
|
try {
|
|
4332
|
-
const blob = JSON.parse(
|
|
4806
|
+
const blob = JSON.parse(fs33.readFileSync(tokenPath, "utf8"));
|
|
4333
4807
|
if (!isEncryptedBlob(blob)) return null;
|
|
4334
4808
|
const { jwtToken, siteId } = JSON.parse(decrypt2(loadOrCreateKey(), blob).toString("utf8"));
|
|
4335
4809
|
return typeof jwtToken === "string" && jwtToken && typeof siteId === "string" ? { jwtToken, siteId } : null;
|
|
@@ -4341,7 +4815,7 @@ function createTokenStore(opts) {
|
|
|
4341
4815
|
}
|
|
4342
4816
|
logger.debug(`[harmonyos] Discarding unreadable token at ${tokenPath}.`);
|
|
4343
4817
|
try {
|
|
4344
|
-
|
|
4818
|
+
fs33.rmSync(tokenPath, { force: true });
|
|
4345
4819
|
} catch {
|
|
4346
4820
|
}
|
|
4347
4821
|
return null;
|
|
@@ -4349,7 +4823,7 @@ function createTokenStore(opts) {
|
|
|
4349
4823
|
},
|
|
4350
4824
|
clear() {
|
|
4351
4825
|
try {
|
|
4352
|
-
|
|
4826
|
+
fs33.rmSync(tokenPath, { force: true });
|
|
4353
4827
|
} catch (err) {
|
|
4354
4828
|
throw new OniroError(`Failed to remove ${tokenPath}.`, err);
|
|
4355
4829
|
}
|
|
@@ -4463,8 +4937,8 @@ function isQuit(quit) {
|
|
|
4463
4937
|
async function startCallbackServer(opts) {
|
|
4464
4938
|
let resolveCallback;
|
|
4465
4939
|
let rejectCallback;
|
|
4466
|
-
const callback = new Promise((
|
|
4467
|
-
resolveCallback =
|
|
4940
|
+
const callback = new Promise((resolve7, reject) => {
|
|
4941
|
+
resolveCallback = resolve7;
|
|
4468
4942
|
rejectCallback = reject;
|
|
4469
4943
|
});
|
|
4470
4944
|
callback.catch(() => {
|
|
@@ -4523,9 +4997,9 @@ async function startCallbackServer(opts) {
|
|
|
4523
4997
|
}
|
|
4524
4998
|
});
|
|
4525
4999
|
server.keepAliveTimeout = 1;
|
|
4526
|
-
await new Promise((
|
|
5000
|
+
await new Promise((resolve7, reject) => {
|
|
4527
5001
|
server.once("error", (err) => reject(new OniroError("Failed to start the local login callback server.", err)));
|
|
4528
|
-
server.listen(0, "127.0.0.1",
|
|
5002
|
+
server.listen(0, "127.0.0.1", resolve7);
|
|
4529
5003
|
});
|
|
4530
5004
|
const port = server.address().port;
|
|
4531
5005
|
return {
|
|
@@ -4541,12 +5015,12 @@ async function startCallbackServer(opts) {
|
|
|
4541
5015
|
return Promise.race([callback, timeout]).finally(() => clearTimeout(timer));
|
|
4542
5016
|
},
|
|
4543
5017
|
stop() {
|
|
4544
|
-
return new Promise((
|
|
5018
|
+
return new Promise((resolve7) => {
|
|
4545
5019
|
server.closeAllConnections?.();
|
|
4546
|
-
const timer = setTimeout(
|
|
5020
|
+
const timer = setTimeout(resolve7, 100);
|
|
4547
5021
|
server.close(() => {
|
|
4548
5022
|
clearTimeout(timer);
|
|
4549
|
-
|
|
5023
|
+
resolve7();
|
|
4550
5024
|
});
|
|
4551
5025
|
});
|
|
4552
5026
|
}
|
|
@@ -4578,11 +5052,11 @@ function openBrowser(url) {
|
|
|
4578
5052
|
windowsHide: true
|
|
4579
5053
|
});
|
|
4580
5054
|
child.unref();
|
|
4581
|
-
return new Promise((
|
|
5055
|
+
return new Promise((resolve7, reject) => {
|
|
4582
5056
|
child.on("error", (err) => reject(new OniroError(`Failed to open a browser (${command}).`, err)));
|
|
4583
5057
|
child.on(
|
|
4584
5058
|
"exit",
|
|
4585
|
-
(code) => code === 0 ?
|
|
5059
|
+
(code) => code === 0 ? resolve7() : reject(new OniroError(`Browser launcher '${command}' exited with code ${code}.`))
|
|
4586
5060
|
);
|
|
4587
5061
|
});
|
|
4588
5062
|
}
|
|
@@ -4830,7 +5304,7 @@ function mapAgcError(operation, statusCode, reasonPhrase, body) {
|
|
|
4830
5304
|
}
|
|
4831
5305
|
|
|
4832
5306
|
// src/harmonyos/signing/profile.ts
|
|
4833
|
-
var
|
|
5307
|
+
var fs34 = __toESM(require("fs"), 1);
|
|
4834
5308
|
var import_node_crypto3 = require("crypto");
|
|
4835
5309
|
var import_node_forge = __toESM(require("node-forge"), 1);
|
|
4836
5310
|
function extractProfileJson(buffer) {
|
|
@@ -4862,7 +5336,7 @@ function extractProfileJson(buffer) {
|
|
|
4862
5336
|
function readProvisionProfile(profilePath) {
|
|
4863
5337
|
let raw;
|
|
4864
5338
|
try {
|
|
4865
|
-
const json = extractProfileJson(
|
|
5339
|
+
const json = extractProfileJson(fs34.readFileSync(profilePath));
|
|
4866
5340
|
if (!json) return null;
|
|
4867
5341
|
raw = JSON.parse(json);
|
|
4868
5342
|
} catch {
|
|
@@ -4891,7 +5365,7 @@ function parseCertificate(pem) {
|
|
|
4891
5365
|
}
|
|
4892
5366
|
function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
|
|
4893
5367
|
try {
|
|
4894
|
-
const der = import_node_forge.default.util.createBuffer(
|
|
5368
|
+
const der = import_node_forge.default.util.createBuffer(fs34.readFileSync(p12Path).toString("binary"));
|
|
4895
5369
|
const p12 = import_node_forge.default.pkcs12.pkcs12FromAsn1(import_node_forge.default.asn1.fromDer(der), keyPwd);
|
|
4896
5370
|
const certBag = import_node_forge.default.pki.oids.certBag ?? "1.2.840.113549.1.12.10.1.3";
|
|
4897
5371
|
const wanted = certificate.publicKey.export({ type: "spki", format: "der" });
|
|
@@ -4907,7 +5381,7 @@ function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
|
|
|
4907
5381
|
}
|
|
4908
5382
|
}
|
|
4909
5383
|
function verifySigningMaterial(opts) {
|
|
4910
|
-
const pems =
|
|
5384
|
+
const pems = fs34.readFileSync(opts.cerPath, "utf8").match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g);
|
|
4911
5385
|
const chain = (pems ?? []).map(parseCertificate);
|
|
4912
5386
|
const leaf = chain.find((c) => !c.ca) ?? chain.at(-1);
|
|
4913
5387
|
if (!leaf) throw new AgcError(SIGNING_ERRORS.CERT_INVALID);
|
|
@@ -4926,14 +5400,14 @@ function verifySigningMaterial(opts) {
|
|
|
4926
5400
|
|
|
4927
5401
|
// src/harmonyos/signing/autoSign.ts
|
|
4928
5402
|
var crypto9 = __toESM(require("crypto"), 1);
|
|
4929
|
-
var
|
|
4930
|
-
var
|
|
5403
|
+
var fs39 = __toESM(require("fs"), 1);
|
|
5404
|
+
var path38 = __toESM(require("path"), 1);
|
|
4931
5405
|
var import_json57 = __toESM(require("json5"), 1);
|
|
4932
5406
|
|
|
4933
5407
|
// src/harmonyos/signing/agc.ts
|
|
4934
5408
|
var crypto6 = __toESM(require("crypto"), 1);
|
|
4935
|
-
var
|
|
4936
|
-
var
|
|
5409
|
+
var fs35 = __toESM(require("fs"), 1);
|
|
5410
|
+
var path33 = __toESM(require("path"), 1);
|
|
4937
5411
|
var ENDPOINTS = {
|
|
4938
5412
|
CERT_LIST: "/api/cps/harmony-cert-manage/v1/cert/list",
|
|
4939
5413
|
CERT_ADD: "/api/cps/harmony-cert-manage/v1/cert/add",
|
|
@@ -5019,8 +5493,8 @@ function createAgcClient(http3, auth) {
|
|
|
5019
5493
|
if (target.sha256 && actual !== target.sha256.toLowerCase()) {
|
|
5020
5494
|
throw new ChecksumMismatchError(target.sha256, actual);
|
|
5021
5495
|
}
|
|
5022
|
-
|
|
5023
|
-
|
|
5496
|
+
fs35.mkdirSync(path33.dirname(dest), { recursive: true, mode: 448 });
|
|
5497
|
+
fs35.writeFileSync(dest, buffer, { mode: 384 });
|
|
5024
5498
|
}
|
|
5025
5499
|
};
|
|
5026
5500
|
}
|
|
@@ -5071,22 +5545,22 @@ async function registerDevices(agc, connected, logger) {
|
|
|
5071
5545
|
|
|
5072
5546
|
// src/harmonyos/signing/keystore.ts
|
|
5073
5547
|
var crypto7 = __toESM(require("crypto"), 1);
|
|
5074
|
-
var
|
|
5075
|
-
var
|
|
5548
|
+
var fs37 = __toESM(require("fs"), 1);
|
|
5549
|
+
var path35 = __toESM(require("path"), 1);
|
|
5076
5550
|
|
|
5077
5551
|
// src/harmonyos/java.ts
|
|
5078
|
-
var
|
|
5079
|
-
var
|
|
5552
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
5553
|
+
var path34 = __toESM(require("path"), 1);
|
|
5080
5554
|
var JAVA_BIN = process.platform === "win32" ? "java.exe" : "java";
|
|
5081
5555
|
function findJava(sdk, env = process.env) {
|
|
5082
5556
|
const candidates = [
|
|
5083
|
-
env.JAVA_HOME &&
|
|
5084
|
-
sdk &&
|
|
5557
|
+
env.JAVA_HOME && path34.join(env.JAVA_HOME, "bin", JAVA_BIN),
|
|
5558
|
+
sdk && path34.join(sdk.installRoot, "jbr", "bin", JAVA_BIN),
|
|
5085
5559
|
// macOS: the JBR is itself a bundle inside Studio's Contents.
|
|
5086
|
-
sdk &&
|
|
5087
|
-
...(env.PATH ?? "").split(
|
|
5560
|
+
sdk && path34.join(sdk.installRoot, "jbr", "Contents", "Home", "bin", JAVA_BIN),
|
|
5561
|
+
...(env.PATH ?? "").split(path34.delimiter).map((dir) => dir && path34.join(dir, JAVA_BIN))
|
|
5088
5562
|
];
|
|
5089
|
-
const found = candidates.find((c) => !!c &&
|
|
5563
|
+
const found = candidates.find((c) => !!c && fs36.existsSync(c));
|
|
5090
5564
|
if (found) return found;
|
|
5091
5565
|
throw new OniroError(
|
|
5092
5566
|
"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."
|
|
@@ -5100,13 +5574,13 @@ function redactArgs(args) {
|
|
|
5100
5574
|
return args.map((arg, i) => args[i - 1] === "-keyPwd" || args[i - 1] === "-keystorePwd" ? "******" : arg);
|
|
5101
5575
|
}
|
|
5102
5576
|
async function generateKeystoreAndCsr(opts) {
|
|
5103
|
-
const jar =
|
|
5104
|
-
if (!
|
|
5577
|
+
const jar = path35.join(opts.sdk.sdkPath, "default", "openharmony", "toolchains", "lib", "hap-sign-tool.jar");
|
|
5578
|
+
if (!fs37.existsSync(jar)) {
|
|
5105
5579
|
throw new OniroError(`hap-sign-tool.jar not found at ${jar}; the HarmonyOS SDK looks incomplete.`);
|
|
5106
5580
|
}
|
|
5107
5581
|
const java = findJava(opts.sdk);
|
|
5108
5582
|
const keyPwd = crypto7.randomBytes(12).toString("base64url").replaceAll(/[-_]/g, "");
|
|
5109
|
-
|
|
5583
|
+
fs37.mkdirSync(path35.dirname(opts.p12Path), { recursive: true, mode: 448 });
|
|
5110
5584
|
const run = async (what, args) => {
|
|
5111
5585
|
const argv = ["-jar", jar, ...args, "-keyAlias", KEY_ALIAS, "-keystoreFile", opts.p12Path, "-keystorePwd", keyPwd, "-keyPwd", keyPwd];
|
|
5112
5586
|
opts.logger.debug(`[harmonyos] ${java} ${redactArgs(argv).join(" ")}`);
|
|
@@ -5120,28 +5594,28 @@ ${detail}` : ""}`);
|
|
|
5120
5594
|
opts.logger.info("[harmonyos] Generating the local keystore and certificate signing request...");
|
|
5121
5595
|
await run("generate the key pair", ["generate-keypair", "-keyAlg", "ECC", "-keySize", "NIST-P-256"]);
|
|
5122
5596
|
await run("generate the CSR", ["generate-csr", "-subject", "CN=DebugKey", "-signAlg", SIGN_ALG, "-outFile", opts.csrPath]);
|
|
5123
|
-
return { keyPwd, csr:
|
|
5597
|
+
return { keyPwd, csr: fs37.readFileSync(opts.csrPath, "utf8") };
|
|
5124
5598
|
}
|
|
5125
5599
|
|
|
5126
5600
|
// src/harmonyos/signing/paths.ts
|
|
5127
5601
|
var crypto8 = __toESM(require("crypto"), 1);
|
|
5128
|
-
var
|
|
5602
|
+
var path36 = __toESM(require("path"), 1);
|
|
5129
5603
|
function sanitizeNamePart(raw) {
|
|
5130
5604
|
const safe = (raw?.trim() ?? "").replace(/[\\/:*?"<>|=.-]+/g, "_");
|
|
5131
5605
|
return safe.slice(0, 64) || "default";
|
|
5132
5606
|
}
|
|
5133
5607
|
function resolveSigningMaterialPaths(config, productName, projectRoot) {
|
|
5134
5608
|
const hash = crypto8.createHash("sha256").update(projectRoot, "utf8").digest("base64url").replaceAll(/[-_]/g, "");
|
|
5135
|
-
const base =
|
|
5609
|
+
const base = path36.join(
|
|
5136
5610
|
config.get("harmonyosSigningDir", defaultPaths.harmonyosSigningDir()),
|
|
5137
|
-
`${sanitizeNamePart(productName)}_${
|
|
5611
|
+
`${sanitizeNamePart(productName)}_${path36.basename(projectRoot)}_${hash}=`
|
|
5138
5612
|
);
|
|
5139
5613
|
return { p12Path: `${base}.p12`, csrPath: `${base}.csr`, cerPath: `${base}.cer`, profilePath: `${base}.p7b` };
|
|
5140
5614
|
}
|
|
5141
5615
|
|
|
5142
5616
|
// src/harmonyos/signing/project.ts
|
|
5143
|
-
var
|
|
5144
|
-
var
|
|
5617
|
+
var fs38 = __toESM(require("fs"), 1);
|
|
5618
|
+
var path37 = __toESM(require("path"), 1);
|
|
5145
5619
|
var import_json56 = __toESM(require("json5"), 1);
|
|
5146
5620
|
|
|
5147
5621
|
// src/harmonyos/signing/aclPermissionList.ts
|
|
@@ -5209,9 +5683,9 @@ var ACL_PERMISSIONS = /* @__PURE__ */ new Set([
|
|
|
5209
5683
|
|
|
5210
5684
|
// src/harmonyos/signing/project.ts
|
|
5211
5685
|
function readRequestedPermissions(moduleConfigPath) {
|
|
5212
|
-
if (!
|
|
5686
|
+
if (!fs38.existsSync(moduleConfigPath)) return [];
|
|
5213
5687
|
try {
|
|
5214
|
-
const parsed = import_json56.default.parse(
|
|
5688
|
+
const parsed = import_json56.default.parse(fs38.readFileSync(moduleConfigPath, "utf-8"));
|
|
5215
5689
|
return (parsed.module?.requestPermissions ?? []).map((p) => p?.name).filter((n) => typeof n === "string" && n.length > 0);
|
|
5216
5690
|
} catch {
|
|
5217
5691
|
return [];
|
|
@@ -5220,10 +5694,10 @@ function readRequestedPermissions(moduleConfigPath) {
|
|
|
5220
5694
|
function collectAclPermissions(projectDir, logger = noopLogger) {
|
|
5221
5695
|
const requested = /* @__PURE__ */ new Set();
|
|
5222
5696
|
for (const module2 of listModules({ projectDir })) {
|
|
5223
|
-
const moduleRoot =
|
|
5697
|
+
const moduleRoot = path37.resolve(projectDir, module2.srcPath);
|
|
5224
5698
|
for (const sourceSet of ["main", "ohosTest"]) {
|
|
5225
5699
|
for (const name of readRequestedPermissions(
|
|
5226
|
-
|
|
5700
|
+
path37.join(moduleRoot, "src", sourceSet, "module.json5")
|
|
5227
5701
|
)) {
|
|
5228
5702
|
requested.add(name);
|
|
5229
5703
|
}
|
|
@@ -5239,7 +5713,7 @@ function collectAclPermissions(projectDir, logger = noopLogger) {
|
|
|
5239
5713
|
// src/harmonyos/signing/autoSign.ts
|
|
5240
5714
|
function shouldRegenerate(input) {
|
|
5241
5715
|
if (input.force) return "--force was passed";
|
|
5242
|
-
const missing = Object.values(input.paths).find((file) => !
|
|
5716
|
+
const missing = Object.values(input.paths).find((file) => !fs39.existsSync(file));
|
|
5243
5717
|
if (missing) return `${missing} is missing`;
|
|
5244
5718
|
const config = input.buildProfile.app?.signingConfigs?.find((c) => c.name === input.productName);
|
|
5245
5719
|
if (config?.type !== "HarmonyOS" || config.material?.profile !== input.paths.profilePath) {
|
|
@@ -5278,16 +5752,16 @@ function writeSigningConfig(opts) {
|
|
|
5278
5752
|
for (const product of app.products ?? []) {
|
|
5279
5753
|
if (product.name === opts.productName) product.signingConfig = opts.productName;
|
|
5280
5754
|
}
|
|
5281
|
-
|
|
5755
|
+
fs39.writeFileSync(opts.buildProfilePath, JSON.stringify(opts.buildProfile, null, 2));
|
|
5282
5756
|
}
|
|
5283
5757
|
async function harmonyOsAutoSign(opts) {
|
|
5284
5758
|
const logger = opts.logger ?? noopLogger;
|
|
5285
5759
|
const productName = opts.productName ?? "default";
|
|
5286
|
-
const projectDir =
|
|
5287
|
-
const buildProfilePath =
|
|
5760
|
+
const projectDir = path38.resolve(opts.projectDir);
|
|
5761
|
+
const buildProfilePath = path38.join(projectDir, "build-profile.json5");
|
|
5288
5762
|
let buildProfile;
|
|
5289
5763
|
try {
|
|
5290
|
-
buildProfile = import_json57.default.parse(
|
|
5764
|
+
buildProfile = import_json57.default.parse(fs39.readFileSync(buildProfilePath, "utf-8"));
|
|
5291
5765
|
} catch (err) {
|
|
5292
5766
|
throw new OniroError(`Could not read ${buildProfilePath}: ${err.message}`, err);
|
|
5293
5767
|
}
|
|
@@ -5327,7 +5801,7 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5327
5801
|
logger.info(`[harmonyos] Regenerating signing material: ${reason}.`);
|
|
5328
5802
|
const agc = createAgcClient(opts.http ?? createHttpClient({ logger }), auth);
|
|
5329
5803
|
const deviceIds = await registerDevices(agc, connected, logger);
|
|
5330
|
-
for (const file of Object.values(paths))
|
|
5804
|
+
for (const file of Object.values(paths)) fs39.rmSync(file, { force: true });
|
|
5331
5805
|
const certName = `oniro_debug_${auth.teamId.replace(/[\\/.:]/g, "")}.cer`;
|
|
5332
5806
|
const stale = (await agc.listCertificates()).find((c) => c.certName === certName);
|
|
5333
5807
|
if (stale) {
|
|
@@ -5358,10 +5832,10 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5358
5832
|
try {
|
|
5359
5833
|
verifySigningMaterial({ ...paths, keyAlias: KEY_ALIAS, keyPwd });
|
|
5360
5834
|
} catch (err) {
|
|
5361
|
-
|
|
5835
|
+
fs39.rmSync(paths.profilePath, { force: true });
|
|
5362
5836
|
throw err;
|
|
5363
5837
|
}
|
|
5364
|
-
const materialDir =
|
|
5838
|
+
const materialDir = path38.join(path38.dirname(paths.p12Path), "material");
|
|
5365
5839
|
try {
|
|
5366
5840
|
getKey(materialDir);
|
|
5367
5841
|
} catch {
|
|
@@ -5373,7 +5847,7 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5373
5847
|
}
|
|
5374
5848
|
|
|
5375
5849
|
// src/index.ts
|
|
5376
|
-
var VERSION = "0.
|
|
5850
|
+
var VERSION = "0.14.0";
|
|
5377
5851
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5378
5852
|
0 && (module.exports = {
|
|
5379
5853
|
ALL_SDKS,
|
|
@@ -5396,7 +5870,9 @@ var VERSION = "0.13.0";
|
|
|
5396
5870
|
TargetNotFoundError,
|
|
5397
5871
|
UnsupportedPlatformError,
|
|
5398
5872
|
VERSION,
|
|
5873
|
+
appSandboxDir,
|
|
5399
5874
|
applyChanges,
|
|
5875
|
+
assertDevicePath,
|
|
5400
5876
|
assertLayoutSelector,
|
|
5401
5877
|
attemptHdcConnection,
|
|
5402
5878
|
buildCmdWrapper,
|
|
@@ -5407,6 +5883,8 @@ var VERSION = "0.13.0";
|
|
|
5407
5883
|
buildInputCommand,
|
|
5408
5884
|
buildRawTouchCommand,
|
|
5409
5885
|
captureBurst,
|
|
5886
|
+
captureLog,
|
|
5887
|
+
cleanCodelinterOutput,
|
|
5410
5888
|
consoleLogger,
|
|
5411
5889
|
createHarmonyOsSession,
|
|
5412
5890
|
createInstallTempDir,
|
|
@@ -5422,9 +5900,12 @@ var VERSION = "0.13.0";
|
|
|
5422
5900
|
defaultPaths,
|
|
5423
5901
|
describeLayoutNode,
|
|
5424
5902
|
detectAaStartFailure,
|
|
5903
|
+
detectCmdToolsFlavour,
|
|
5904
|
+
detectInstallFailure,
|
|
5425
5905
|
detectProjectSdkVersion,
|
|
5426
5906
|
detectRuntimeOs,
|
|
5427
5907
|
detectSigningConfigNames,
|
|
5908
|
+
diagnoseBuildFailure,
|
|
5428
5909
|
diffEntryNames,
|
|
5429
5910
|
diffHapAssets,
|
|
5430
5911
|
discoverHaps,
|
|
@@ -5437,11 +5918,13 @@ var VERSION = "0.13.0";
|
|
|
5437
5918
|
dumpWindow,
|
|
5438
5919
|
encryptPwd,
|
|
5439
5920
|
ensureFreeSpace,
|
|
5921
|
+
ensureInstallOk,
|
|
5440
5922
|
ensureOhModules,
|
|
5441
5923
|
ensureOk,
|
|
5442
5924
|
ensureRemoteOk,
|
|
5443
5925
|
escapeCmdArgument,
|
|
5444
5926
|
escapeCmdCommand,
|
|
5927
|
+
existingHapOrUnsigned,
|
|
5445
5928
|
extractTarball,
|
|
5446
5929
|
extractZipWithProgress,
|
|
5447
5930
|
findAppProcessId,
|
|
@@ -5450,6 +5933,7 @@ var VERSION = "0.13.0";
|
|
|
5450
5933
|
findHarmonyOsSdk,
|
|
5451
5934
|
findKeyboardWindow,
|
|
5452
5935
|
findLayoutNodes,
|
|
5936
|
+
findMissingProjectSdk,
|
|
5453
5937
|
findRunningProcess,
|
|
5454
5938
|
flattenLayout,
|
|
5455
5939
|
forceStop,
|
|
@@ -5463,6 +5947,7 @@ var VERSION = "0.13.0";
|
|
|
5463
5947
|
getDeviceInfo,
|
|
5464
5948
|
getDisplaySize,
|
|
5465
5949
|
getEmulatorDir,
|
|
5950
|
+
getEmulatorStatus,
|
|
5466
5951
|
getFreeSpaceBytes,
|
|
5467
5952
|
getHdcPath,
|
|
5468
5953
|
getHvigorwPath,
|
|
@@ -5478,15 +5963,21 @@ var VERSION = "0.13.0";
|
|
|
5478
5963
|
getSupportedSdksForUi,
|
|
5479
5964
|
harmonyOsAutoSign,
|
|
5480
5965
|
harmonyOsSdkLabelForApi,
|
|
5966
|
+
hdcClientFailure,
|
|
5481
5967
|
hdcExec,
|
|
5968
|
+
hdcTargetArgs,
|
|
5969
|
+
hdcTargetArgsFor,
|
|
5482
5970
|
hideKeyboard,
|
|
5483
5971
|
installApp,
|
|
5484
5972
|
installCmdTools,
|
|
5485
5973
|
installEmulator,
|
|
5974
|
+
installFailureReason,
|
|
5975
|
+
isBundleInstalled,
|
|
5486
5976
|
isCmdToolsInstalled,
|
|
5487
5977
|
isEmulatorInstalled,
|
|
5488
5978
|
isOutOfSpaceError,
|
|
5489
5979
|
isRamBackedPath,
|
|
5980
|
+
isUnsignedHap,
|
|
5490
5981
|
isValidBundleName,
|
|
5491
5982
|
isValidProjectName,
|
|
5492
5983
|
killProcessTree,
|
|
@@ -5501,16 +5992,21 @@ var VERSION = "0.13.0";
|
|
|
5501
5992
|
nonInteractivePrompter,
|
|
5502
5993
|
noopLogger,
|
|
5503
5994
|
noopProgress,
|
|
5995
|
+
normaliseLocalPath,
|
|
5504
5996
|
paramGet,
|
|
5997
|
+
paramGetMany,
|
|
5505
5998
|
paramSet,
|
|
5506
5999
|
parseBounds,
|
|
5507
6000
|
parseCodelinterFindings,
|
|
6001
|
+
parseCodelinterReport,
|
|
5508
6002
|
parseDeviceList,
|
|
5509
6003
|
parseHilogLine,
|
|
5510
6004
|
parseImeBundles,
|
|
5511
6005
|
parseMainAbilityFromBmDump,
|
|
6006
|
+
parseParamValues,
|
|
5512
6007
|
parseRemoteExit,
|
|
5513
6008
|
performInput,
|
|
6009
|
+
pickHap,
|
|
5514
6010
|
pickSigningKind,
|
|
5515
6011
|
pickTarget,
|
|
5516
6012
|
prepareSigning,
|
|
@@ -5525,6 +6021,7 @@ var VERSION = "0.13.0";
|
|
|
5525
6021
|
removeSdk,
|
|
5526
6022
|
removeTempWorkDir,
|
|
5527
6023
|
requireHarmonyOsSdk,
|
|
6024
|
+
resolveDeviceSerial,
|
|
5528
6025
|
resolveKeyEvent,
|
|
5529
6026
|
resolveTmpRoot,
|
|
5530
6027
|
runCodelinter,
|
|
@@ -5549,6 +6046,7 @@ var VERSION = "0.13.0";
|
|
|
5549
6046
|
toLongPath,
|
|
5550
6047
|
toSpaceError,
|
|
5551
6048
|
uninstallApp,
|
|
6049
|
+
unsignedHapRejection,
|
|
5552
6050
|
validateTemplateLayout,
|
|
5553
6051
|
verifySha256,
|
|
5554
6052
|
waitForBoot,
|