@oniroproject/core 0.13.0 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -9
- package/dist/index.cjs +818 -310
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +276 -25
- package/dist/index.d.ts +276 -25
- package/dist/index.js +794 -310
- 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);
|
|
@@ -1783,6 +1849,7 @@ var import_node_child_process4 = require("child_process");
|
|
|
1783
1849
|
|
|
1784
1850
|
// src/hdc/exec.ts
|
|
1785
1851
|
var fs15 = __toESM(require("fs"), 1);
|
|
1852
|
+
var import_node_string_decoder = require("string_decoder");
|
|
1786
1853
|
function errorMessage(err) {
|
|
1787
1854
|
return err instanceof Error ? err.message : String(err);
|
|
1788
1855
|
}
|
|
@@ -1790,7 +1857,7 @@ function runProcess(opts) {
|
|
|
1790
1857
|
const { command, args, cwd, env, onOutput } = opts;
|
|
1791
1858
|
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
1792
1859
|
const { abortSignal } = opts;
|
|
1793
|
-
return new Promise((
|
|
1860
|
+
return new Promise((resolve7, reject) => {
|
|
1794
1861
|
if (abortSignal?.aborted) {
|
|
1795
1862
|
reject(new CancelledError(`Command aborted before start: ${command}`));
|
|
1796
1863
|
return;
|
|
@@ -1810,6 +1877,8 @@ function runProcess(opts) {
|
|
|
1810
1877
|
let stderr = "";
|
|
1811
1878
|
let settled = false;
|
|
1812
1879
|
let timedOut = false;
|
|
1880
|
+
const stdoutDecoder = new import_node_string_decoder.StringDecoder("utf8");
|
|
1881
|
+
const stderrDecoder = new import_node_string_decoder.StringDecoder("utf8");
|
|
1813
1882
|
const cleanup = () => {
|
|
1814
1883
|
clearTimeout(timer);
|
|
1815
1884
|
abortSignal?.removeEventListener("abort", onAbort);
|
|
@@ -1827,14 +1896,14 @@ function runProcess(opts) {
|
|
|
1827
1896
|
}, timeoutMs);
|
|
1828
1897
|
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
1829
1898
|
child.stdout?.on("data", (d) => {
|
|
1830
|
-
const s =
|
|
1899
|
+
const s = stdoutDecoder.write(d);
|
|
1831
1900
|
stdout += s;
|
|
1832
|
-
onOutput?.(s, "stdout");
|
|
1901
|
+
if (s) onOutput?.(s, "stdout");
|
|
1833
1902
|
});
|
|
1834
1903
|
child.stderr?.on("data", (d) => {
|
|
1835
|
-
const s =
|
|
1904
|
+
const s = stderrDecoder.write(d);
|
|
1836
1905
|
stderr += s;
|
|
1837
|
-
onOutput?.(s, "stderr");
|
|
1906
|
+
if (s) onOutput?.(s, "stderr");
|
|
1838
1907
|
});
|
|
1839
1908
|
child.on("error", (err) => {
|
|
1840
1909
|
if (settled) return;
|
|
@@ -1846,6 +1915,12 @@ function runProcess(opts) {
|
|
|
1846
1915
|
if (settled) return;
|
|
1847
1916
|
settled = true;
|
|
1848
1917
|
cleanup();
|
|
1918
|
+
const stdoutTail = stdoutDecoder.end();
|
|
1919
|
+
const stderrTail = stderrDecoder.end();
|
|
1920
|
+
stdout += stdoutTail;
|
|
1921
|
+
stderr += stderrTail;
|
|
1922
|
+
if (stdoutTail) onOutput?.(stdoutTail, "stdout");
|
|
1923
|
+
if (stderrTail) onOutput?.(stderrTail, "stderr");
|
|
1849
1924
|
if (timedOut) {
|
|
1850
1925
|
reject(
|
|
1851
1926
|
new OniroError(
|
|
@@ -1855,21 +1930,41 @@ ${stderr.trim()}` : "")
|
|
|
1855
1930
|
);
|
|
1856
1931
|
return;
|
|
1857
1932
|
}
|
|
1858
|
-
|
|
1933
|
+
resolve7({ code: code ?? -1, stdout, stderr });
|
|
1859
1934
|
});
|
|
1860
1935
|
});
|
|
1861
1936
|
}
|
|
1862
|
-
function
|
|
1937
|
+
function resolveDeviceSerial(explicit, env = process.env) {
|
|
1938
|
+
if (explicit && explicit !== "auto") return explicit;
|
|
1939
|
+
const fromEnv = env.ONIRO_DEVICE_SERIAL || env.DEVICE_SERIAL;
|
|
1940
|
+
return fromEnv && fromEnv !== "auto" ? fromEnv : void 0;
|
|
1941
|
+
}
|
|
1942
|
+
function hdcTargetArgs(explicit) {
|
|
1943
|
+
const serial = resolveDeviceSerial(explicit);
|
|
1944
|
+
return serial ? ["-t", serial] : [];
|
|
1945
|
+
}
|
|
1946
|
+
var HOST_COMMANDS = /* @__PURE__ */ new Set(["list", "tconn", "start", "kill", "version", "checkserver"]);
|
|
1947
|
+
function hdcTargetArgsFor(args, explicit) {
|
|
1948
|
+
if (HOST_COMMANDS.has(args[0] ?? "")) return explicit ? ["-t", explicit] : [];
|
|
1949
|
+
return hdcTargetArgs(explicit);
|
|
1950
|
+
}
|
|
1951
|
+
function hdcClientFailure(output) {
|
|
1952
|
+
const first = output.split(/\r?\n/).find((l) => l.trim() !== "")?.trim() ?? "";
|
|
1953
|
+
return first.startsWith("[Fail]") ? first : null;
|
|
1954
|
+
}
|
|
1955
|
+
async function hdcExec(opts) {
|
|
1863
1956
|
const hdc = getHdcPath(opts.config);
|
|
1864
|
-
const
|
|
1865
|
-
return runProcess({
|
|
1957
|
+
const res = await runProcess({
|
|
1866
1958
|
command: hdc,
|
|
1867
|
-
args:
|
|
1959
|
+
args: [...hdcTargetArgsFor(opts.args, opts.deviceSerial), ...opts.args],
|
|
1868
1960
|
timeoutMs: opts.timeoutMs,
|
|
1869
1961
|
abortSignal: opts.abortSignal,
|
|
1870
1962
|
onOutput: opts.onOutput,
|
|
1871
1963
|
logger: opts.logger
|
|
1872
1964
|
});
|
|
1965
|
+
if (res.code === 0 && hdcClientFailure(`${res.stdout}
|
|
1966
|
+
${res.stderr}`)) return { ...res, code: 1 };
|
|
1967
|
+
return res;
|
|
1873
1968
|
}
|
|
1874
1969
|
function shell(opts) {
|
|
1875
1970
|
const { command, ...rest } = opts;
|
|
@@ -1877,10 +1972,15 @@ function shell(opts) {
|
|
|
1877
1972
|
}
|
|
1878
1973
|
function ensureOk(result, command) {
|
|
1879
1974
|
if (result.code !== 0) {
|
|
1880
|
-
throw new CommandFailedError(command, result.code, result.stderr.trim());
|
|
1975
|
+
throw new CommandFailedError(command, result.code, withTargetHint(result.stderr.trim() || result.stdout.trim()));
|
|
1881
1976
|
}
|
|
1882
1977
|
return result;
|
|
1883
1978
|
}
|
|
1979
|
+
function withTargetHint(detail) {
|
|
1980
|
+
if (!/need connect-key|Not match target/i.test(detail)) return detail;
|
|
1981
|
+
return `${detail}
|
|
1982
|
+
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\`.`;
|
|
1983
|
+
}
|
|
1884
1984
|
var REMOTE_RC_RE = /__ONIRO_RC=(-?\d+)__/g;
|
|
1885
1985
|
function parseRemoteExit(stdout) {
|
|
1886
1986
|
let code = null;
|
|
@@ -1897,7 +1997,7 @@ async function shellChecked(opts) {
|
|
|
1897
1997
|
}
|
|
1898
1998
|
function ensureRemoteOk(result, command) {
|
|
1899
1999
|
if (result.code !== 0) {
|
|
1900
|
-
throw new CommandFailedError(command, result.code, result.stderr.trim() || result.stdout.trim());
|
|
2000
|
+
throw new CommandFailedError(command, result.code, withTargetHint(result.stderr.trim() || result.stdout.trim()));
|
|
1901
2001
|
}
|
|
1902
2002
|
return result;
|
|
1903
2003
|
}
|
|
@@ -1983,11 +2083,11 @@ async function startEmulator(opts) {
|
|
|
1983
2083
|
fs16.writeFileSync(PID_FILE, String(child.pid));
|
|
1984
2084
|
child.unref();
|
|
1985
2085
|
logger.info(`Emulator launched (PID ${child.pid}). Logs: ${logPath}`);
|
|
1986
|
-
const earlyExit = new Promise((
|
|
1987
|
-
child.once("exit", (code) =>
|
|
1988
|
-
child.once("error", () =>
|
|
2086
|
+
const earlyExit = new Promise((resolve7) => {
|
|
2087
|
+
child.once("exit", (code) => resolve7(code));
|
|
2088
|
+
child.once("error", () => resolve7(-1));
|
|
1989
2089
|
});
|
|
1990
|
-
const liveness = new Promise((
|
|
2090
|
+
const liveness = new Promise((resolve7) => setTimeout(() => resolve7("alive"), 2e3));
|
|
1991
2091
|
const outcome = await Promise.race([earlyExit, liveness]);
|
|
1992
2092
|
if (outcome !== "alive") {
|
|
1993
2093
|
const tail = readTail(logPath, 4e3);
|
|
@@ -2067,10 +2167,48 @@ async function stopEmulator(logger = noopLogger) {
|
|
|
2067
2167
|
if (err) logger.warn(`Could not remove PID file: ${err.message}`);
|
|
2068
2168
|
});
|
|
2069
2169
|
}
|
|
2170
|
+
async function isQemuRunning(logger) {
|
|
2171
|
+
if (os8.platform() !== "win32") {
|
|
2172
|
+
try {
|
|
2173
|
+
const pid = Number(fs16.readFileSync(PID_FILE, "utf8").trim());
|
|
2174
|
+
if (Number.isFinite(pid) && pid > 0) {
|
|
2175
|
+
process.kill(pid, 0);
|
|
2176
|
+
return true;
|
|
2177
|
+
}
|
|
2178
|
+
} catch {
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
const [cmd, ...args] = os8.platform() === "win32" ? ["tasklist", "/FI", "IMAGENAME eq qemu-system-x86_64.exe", "/NH"] : ["pgrep", "-f", "qemu-system-x86_64"];
|
|
2182
|
+
try {
|
|
2183
|
+
const res = await runProcess({ command: cmd, args, timeoutMs: 1e4, logger });
|
|
2184
|
+
return os8.platform() === "win32" ? /qemu-system-x86_64/i.test(res.stdout) : res.code === 0;
|
|
2185
|
+
} catch {
|
|
2186
|
+
return false;
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
async function getEmulatorStatus(config, opts = {}) {
|
|
2190
|
+
const logger = opts.logger ?? noopLogger;
|
|
2191
|
+
const address = opts.address ?? "127.0.0.1:55555";
|
|
2192
|
+
const dir = getEmulatorDir(config);
|
|
2193
|
+
let connected = false;
|
|
2194
|
+
try {
|
|
2195
|
+
const targets = await hdcExec({ config, args: ["list", "targets", "-v"], timeoutMs: 1e4, logger });
|
|
2196
|
+
connected = targets.stdout.split("\n").some((l) => l.trim().startsWith(address) && /\bConnected\b/.test(l));
|
|
2197
|
+
} catch {
|
|
2198
|
+
}
|
|
2199
|
+
return {
|
|
2200
|
+
installed: isEmulatorInstalled(config),
|
|
2201
|
+
dir,
|
|
2202
|
+
running: await isQemuRunning(logger),
|
|
2203
|
+
address,
|
|
2204
|
+
connected
|
|
2205
|
+
};
|
|
2206
|
+
}
|
|
2070
2207
|
|
|
2071
2208
|
// src/hdc/devices.ts
|
|
2072
2209
|
var STATUS_TOKENS = /* @__PURE__ */ new Set([
|
|
2073
2210
|
"Connected",
|
|
2211
|
+
"Ready",
|
|
2074
2212
|
"Offline",
|
|
2075
2213
|
"Unauthorized",
|
|
2076
2214
|
"Authorizing",
|
|
@@ -2105,9 +2243,8 @@ async function listDevices(config, opts = {}) {
|
|
|
2105
2243
|
return parseDeviceList(res.stdout);
|
|
2106
2244
|
}
|
|
2107
2245
|
async function selectDevice(config, serial, opts = {}) {
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
if (envSerial && envSerial !== "auto") return envSerial;
|
|
2246
|
+
const resolved = resolveDeviceSerial(serial);
|
|
2247
|
+
if (resolved) return resolved;
|
|
2111
2248
|
const usable = (await listDevices(config, opts)).filter(
|
|
2112
2249
|
(d) => d.status === "Connected" || d.status === "Unknown"
|
|
2113
2250
|
);
|
|
@@ -2121,6 +2258,7 @@ async function selectDevice(config, serial, opts = {}) {
|
|
|
2121
2258
|
}
|
|
2122
2259
|
|
|
2123
2260
|
// src/hdc/param.ts
|
|
2261
|
+
var PARAM_MISSING_RE = /^Get parameter ".*" fail!/;
|
|
2124
2262
|
async function paramGet(config, key, opts = {}) {
|
|
2125
2263
|
const res = await shell({
|
|
2126
2264
|
config,
|
|
@@ -2130,7 +2268,30 @@ async function paramGet(config, key, opts = {}) {
|
|
|
2130
2268
|
logger: opts.logger
|
|
2131
2269
|
});
|
|
2132
2270
|
ensureOk(res, `hdc shell param get ${key}`);
|
|
2133
|
-
|
|
2271
|
+
const value = res.stdout.trim();
|
|
2272
|
+
if (PARAM_MISSING_RE.test(value)) throw new OniroError(`System parameter ${key} is not set: ${value}`);
|
|
2273
|
+
return value;
|
|
2274
|
+
}
|
|
2275
|
+
var PARAM_SEPARATOR = "__ONIRO_PARAM__";
|
|
2276
|
+
function parseParamValues(keys, stdout) {
|
|
2277
|
+
const parts = stdout.split(PARAM_SEPARATOR);
|
|
2278
|
+
const values = {};
|
|
2279
|
+
keys.forEach((key, i) => {
|
|
2280
|
+
const value = parts[i]?.trim();
|
|
2281
|
+
values[key] = value && !PARAM_MISSING_RE.test(value) ? value : void 0;
|
|
2282
|
+
});
|
|
2283
|
+
return values;
|
|
2284
|
+
}
|
|
2285
|
+
async function paramGetMany(config, keys, opts = {}) {
|
|
2286
|
+
const res = await shell({
|
|
2287
|
+
config,
|
|
2288
|
+
command: keys.map((k) => `param get ${k}; echo ${PARAM_SEPARATOR}`).join("; "),
|
|
2289
|
+
deviceSerial: opts.deviceSerial,
|
|
2290
|
+
timeoutMs: opts.timeoutMs ?? 1e4,
|
|
2291
|
+
logger: opts.logger
|
|
2292
|
+
});
|
|
2293
|
+
ensureOk(res, "hdc shell param get \u2026");
|
|
2294
|
+
return parseParamValues(keys, res.stdout);
|
|
2134
2295
|
}
|
|
2135
2296
|
async function paramSet(config, key, value, opts = {}) {
|
|
2136
2297
|
const res = await shell({
|
|
@@ -2144,29 +2305,66 @@ async function paramSet(config, key, value, opts = {}) {
|
|
|
2144
2305
|
}
|
|
2145
2306
|
|
|
2146
2307
|
// src/hdc/files.ts
|
|
2308
|
+
var path17 = __toESM(require("path"), 1);
|
|
2309
|
+
function normaliseLocalPath(local) {
|
|
2310
|
+
const abs = path17.resolve(local);
|
|
2311
|
+
const long = toLongPath(abs);
|
|
2312
|
+
return long !== abs ? long : path17.join(toLongPath(path17.dirname(abs)), path17.basename(abs));
|
|
2313
|
+
}
|
|
2314
|
+
function assertDevicePath(remote) {
|
|
2315
|
+
if (/^[A-Za-z]:[\\/]/.test(remote)) {
|
|
2316
|
+
throw new OniroError(
|
|
2317
|
+
`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.`
|
|
2318
|
+
);
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
function appSandboxDir(bundle) {
|
|
2322
|
+
return `/data/app/el2/100/base/${bundle}`;
|
|
2323
|
+
}
|
|
2324
|
+
function shQuote(s) {
|
|
2325
|
+
return `'${s.replace(/'/g, `'\\''`)}'`;
|
|
2326
|
+
}
|
|
2147
2327
|
async function sendFile(opts) {
|
|
2328
|
+
assertDevicePath(opts.remote);
|
|
2329
|
+
const local = normaliseLocalPath(opts.local);
|
|
2330
|
+
const sandbox = opts.bundle ? appSandboxDir(opts.bundle) : void 0;
|
|
2331
|
+
const remote = sandbox && !opts.remote.startsWith("/") ? path17.posix.join(sandbox, opts.remote) : opts.remote;
|
|
2332
|
+
if (sandbox && !remote.startsWith(`${sandbox}/`)) {
|
|
2333
|
+
throw new OniroError(`${remote} is outside the sandbox of ${opts.bundle} (${sandbox}).`);
|
|
2334
|
+
}
|
|
2335
|
+
const device = { config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger };
|
|
2336
|
+
if (sandbox) {
|
|
2337
|
+
const mkdir = `mkdir -p ${shQuote(path17.posix.dirname(remote))}`;
|
|
2338
|
+
ensureRemoteOk(await shellChecked({ ...device, command: mkdir }), `hdc shell ${mkdir}`);
|
|
2339
|
+
}
|
|
2148
2340
|
const res = await hdcExec({
|
|
2149
|
-
|
|
2150
|
-
args: ["file", "send",
|
|
2151
|
-
deviceSerial: opts.deviceSerial,
|
|
2341
|
+
...device,
|
|
2342
|
+
args: ["file", "send", local, remote],
|
|
2152
2343
|
timeoutMs: opts.timeoutMs ?? 6e5,
|
|
2153
2344
|
abortSignal: opts.abortSignal,
|
|
2154
|
-
onOutput: opts.onOutput
|
|
2155
|
-
logger: opts.logger
|
|
2345
|
+
onOutput: opts.onOutput
|
|
2156
2346
|
});
|
|
2157
|
-
ensureOk(res, `hdc file send ${
|
|
2347
|
+
ensureOk(res, `hdc file send ${local} ${remote}`);
|
|
2348
|
+
if (sandbox) {
|
|
2349
|
+
const top = path17.posix.join(sandbox, path17.posix.relative(sandbox, remote).split("/")[0]);
|
|
2350
|
+
const chown = `chown -R "$(stat -c %u:%g ${shQuote(sandbox)})" ${shQuote(top)}`;
|
|
2351
|
+
ensureRemoteOk(await shellChecked({ ...device, command: chown }), `hdc shell ${chown}`);
|
|
2352
|
+
}
|
|
2353
|
+
return remote;
|
|
2158
2354
|
}
|
|
2159
2355
|
async function recvFile(opts) {
|
|
2356
|
+
assertDevicePath(opts.remote);
|
|
2357
|
+
const local = normaliseLocalPath(opts.local);
|
|
2160
2358
|
const res = await hdcExec({
|
|
2161
2359
|
config: opts.config,
|
|
2162
|
-
args: ["file", "recv", opts.remote,
|
|
2360
|
+
args: ["file", "recv", opts.remote, local],
|
|
2163
2361
|
deviceSerial: opts.deviceSerial,
|
|
2164
2362
|
timeoutMs: opts.timeoutMs ?? 6e5,
|
|
2165
2363
|
abortSignal: opts.abortSignal,
|
|
2166
2364
|
onOutput: opts.onOutput,
|
|
2167
2365
|
logger: opts.logger
|
|
2168
2366
|
});
|
|
2169
|
-
ensureOk(res, `hdc file recv ${opts.remote} ${
|
|
2367
|
+
ensureOk(res, `hdc file recv ${opts.remote} ${local}`);
|
|
2170
2368
|
}
|
|
2171
2369
|
|
|
2172
2370
|
// src/hdc/display.ts
|
|
@@ -2186,7 +2384,7 @@ async function getDisplaySize(config, opts = {}) {
|
|
|
2186
2384
|
|
|
2187
2385
|
// src/hdc/wait.ts
|
|
2188
2386
|
function delay(ms, signal) {
|
|
2189
|
-
return new Promise((
|
|
2387
|
+
return new Promise((resolve7, reject) => {
|
|
2190
2388
|
if (signal?.aborted) {
|
|
2191
2389
|
reject(new CancelledError("Wait cancelled."));
|
|
2192
2390
|
return;
|
|
@@ -2201,7 +2399,7 @@ function delay(ms, signal) {
|
|
|
2201
2399
|
};
|
|
2202
2400
|
const timer = setTimeout(() => {
|
|
2203
2401
|
cleanup();
|
|
2204
|
-
|
|
2402
|
+
resolve7();
|
|
2205
2403
|
}, ms);
|
|
2206
2404
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2207
2405
|
});
|
|
@@ -2230,20 +2428,73 @@ async function waitForCondition(opts) {
|
|
|
2230
2428
|
}
|
|
2231
2429
|
|
|
2232
2430
|
// src/hdc/app.ts
|
|
2233
|
-
var
|
|
2431
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
2432
|
+
var path20 = __toESM(require("path"), 1);
|
|
2433
|
+
|
|
2434
|
+
// src/build/discoverHaps.ts
|
|
2435
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
2234
2436
|
var path18 = __toESM(require("path"), 1);
|
|
2437
|
+
function moduleOfHap(hapFileName) {
|
|
2438
|
+
const dash = hapFileName.indexOf("-");
|
|
2439
|
+
return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
|
|
2440
|
+
}
|
|
2441
|
+
async function discoverHaps(opts) {
|
|
2442
|
+
const { projectDir } = opts;
|
|
2443
|
+
const maxDepth = opts.maxDepth ?? 8;
|
|
2444
|
+
const result = {};
|
|
2445
|
+
const walk = async (dir, depth) => {
|
|
2446
|
+
if (depth > maxDepth) return;
|
|
2447
|
+
const entries = await fs17.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
2448
|
+
for (const e of entries) {
|
|
2449
|
+
const full = path18.join(dir, e.name);
|
|
2450
|
+
if (e.isDirectory()) {
|
|
2451
|
+
if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
|
|
2452
|
+
await walk(full, depth + 1);
|
|
2453
|
+
} else if (e.isFile() && e.name.endsWith(".hap")) {
|
|
2454
|
+
const moduleName = moduleOfHap(e.name);
|
|
2455
|
+
const bucket = result[moduleName] ??= { signed: [], unsigned: [] };
|
|
2456
|
+
if (e.name.includes("unsigned")) bucket.unsigned.push(full);
|
|
2457
|
+
else if (e.name.includes("signed")) bucket.signed.push(full);
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
};
|
|
2461
|
+
await walk(projectDir, 0);
|
|
2462
|
+
const mtime = (p) => fs17.statSync(p).mtimeMs;
|
|
2463
|
+
for (const bucket of Object.values(result)) {
|
|
2464
|
+
bucket.signed.sort((a, b) => mtime(b) - mtime(a));
|
|
2465
|
+
bucket.unsigned.sort((a, b) => mtime(b) - mtime(a));
|
|
2466
|
+
}
|
|
2467
|
+
return result;
|
|
2468
|
+
}
|
|
2469
|
+
function pickHap(haps, module2) {
|
|
2470
|
+
const pick = (name) => {
|
|
2471
|
+
const signed = haps[name]?.signed[0];
|
|
2472
|
+
if (signed) return { module: name, path: signed, signed: true };
|
|
2473
|
+
const unsigned = haps[name]?.unsigned[0];
|
|
2474
|
+
return unsigned ? { module: name, path: unsigned, signed: false } : null;
|
|
2475
|
+
};
|
|
2476
|
+
if (module2) return pick(module2);
|
|
2477
|
+
const names = Object.keys(haps);
|
|
2478
|
+
const withSigned = names.filter((n) => haps[n].signed.length > 0);
|
|
2479
|
+
const candidates = withSigned.length > 0 ? withSigned : names.filter((n) => haps[n].unsigned.length > 0);
|
|
2480
|
+
if (candidates.length === 0) return null;
|
|
2481
|
+
if (candidates.length > 1) {
|
|
2482
|
+
throw new OniroError(`Multiple modules have built HAPs (${candidates.join(", ")}). Pass a module to choose.`);
|
|
2483
|
+
}
|
|
2484
|
+
return pick(candidates[0]);
|
|
2485
|
+
}
|
|
2235
2486
|
|
|
2236
2487
|
// src/hdc/project.ts
|
|
2237
|
-
var
|
|
2238
|
-
var
|
|
2488
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
2489
|
+
var path19 = __toESM(require("path"), 1);
|
|
2239
2490
|
var import_json53 = __toESM(require("json5"), 1);
|
|
2240
2491
|
function readJson5(filePath) {
|
|
2241
|
-
const content =
|
|
2492
|
+
const content = fs18.readFileSync(filePath, "utf-8");
|
|
2242
2493
|
return import_json53.default.parse(content);
|
|
2243
2494
|
}
|
|
2244
2495
|
function getBundleName(projectDir) {
|
|
2245
|
-
const appJsonPath =
|
|
2246
|
-
if (!
|
|
2496
|
+
const appJsonPath = path19.join(projectDir, "AppScope", "app.json5");
|
|
2497
|
+
if (!fs18.existsSync(appJsonPath)) {
|
|
2247
2498
|
throw new OniroError(`Could not find app.json5 at ${appJsonPath}`);
|
|
2248
2499
|
}
|
|
2249
2500
|
const appJson = readJson5(appJsonPath);
|
|
@@ -2253,8 +2504,8 @@ function getBundleName(projectDir) {
|
|
|
2253
2504
|
return appJson.app.bundleName;
|
|
2254
2505
|
}
|
|
2255
2506
|
function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
2256
|
-
const moduleJsonPath =
|
|
2257
|
-
if (!
|
|
2507
|
+
const moduleJsonPath = path19.join(projectDir, moduleName, "src", "main", "module.json5");
|
|
2508
|
+
if (!fs18.existsSync(moduleJsonPath)) {
|
|
2258
2509
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
2259
2510
|
}
|
|
2260
2511
|
const moduleJson = readJson5(moduleJsonPath);
|
|
@@ -2274,13 +2525,67 @@ function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
|
2274
2525
|
}
|
|
2275
2526
|
|
|
2276
2527
|
// src/hdc/app.ts
|
|
2528
|
+
function detectInstallFailure(output) {
|
|
2529
|
+
return /\[Fail\]|msg:\s*error|error:\s*failed to install|code:\s*95\d{5}/i.test(output) ? output.trim() : null;
|
|
2530
|
+
}
|
|
2531
|
+
function isUnsignedHap(hapPath) {
|
|
2532
|
+
return path20.basename(hapPath).includes("unsigned");
|
|
2533
|
+
}
|
|
2534
|
+
function installFailureReason(output) {
|
|
2535
|
+
const code = /code:\s*(\d+)/i.exec(output);
|
|
2536
|
+
if (!code) return output.trim().split(/\r?\n/)[0] ?? "";
|
|
2537
|
+
const message = /error:\s*([^\r\n]+)/i.exec(output.slice(code.index + code[0].length))?.[1]?.trim().replace(/\.$/, "");
|
|
2538
|
+
return message ? `code ${code[1]}: ${message}` : `code ${code[1]}`;
|
|
2539
|
+
}
|
|
2540
|
+
function unsignedHapRejection(output, hap) {
|
|
2541
|
+
const name = path20.basename(hap.path);
|
|
2542
|
+
const reason = installFailureReason(output);
|
|
2543
|
+
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}).`;
|
|
2544
|
+
if (!/9568320|signature|pkcs7/i.test(reason)) return what;
|
|
2545
|
+
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.`;
|
|
2546
|
+
}
|
|
2547
|
+
function ensureInstallOk(result, command, hap) {
|
|
2548
|
+
const output = `${result.stdout}
|
|
2549
|
+
${result.stderr}`;
|
|
2550
|
+
if (hap && isUnsignedHap(hap.path) && /code:\s*95\d{5}/i.test(output)) {
|
|
2551
|
+
throw new OniroError(unsignedHapRejection(output, hap), new CommandFailedError(command, result.code || 1, output.trim()));
|
|
2552
|
+
}
|
|
2553
|
+
ensureOk(result, command);
|
|
2554
|
+
const failure = detectInstallFailure(output);
|
|
2555
|
+
if (failure) throw new CommandFailedError(command, 1, failure);
|
|
2556
|
+
return result;
|
|
2557
|
+
}
|
|
2558
|
+
function existingHapOrUnsigned(hapPath) {
|
|
2559
|
+
if (fs19.existsSync(hapPath)) return { path: hapPath };
|
|
2560
|
+
const sibling = hapPath.replace(/-signed\.hap$/i, "-unsigned.hap");
|
|
2561
|
+
return sibling !== hapPath && fs19.existsSync(sibling) ? { path: sibling, fallback: true } : void 0;
|
|
2562
|
+
}
|
|
2563
|
+
async function resolveInstallHap(opts, logger) {
|
|
2564
|
+
const warnIfFallback = (hap) => {
|
|
2565
|
+
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path20.basename(hap.path)}.`);
|
|
2566
|
+
return hap;
|
|
2567
|
+
};
|
|
2568
|
+
const configured = opts.hapPath ?? opts.config.get("hapPath", "");
|
|
2569
|
+
const relative3 = configured || defaultPaths.hapPath;
|
|
2570
|
+
const hapPath = path20.isAbsolute(relative3) ? relative3 : path20.join(opts.projectDir, relative3);
|
|
2571
|
+
if (configured) {
|
|
2572
|
+
const hap = existingHapOrUnsigned(hapPath);
|
|
2573
|
+
if (!hap) throw new OniroError(`HAP file not found at: ${hapPath}. Build the app first.`);
|
|
2574
|
+
return warnIfFallback(hap);
|
|
2575
|
+
}
|
|
2576
|
+
if (fs19.existsSync(hapPath)) return { path: hapPath };
|
|
2577
|
+
const haps = await discoverHaps({ projectDir: opts.projectDir });
|
|
2578
|
+
const anySigned = Object.values(haps).some((m) => m.signed.length > 0);
|
|
2579
|
+
const entryUnsigned = anySigned ? void 0 : existingHapOrUnsigned(hapPath);
|
|
2580
|
+
if (entryUnsigned) return warnIfFallback(entryUnsigned);
|
|
2581
|
+
const picked = pickHap(haps);
|
|
2582
|
+
if (!picked) throw new OniroError(`No HAP found under ${opts.projectDir}. Build the app first (\`oniro-app build\`).`);
|
|
2583
|
+
return warnIfFallback({ path: picked.path, fallback: !picked.signed });
|
|
2584
|
+
}
|
|
2277
2585
|
async function installApp(opts) {
|
|
2278
2586
|
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
|
-
}
|
|
2587
|
+
const hap = await resolveInstallHap(opts, logger);
|
|
2588
|
+
const hapPath = hap.path;
|
|
2284
2589
|
const result = await hdcExec({
|
|
2285
2590
|
config: opts.config,
|
|
2286
2591
|
args: ["install", hapPath],
|
|
@@ -2289,7 +2594,7 @@ async function installApp(opts) {
|
|
|
2289
2594
|
});
|
|
2290
2595
|
if (result.stdout.trim()) logger.info(result.stdout.trim());
|
|
2291
2596
|
if (result.stderr.trim()) logger.warn(result.stderr.trim());
|
|
2292
|
-
|
|
2597
|
+
ensureInstallOk(result, `hdc install ${hapPath}`, hap);
|
|
2293
2598
|
let bundleName = "";
|
|
2294
2599
|
try {
|
|
2295
2600
|
bundleName = getBundleName(opts.projectDir);
|
|
@@ -2297,6 +2602,18 @@ async function installApp(opts) {
|
|
|
2297
2602
|
}
|
|
2298
2603
|
return { installed: true, bundleName, hapPath, output: `${result.stdout}${result.stderr}`.trim() };
|
|
2299
2604
|
}
|
|
2605
|
+
async function isBundleInstalled(opts) {
|
|
2606
|
+
const safe = opts.bundle.replace(/'/g, `'\\''`);
|
|
2607
|
+
const res = await shell({
|
|
2608
|
+
config: opts.config,
|
|
2609
|
+
command: `bm dump -n '${safe}'`,
|
|
2610
|
+
deviceSerial: opts.deviceSerial,
|
|
2611
|
+
timeoutMs: opts.timeoutMs ?? 15e3,
|
|
2612
|
+
logger: opts.logger
|
|
2613
|
+
});
|
|
2614
|
+
ensureOk(res, `hdc shell bm dump -n ${opts.bundle}`);
|
|
2615
|
+
return res.stdout.includes("{") && !/failed to get information/i.test(res.stdout);
|
|
2616
|
+
}
|
|
2300
2617
|
function detectAaStartFailure(output) {
|
|
2301
2618
|
return /failed to start ability|Error Code:\s*\d|Error Message:/i.test(output) ? output.trim() : null;
|
|
2302
2619
|
}
|
|
@@ -2367,10 +2684,10 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2367
2684
|
const logger = options.logger ?? noopLogger;
|
|
2368
2685
|
const timeoutMs = options.timeoutMs ?? 1e3;
|
|
2369
2686
|
const hdc = getHdcPath(config);
|
|
2370
|
-
return new Promise((
|
|
2687
|
+
return new Promise((resolve7, reject) => {
|
|
2371
2688
|
let proc;
|
|
2372
2689
|
try {
|
|
2373
|
-
proc = spawnCompat(hdc, ["track-jpid"]);
|
|
2690
|
+
proc = spawnCompat(hdc, [...hdcTargetArgs(options.deviceSerial), "track-jpid"]);
|
|
2374
2691
|
} catch (err) {
|
|
2375
2692
|
reject(new OniroError(`Failed to spawn ${hdc}: ${err instanceof Error ? err.message : String(err)}`, err));
|
|
2376
2693
|
return;
|
|
@@ -2387,7 +2704,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2387
2704
|
if (options.targetProcessName && name === options.targetProcessName && !resolved) {
|
|
2388
2705
|
resolved = true;
|
|
2389
2706
|
killProcessTree(proc);
|
|
2390
|
-
|
|
2707
|
+
resolve7(pid);
|
|
2391
2708
|
return;
|
|
2392
2709
|
}
|
|
2393
2710
|
}
|
|
@@ -2408,7 +2725,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2408
2725
|
if (options.targetProcessName) {
|
|
2409
2726
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
2410
2727
|
} else {
|
|
2411
|
-
|
|
2728
|
+
resolve7(processes);
|
|
2412
2729
|
}
|
|
2413
2730
|
}, timeoutMs);
|
|
2414
2731
|
proc.on("close", () => {
|
|
@@ -2418,7 +2735,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2418
2735
|
if (options.targetProcessName) {
|
|
2419
2736
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
2420
2737
|
} else {
|
|
2421
|
-
|
|
2738
|
+
resolve7(processes);
|
|
2422
2739
|
}
|
|
2423
2740
|
});
|
|
2424
2741
|
});
|
|
@@ -2440,7 +2757,11 @@ async function findRunningProcess(opts) {
|
|
|
2440
2757
|
const pid = res.stdout.trim().split(/\s+/).filter(Boolean)[0];
|
|
2441
2758
|
if (res.code === 0 && pid && /^\d+$/.test(pid)) return { pid, name: opts.bundle };
|
|
2442
2759
|
try {
|
|
2443
|
-
const list = await listRunningProcesses(opts.config, {
|
|
2760
|
+
const list = await listRunningProcesses(opts.config, {
|
|
2761
|
+
timeoutMs: 1200,
|
|
2762
|
+
deviceSerial: opts.deviceSerial,
|
|
2763
|
+
logger: opts.logger
|
|
2764
|
+
});
|
|
2444
2765
|
if (Array.isArray(list)) {
|
|
2445
2766
|
const mine = (name) => name === opts.bundle || name.startsWith(`${opts.bundle}/`) || name.startsWith(`${opts.bundle}:`);
|
|
2446
2767
|
const match = list.find((p) => p.name === opts.bundle) ?? list.find((p) => mine(p.name));
|
|
@@ -2583,12 +2904,12 @@ async function reboot(opts) {
|
|
|
2583
2904
|
}
|
|
2584
2905
|
|
|
2585
2906
|
// src/hdc/screen.ts
|
|
2586
|
-
var
|
|
2907
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
2587
2908
|
var os9 = __toESM(require("os"), 1);
|
|
2588
|
-
var
|
|
2909
|
+
var path21 = __toESM(require("path"), 1);
|
|
2589
2910
|
var import_node_crypto = require("crypto");
|
|
2590
2911
|
function tmpName(ext) {
|
|
2591
|
-
return
|
|
2912
|
+
return path21.join(os9.tmpdir(), `oniro_screen_${(0, import_node_crypto.randomBytes)(6).toString("hex")}.${ext}`);
|
|
2592
2913
|
}
|
|
2593
2914
|
async function takeScreenshot(opts) {
|
|
2594
2915
|
const remote = "/data/local/tmp/oniro_screenshot.jpeg";
|
|
@@ -2598,11 +2919,11 @@ async function takeScreenshot(opts) {
|
|
|
2598
2919
|
const local = tmpName("jpeg");
|
|
2599
2920
|
try {
|
|
2600
2921
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
2601
|
-
const pixels = await
|
|
2922
|
+
const pixels = await fs20.promises.readFile(local);
|
|
2602
2923
|
const size = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial }) ?? { width: 0, height: 0 };
|
|
2603
2924
|
return { pixels, width: size.width, height: size.height };
|
|
2604
2925
|
} finally {
|
|
2605
|
-
|
|
2926
|
+
fs20.promises.unlink(local).catch(() => {
|
|
2606
2927
|
});
|
|
2607
2928
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
2608
2929
|
});
|
|
@@ -2621,9 +2942,9 @@ async function captureBurst(opts) {
|
|
|
2621
2942
|
const local = tmpName(`burst_${i}.jpeg`);
|
|
2622
2943
|
try {
|
|
2623
2944
|
await recvFile({ config: opts.config, remote: `${remoteDir}/f${i}.jpeg`, local, deviceSerial: opts.deviceSerial });
|
|
2624
|
-
frames.push(await
|
|
2945
|
+
frames.push(await fs20.promises.readFile(local));
|
|
2625
2946
|
} finally {
|
|
2626
|
-
|
|
2947
|
+
fs20.promises.unlink(local).catch(() => {
|
|
2627
2948
|
});
|
|
2628
2949
|
}
|
|
2629
2950
|
}
|
|
@@ -2798,9 +3119,9 @@ async function sendRawTouch(opts) {
|
|
|
2798
3119
|
}
|
|
2799
3120
|
|
|
2800
3121
|
// src/hdc/dump.ts
|
|
2801
|
-
var
|
|
3122
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
2802
3123
|
var os10 = __toESM(require("os"), 1);
|
|
2803
|
-
var
|
|
3124
|
+
var path22 = __toESM(require("path"), 1);
|
|
2804
3125
|
var import_node_crypto2 = require("crypto");
|
|
2805
3126
|
|
|
2806
3127
|
// src/hdc/ime.ts
|
|
@@ -3063,10 +3384,10 @@ async function dumpLayout(opts) {
|
|
|
3063
3384
|
if (!m) throw new OniroError(`Could not parse dumpLayout output:
|
|
3064
3385
|
${dump.stdout}`);
|
|
3065
3386
|
const remote = m[1];
|
|
3066
|
-
const local =
|
|
3387
|
+
const local = path22.join(os10.tmpdir(), `oniro_layout_${(0, import_node_crypto2.randomBytes)(6).toString("hex")}.json`);
|
|
3067
3388
|
try {
|
|
3068
3389
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
3069
|
-
const parsed = JSON.parse(await
|
|
3390
|
+
const parsed = JSON.parse(await fs21.promises.readFile(local, "utf8"));
|
|
3070
3391
|
const display = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial });
|
|
3071
3392
|
if (opts.prune === false) {
|
|
3072
3393
|
return { display, tree: parsed };
|
|
@@ -3079,7 +3400,7 @@ ${dump.stdout}`);
|
|
|
3079
3400
|
const keyboard = kb ? { shown: true, bundle: kb.bundle, ...kb.b ? { b: kb.b } : {} } : { shown: false };
|
|
3080
3401
|
return { display, tree, keyboard };
|
|
3081
3402
|
} finally {
|
|
3082
|
-
|
|
3403
|
+
fs21.promises.unlink(local).catch(() => {
|
|
3083
3404
|
});
|
|
3084
3405
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
3085
3406
|
});
|
|
@@ -3089,7 +3410,7 @@ ${dump.stdout}`);
|
|
|
3089
3410
|
// src/hdc/uiActions.ts
|
|
3090
3411
|
var FOCUS_SETTLE_MS = 400;
|
|
3091
3412
|
var KEYBOARD_SETTLE_MS = 400;
|
|
3092
|
-
var sleep = (ms) => new Promise((
|
|
3413
|
+
var sleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
3093
3414
|
function targetTree(layout) {
|
|
3094
3415
|
const kb = layout.keyboard;
|
|
3095
3416
|
return kb?.shown && kb.bundle ? withoutWindow(layout.tree, kb.bundle) : layout.tree;
|
|
@@ -3242,13 +3563,14 @@ async function waitForTarget(opts) {
|
|
|
3242
3563
|
}
|
|
3243
3564
|
|
|
3244
3565
|
// src/hdc/hilog.ts
|
|
3566
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
3245
3567
|
function setHilogLevel(opts) {
|
|
3246
3568
|
const logger = opts.logger ?? noopLogger;
|
|
3247
3569
|
const hdc = getHdcPath(opts.config);
|
|
3248
|
-
return new Promise((
|
|
3570
|
+
return new Promise((resolve7, reject) => {
|
|
3249
3571
|
let child;
|
|
3250
3572
|
try {
|
|
3251
|
-
child = spawnCompat(hdc, ["shell", "hilog", "-b", opts.level]);
|
|
3573
|
+
child = spawnCompat(hdc, [...hdcTargetArgs(opts.deviceSerial), "shell", "hilog", "-b", opts.level]);
|
|
3252
3574
|
} catch (err) {
|
|
3253
3575
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3254
3576
|
logger.error(`[hilog] failed to spawn hdc: ${msg}`);
|
|
@@ -3265,7 +3587,7 @@ function setHilogLevel(opts) {
|
|
|
3265
3587
|
});
|
|
3266
3588
|
child.once("close", (code) => {
|
|
3267
3589
|
if (code === 0) {
|
|
3268
|
-
|
|
3590
|
+
resolve7();
|
|
3269
3591
|
} else {
|
|
3270
3592
|
const msg = stderr.trim() || `hdc shell hilog -b ${opts.level} exited with code ${code}`;
|
|
3271
3593
|
logger.error(`[hilog] ${msg}`);
|
|
@@ -3276,8 +3598,7 @@ function setHilogLevel(opts) {
|
|
|
3276
3598
|
}
|
|
3277
3599
|
function streamHilog(opts) {
|
|
3278
3600
|
const hdc = getHdcPath(opts.config);
|
|
3279
|
-
const args = [];
|
|
3280
|
-
if (opts.deviceSerial) args.push("-t", opts.deviceSerial);
|
|
3601
|
+
const args = [...hdcTargetArgs(opts.deviceSerial)];
|
|
3281
3602
|
args.push("shell", "hilog");
|
|
3282
3603
|
if (opts.processId && opts.processId.trim() !== "") {
|
|
3283
3604
|
args.push("-P", opts.processId.trim());
|
|
@@ -3320,7 +3641,7 @@ async function resolveProcessId(config, bundle, deviceSerial) {
|
|
|
3320
3641
|
return proc?.pid;
|
|
3321
3642
|
}
|
|
3322
3643
|
function waitForLog(opts) {
|
|
3323
|
-
return new Promise((
|
|
3644
|
+
return new Promise((resolve7, reject) => {
|
|
3324
3645
|
const deadline = Date.now() + opts.timeoutMs;
|
|
3325
3646
|
let settled = false;
|
|
3326
3647
|
let child = null;
|
|
@@ -3339,7 +3660,7 @@ function waitForLog(opts) {
|
|
|
3339
3660
|
if (settled) return;
|
|
3340
3661
|
settled = true;
|
|
3341
3662
|
cleanup();
|
|
3342
|
-
|
|
3663
|
+
resolve7(entry);
|
|
3343
3664
|
};
|
|
3344
3665
|
const fail = (err) => {
|
|
3345
3666
|
if (settled) return;
|
|
@@ -3386,7 +3707,7 @@ function waitForLog(opts) {
|
|
|
3386
3707
|
});
|
|
3387
3708
|
}
|
|
3388
3709
|
function watchLog(opts) {
|
|
3389
|
-
return new Promise((
|
|
3710
|
+
return new Promise((resolve7, reject) => {
|
|
3390
3711
|
const matches = [];
|
|
3391
3712
|
let settled = false;
|
|
3392
3713
|
let child = null;
|
|
@@ -3403,7 +3724,7 @@ function watchLog(opts) {
|
|
|
3403
3724
|
if (settled) return;
|
|
3404
3725
|
settled = true;
|
|
3405
3726
|
cleanup();
|
|
3406
|
-
|
|
3727
|
+
resolve7(opts.dedup === false ? matches : dedupEntries(matches));
|
|
3407
3728
|
};
|
|
3408
3729
|
const onAbort = () => {
|
|
3409
3730
|
if (settled) return;
|
|
@@ -3435,6 +3756,94 @@ function watchLog(opts) {
|
|
|
3435
3756
|
});
|
|
3436
3757
|
});
|
|
3437
3758
|
}
|
|
3759
|
+
async function captureLog(opts) {
|
|
3760
|
+
const logger = opts.logger ?? noopLogger;
|
|
3761
|
+
if (opts.clear) {
|
|
3762
|
+
const res = await shell({ config: opts.config, command: "hilog -r", deviceSerial: opts.deviceSerial, timeoutMs: 1e4, logger });
|
|
3763
|
+
ensureOk(res, "hdc shell hilog -r");
|
|
3764
|
+
}
|
|
3765
|
+
const fd = fs22.openSync(opts.file, "a");
|
|
3766
|
+
let lines = 0;
|
|
3767
|
+
let reconnects = 0;
|
|
3768
|
+
try {
|
|
3769
|
+
await new Promise((resolve7, reject) => {
|
|
3770
|
+
const deadline = opts.durationMs !== void 0 ? Date.now() + opts.durationMs : Infinity;
|
|
3771
|
+
let settled = false;
|
|
3772
|
+
let child = null;
|
|
3773
|
+
let reconnectTimer;
|
|
3774
|
+
let buf = "";
|
|
3775
|
+
let open = true;
|
|
3776
|
+
const write = (line) => {
|
|
3777
|
+
if (!open || opts.pattern && !opts.pattern.test(line)) return;
|
|
3778
|
+
fs22.writeSync(fd, `${line}
|
|
3779
|
+
`);
|
|
3780
|
+
lines++;
|
|
3781
|
+
};
|
|
3782
|
+
const cleanup = () => {
|
|
3783
|
+
if (timer) clearTimeout(timer);
|
|
3784
|
+
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
3785
|
+
opts.abortSignal?.removeEventListener("abort", finish);
|
|
3786
|
+
if (buf.trim()) write(buf.trimEnd());
|
|
3787
|
+
buf = "";
|
|
3788
|
+
open = false;
|
|
3789
|
+
if (child) {
|
|
3790
|
+
child.stdout.removeAllListeners("data");
|
|
3791
|
+
killProcessTree(child);
|
|
3792
|
+
child = null;
|
|
3793
|
+
}
|
|
3794
|
+
};
|
|
3795
|
+
function finish() {
|
|
3796
|
+
if (settled) return;
|
|
3797
|
+
settled = true;
|
|
3798
|
+
cleanup();
|
|
3799
|
+
resolve7();
|
|
3800
|
+
}
|
|
3801
|
+
const fail = (err) => {
|
|
3802
|
+
if (settled) return;
|
|
3803
|
+
settled = true;
|
|
3804
|
+
cleanup();
|
|
3805
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
3806
|
+
};
|
|
3807
|
+
const timer = opts.durationMs !== void 0 ? setTimeout(finish, opts.durationMs) : void 0;
|
|
3808
|
+
if (opts.abortSignal?.aborted) {
|
|
3809
|
+
finish();
|
|
3810
|
+
return;
|
|
3811
|
+
}
|
|
3812
|
+
opts.abortSignal?.addEventListener("abort", finish, { once: true });
|
|
3813
|
+
const spawnStream = () => {
|
|
3814
|
+
if (settled) return;
|
|
3815
|
+
const stream = streamHilog({ config: opts.config, domain: opts.domain, deviceSerial: opts.deviceSerial });
|
|
3816
|
+
child = stream;
|
|
3817
|
+
stream.stdout.on("data", (d) => {
|
|
3818
|
+
buf += d.toString();
|
|
3819
|
+
const parts = buf.split(/\r?\n/);
|
|
3820
|
+
buf = parts.pop() ?? "";
|
|
3821
|
+
for (const line of parts) write(line);
|
|
3822
|
+
});
|
|
3823
|
+
const onEnd = () => {
|
|
3824
|
+
if (settled || child !== stream) return;
|
|
3825
|
+
child = null;
|
|
3826
|
+
if (Date.now() >= deadline) return;
|
|
3827
|
+
reconnects++;
|
|
3828
|
+
logger.warn(`[hilog] stream ended; reconnecting (${reconnects}).`);
|
|
3829
|
+
reconnectTimer = setTimeout(() => {
|
|
3830
|
+
try {
|
|
3831
|
+
spawnStream();
|
|
3832
|
+
} catch (err) {
|
|
3833
|
+
fail(err);
|
|
3834
|
+
}
|
|
3835
|
+
}, 2e3);
|
|
3836
|
+
};
|
|
3837
|
+
stream.once("close", onEnd);
|
|
3838
|
+
stream.once("error", onEnd);
|
|
3839
|
+
};
|
|
3840
|
+
spawnStream();
|
|
3841
|
+
});
|
|
3842
|
+
} finally {
|
|
3843
|
+
fs22.closeSync(fd);
|
|
3844
|
+
}
|
|
3845
|
+
return { file: opts.file, lines, reconnects };
|
|
3846
|
+
}
|
|
3438
3847
|
async function dumpLog(opts) {
|
|
3439
3848
|
let pipe = "hilog -x";
|
|
3440
3849
|
if (opts.domain !== void 0 && `${opts.domain}` !== "") pipe += ` -D ${opts.domain}`;
|
|
@@ -3459,17 +3868,17 @@ async function dumpLog(opts) {
|
|
|
3459
3868
|
}
|
|
3460
3869
|
|
|
3461
3870
|
// src/build/runHvigorw.ts
|
|
3462
|
-
var
|
|
3463
|
-
var
|
|
3871
|
+
var fs24 = __toESM(require("fs"), 1);
|
|
3872
|
+
var path24 = __toESM(require("path"), 1);
|
|
3464
3873
|
|
|
3465
3874
|
// src/harmonyos/target.ts
|
|
3466
|
-
var
|
|
3467
|
-
var
|
|
3875
|
+
var fs23 = __toESM(require("fs"), 1);
|
|
3876
|
+
var path23 = __toESM(require("path"), 1);
|
|
3468
3877
|
var import_json54 = __toESM(require("json5"), 1);
|
|
3469
3878
|
function detectRuntimeOs(projectDir, productName) {
|
|
3470
3879
|
let products = [];
|
|
3471
3880
|
try {
|
|
3472
|
-
const parsed = import_json54.default.parse(
|
|
3881
|
+
const parsed = import_json54.default.parse(fs23.readFileSync(path23.join(projectDir, "build-profile.json5"), "utf-8"));
|
|
3473
3882
|
if (Array.isArray(parsed.app?.products)) products = parsed.app.products;
|
|
3474
3883
|
} catch {
|
|
3475
3884
|
return "OpenHarmony";
|
|
@@ -3510,7 +3919,7 @@ function runHvigorw(opts) {
|
|
|
3510
3919
|
const { config } = opts;
|
|
3511
3920
|
const projectDir = toLongPath(opts.projectDir);
|
|
3512
3921
|
const logger = opts.logger ?? noopLogger;
|
|
3513
|
-
if (!
|
|
3922
|
+
if (!fs24.existsSync(path24.join(projectDir, "build-profile.json5"))) {
|
|
3514
3923
|
throw new OniroError(`Not an OpenHarmony project: ${projectDir} (build-profile.json5 not found).`);
|
|
3515
3924
|
}
|
|
3516
3925
|
let hvigorw;
|
|
@@ -3522,24 +3931,24 @@ function runHvigorw(opts) {
|
|
|
3522
3931
|
hvigorw = resolved.startsWith(projectDir) ? resolved : findHarmonyOsTool(sdk, "hvigorw") ?? resolved;
|
|
3523
3932
|
logger.info(`[build] Building for HarmonyOS against the SDK at ${sdk.sdkPath}.`);
|
|
3524
3933
|
} else {
|
|
3525
|
-
if (!
|
|
3934
|
+
if (!fs24.existsSync(getCmdToolsPath(config))) {
|
|
3526
3935
|
throw new CmdToolsNotInstalledError(getCmdToolsPath(config));
|
|
3527
3936
|
}
|
|
3528
3937
|
sdkEnv = { OHOS_BASE_SDK_HOME: getOhosBaseSdkHome(config) };
|
|
3529
3938
|
hvigorw = getHvigorwPath(config, projectDir);
|
|
3530
3939
|
}
|
|
3531
|
-
if (!
|
|
3940
|
+
if (!fs24.existsSync(hvigorw)) {
|
|
3532
3941
|
throw new OniroError(`hvigorw wrapper not found at ${hvigorw}.`);
|
|
3533
3942
|
}
|
|
3534
3943
|
const args = buildHvigorwArgs(opts);
|
|
3535
3944
|
if (process.platform !== "win32") {
|
|
3536
3945
|
try {
|
|
3537
|
-
|
|
3946
|
+
fs24.chmodSync(hvigorw, 493);
|
|
3538
3947
|
} catch {
|
|
3539
3948
|
}
|
|
3540
3949
|
}
|
|
3541
3950
|
const env = { ...process.env, ...sdkEnv };
|
|
3542
|
-
return new Promise((
|
|
3951
|
+
return new Promise((resolve7, reject) => {
|
|
3543
3952
|
if (opts.abortSignal?.aborted) {
|
|
3544
3953
|
reject(new CancelledError("hvigorw build cancelled."));
|
|
3545
3954
|
return;
|
|
@@ -3583,46 +3992,15 @@ function runHvigorw(opts) {
|
|
|
3583
3992
|
settled = true;
|
|
3584
3993
|
cleanup();
|
|
3585
3994
|
const exitCode = code ?? 1;
|
|
3586
|
-
if (exitCode === 0)
|
|
3995
|
+
if (exitCode === 0) resolve7({ exitCode });
|
|
3587
3996
|
else reject(new OniroError(`hvigorw exited with code ${exitCode}`));
|
|
3588
3997
|
});
|
|
3589
3998
|
});
|
|
3590
3999
|
}
|
|
3591
4000
|
|
|
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
4001
|
// src/build/ohpm.ts
|
|
3624
|
-
var
|
|
3625
|
-
var
|
|
4002
|
+
var fs25 = __toESM(require("fs"), 1);
|
|
4003
|
+
var path25 = __toESM(require("path"), 1);
|
|
3626
4004
|
function runOhpm(opts) {
|
|
3627
4005
|
return runProcess({
|
|
3628
4006
|
command: opts.ohpmPath ?? getOhpmPath(opts.config),
|
|
@@ -3635,7 +4013,7 @@ function runOhpm(opts) {
|
|
|
3635
4013
|
});
|
|
3636
4014
|
}
|
|
3637
4015
|
async function ensureOhModules(opts) {
|
|
3638
|
-
if (
|
|
4016
|
+
if (fs25.existsSync(path25.join(opts.projectDir, "oh_modules"))) {
|
|
3639
4017
|
return { installed: false };
|
|
3640
4018
|
}
|
|
3641
4019
|
const res = await runOhpm({
|
|
@@ -3652,23 +4030,91 @@ async function ensureOhModules(opts) {
|
|
|
3652
4030
|
}
|
|
3653
4031
|
|
|
3654
4032
|
// src/build/codelinter.ts
|
|
3655
|
-
var FINDING_RE = /^(.*?):(\d+):(
|
|
4033
|
+
var FINDING_RE = /^(.*?):(\d+):(?:(\d+):)?\s*(error|warning|warn|suggestion|info)\b[:\s-]*(.*)$/i;
|
|
3656
4034
|
var TRAILING_CODE_RE = /[([]([\w@/.\-]+)[)\]]\s*$/;
|
|
3657
|
-
|
|
4035
|
+
var FILE_HEADER_RE = /^(.+\.\w+)\((\d+)\)$/;
|
|
4036
|
+
var ROW_RE = /^(\d+):(\d+)\s+(error|warning|warn|suggestion|info)\s+(.*)$/i;
|
|
4037
|
+
var RULE_RE = /^@?[\w.-]+(?:\/[\w.-]+)+$/;
|
|
4038
|
+
var SUMMARY_RE = /Defects:\s*(\d+);\s*Errors:\s*(\d+);\s*Warns:\s*(\d+);\s*Suggestions:\s*(\d+)/i;
|
|
4039
|
+
var NOTICE_RE = /does not match that of the project|error occurred during linting|incomplete report/i;
|
|
4040
|
+
var ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]/g;
|
|
4041
|
+
function cleanCodelinterOutput(output) {
|
|
4042
|
+
return output.replace(ANSI_RE, "").split("\n").map((line) => (line.split("\r").filter((s) => s.trim() !== "").pop() ?? "").trimEnd()).join("\n");
|
|
4043
|
+
}
|
|
4044
|
+
function normaliseSeverity(s) {
|
|
4045
|
+
const lower = s.toLowerCase();
|
|
4046
|
+
return lower === "warn" ? "warning" : lower;
|
|
4047
|
+
}
|
|
4048
|
+
function parseCodelinterReport(output) {
|
|
3658
4049
|
const findings = [];
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
4050
|
+
const notices = [];
|
|
4051
|
+
let summary = null;
|
|
4052
|
+
let file = "";
|
|
4053
|
+
for (const rawLine of cleanCodelinterOutput(output).split("\n")) {
|
|
4054
|
+
const line = rawLine.trim();
|
|
4055
|
+
if (!line) continue;
|
|
4056
|
+
const row = ROW_RE.exec(line);
|
|
4057
|
+
if (row) {
|
|
4058
|
+
if (!file) continue;
|
|
4059
|
+
const columns = row[4].trim().split(/\s{2,}/);
|
|
4060
|
+
const last = columns[columns.length - 1];
|
|
4061
|
+
const code = columns.length > 1 && RULE_RE.test(last) ? last : "";
|
|
4062
|
+
const message = (code ? columns.slice(0, -1) : columns).join(" ").trim();
|
|
4063
|
+
findings.push({
|
|
4064
|
+
file,
|
|
4065
|
+
line: Number(row[1]),
|
|
4066
|
+
column: Number(row[2]),
|
|
4067
|
+
severity: normaliseSeverity(row[3]),
|
|
4068
|
+
code,
|
|
4069
|
+
message
|
|
4070
|
+
});
|
|
4071
|
+
continue;
|
|
4072
|
+
}
|
|
4073
|
+
const header = FILE_HEADER_RE.exec(line);
|
|
4074
|
+
if (header) {
|
|
4075
|
+
file = header[1];
|
|
4076
|
+
continue;
|
|
4077
|
+
}
|
|
4078
|
+
const legacy = FINDING_RE.exec(line);
|
|
4079
|
+
if (legacy) {
|
|
4080
|
+
let message = legacy[5].trim();
|
|
4081
|
+
let code = "";
|
|
4082
|
+
const codeMatch = TRAILING_CODE_RE.exec(message);
|
|
4083
|
+
if (codeMatch) {
|
|
4084
|
+
code = codeMatch[1];
|
|
4085
|
+
message = message.slice(0, codeMatch.index).trim();
|
|
4086
|
+
}
|
|
4087
|
+
const finding = {
|
|
4088
|
+
file: legacy[1].trim(),
|
|
4089
|
+
line: Number(legacy[2]),
|
|
4090
|
+
severity: normaliseSeverity(legacy[4]),
|
|
4091
|
+
code,
|
|
4092
|
+
message
|
|
4093
|
+
};
|
|
4094
|
+
if (legacy[3]) finding.column = Number(legacy[3]);
|
|
4095
|
+
findings.push(finding);
|
|
4096
|
+
continue;
|
|
3668
4097
|
}
|
|
3669
|
-
|
|
4098
|
+
const totals = SUMMARY_RE.exec(line);
|
|
4099
|
+
if (totals) {
|
|
4100
|
+
summary = {
|
|
4101
|
+
defects: Number(totals[1]),
|
|
4102
|
+
errors: Number(totals[2]),
|
|
4103
|
+
warnings: Number(totals[3]),
|
|
4104
|
+
suggestions: Number(totals[4])
|
|
4105
|
+
};
|
|
4106
|
+
continue;
|
|
4107
|
+
}
|
|
4108
|
+
if (/no defects found/i.test(line)) {
|
|
4109
|
+
summary = { defects: 0, errors: 0, warnings: 0, suggestions: 0 };
|
|
4110
|
+
continue;
|
|
4111
|
+
}
|
|
4112
|
+
if (NOTICE_RE.test(line)) notices.push(line);
|
|
3670
4113
|
}
|
|
3671
|
-
return findings;
|
|
4114
|
+
return { findings, summary, notices, incomplete: notices.length > 0 };
|
|
4115
|
+
}
|
|
4116
|
+
function parseCodelinterFindings(output) {
|
|
4117
|
+
return parseCodelinterReport(output).findings;
|
|
3672
4118
|
}
|
|
3673
4119
|
async function runCodelinter(opts) {
|
|
3674
4120
|
const res = await runProcess({
|
|
@@ -3680,16 +4126,28 @@ async function runCodelinter(opts) {
|
|
|
3680
4126
|
logger: opts.logger
|
|
3681
4127
|
});
|
|
3682
4128
|
const raw = `${res.stdout}${res.stderr}`;
|
|
3683
|
-
return { code: res.code,
|
|
4129
|
+
return { code: res.code, ...parseCodelinterReport(raw), raw: cleanCodelinterOutput(raw) };
|
|
3684
4130
|
}
|
|
3685
4131
|
|
|
3686
4132
|
// src/build/buildHap.ts
|
|
4133
|
+
var DIAGNOSIS_OUTPUT_LIMIT = 2e6;
|
|
4134
|
+
function diagnoseBuildFailure(output) {
|
|
4135
|
+
if (/is not exported from Kit|has no exported member .*@systemapi/i.test(output)) {
|
|
4136
|
+
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`).";
|
|
4137
|
+
}
|
|
4138
|
+
if (/00308018|SDK path does not exist|SDK license agreement is not accepted/i.test(output)) {
|
|
4139
|
+
return "hvigor cannot find the SDK the project compiles against: check `oniro-app sdk list` against compileSdkVersion.";
|
|
4140
|
+
}
|
|
4141
|
+
return void 0;
|
|
4142
|
+
}
|
|
3687
4143
|
async function buildHap(opts) {
|
|
3688
4144
|
const logger = scopedLogger(opts.logger ?? noopLogger, "build");
|
|
3689
4145
|
const warnings = [];
|
|
3690
4146
|
const start = Date.now();
|
|
3691
4147
|
const projectDir = toLongPath(opts.projectDir);
|
|
3692
4148
|
const isHarmonyOs = detectRuntimeOs(projectDir, opts.product) === "HarmonyOS";
|
|
4149
|
+
const missingSdk = isHarmonyOs ? null : findMissingProjectSdk(opts.config, projectDir);
|
|
4150
|
+
if (missingSdk) throw missingSdk;
|
|
3693
4151
|
if (opts.autoInstallDeps !== false) {
|
|
3694
4152
|
const harmonySdk = isHarmonyOs ? findHarmonyOsSdk({ config: opts.config, logger: opts.logger }) : null;
|
|
3695
4153
|
const r = await ensureOhModules({
|
|
@@ -3702,23 +4160,35 @@ async function buildHap(opts) {
|
|
|
3702
4160
|
});
|
|
3703
4161
|
if (r.installed) logger.info("ran ohpm install --all (oh_modules was missing)");
|
|
3704
4162
|
}
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
4163
|
+
let output = "";
|
|
4164
|
+
let exitCode;
|
|
4165
|
+
try {
|
|
4166
|
+
({ exitCode } = await runHvigorw({
|
|
4167
|
+
config: opts.config,
|
|
4168
|
+
projectDir,
|
|
4169
|
+
product: opts.product,
|
|
4170
|
+
module: opts.module,
|
|
4171
|
+
buildMode: opts.mode,
|
|
4172
|
+
task: opts.task,
|
|
4173
|
+
parallel: opts.parallel,
|
|
4174
|
+
abortSignal: opts.abortSignal,
|
|
4175
|
+
onOutput: (chunk, stream) => {
|
|
4176
|
+
output = (output + chunk).slice(-DIAGNOSIS_OUTPUT_LIMIT);
|
|
4177
|
+
opts.onOutput?.(chunk, stream);
|
|
4178
|
+
},
|
|
4179
|
+
logger: opts.logger
|
|
4180
|
+
}));
|
|
4181
|
+
} catch (err) {
|
|
4182
|
+
const hint = diagnoseBuildFailure(output);
|
|
4183
|
+
if (hint && err instanceof OniroError) throw new OniroError(`${err.message}
|
|
4184
|
+
${hint}`, err);
|
|
4185
|
+
throw err;
|
|
4186
|
+
}
|
|
3717
4187
|
const discoveredHaps = await discoverHaps({ projectDir });
|
|
3718
4188
|
const anySigned = Object.values(discoveredHaps).some((m) => m.signed.length > 0);
|
|
3719
4189
|
if (!anySigned) {
|
|
3720
4190
|
warnings.push(
|
|
3721
|
-
isHarmonyOs ? "No signed HAPs found
|
|
4191
|
+
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
4192
|
);
|
|
3723
4193
|
}
|
|
3724
4194
|
return { exitCode, durationMs: Date.now() - start, discoveredHaps, warnings };
|
|
@@ -3735,21 +4205,21 @@ function isValidBundleName(bundleName) {
|
|
|
3735
4205
|
}
|
|
3736
4206
|
|
|
3737
4207
|
// src/project/templates.ts
|
|
3738
|
-
var
|
|
3739
|
-
var
|
|
4208
|
+
var fs26 = __toESM(require("fs"), 1);
|
|
4209
|
+
var path26 = __toESM(require("path"), 1);
|
|
3740
4210
|
function toHumanTemplateName(folderName) {
|
|
3741
4211
|
return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
3742
4212
|
}
|
|
3743
4213
|
function listTemplates(templateRoot) {
|
|
3744
|
-
if (!
|
|
3745
|
-
const entries =
|
|
4214
|
+
if (!fs26.existsSync(templateRoot)) return [];
|
|
4215
|
+
const entries = fs26.readdirSync(templateRoot, { withFileTypes: true });
|
|
3746
4216
|
return entries.filter((e) => e.isDirectory()).map((e) => {
|
|
3747
|
-
const dir =
|
|
3748
|
-
const metaPath =
|
|
4217
|
+
const dir = path26.join(templateRoot, e.name);
|
|
4218
|
+
const metaPath = path26.join(dir, "template.json");
|
|
3749
4219
|
let meta = {};
|
|
3750
|
-
if (
|
|
4220
|
+
if (fs26.existsSync(metaPath)) {
|
|
3751
4221
|
try {
|
|
3752
|
-
meta = JSON.parse(
|
|
4222
|
+
meta = JSON.parse(fs26.readFileSync(metaPath, "utf8"));
|
|
3753
4223
|
} catch {
|
|
3754
4224
|
}
|
|
3755
4225
|
}
|
|
@@ -3764,57 +4234,57 @@ function listTemplates(templateRoot) {
|
|
|
3764
4234
|
function validateTemplateLayout(templateDir, defaultModuleName) {
|
|
3765
4235
|
const required = [
|
|
3766
4236
|
"build-profile.json5",
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
4237
|
+
path26.join("AppScope", "app.json5"),
|
|
4238
|
+
path26.join(defaultModuleName, "src", "main", "module.json5"),
|
|
4239
|
+
path26.join(defaultModuleName, "oh-package.json5"),
|
|
3770
4240
|
"hvigorfile.ts"
|
|
3771
4241
|
];
|
|
3772
|
-
return required.filter((rel) => !
|
|
4242
|
+
return required.filter((rel) => !fs26.existsSync(path26.join(templateDir, rel)));
|
|
3773
4243
|
}
|
|
3774
4244
|
|
|
3775
4245
|
// src/project/createScaffold.ts
|
|
3776
|
-
var
|
|
3777
|
-
var
|
|
4246
|
+
var fs28 = __toESM(require("fs"), 1);
|
|
4247
|
+
var path27 = __toESM(require("path"), 1);
|
|
3778
4248
|
|
|
3779
4249
|
// src/project/jsonHelpers.ts
|
|
3780
|
-
var
|
|
4250
|
+
var fs27 = __toESM(require("fs"), 1);
|
|
3781
4251
|
var import_json55 = __toESM(require("json5"), 1);
|
|
3782
4252
|
function readJson5File(filePath) {
|
|
3783
|
-
return import_json55.default.parse(
|
|
4253
|
+
return import_json55.default.parse(fs27.readFileSync(filePath, "utf8"));
|
|
3784
4254
|
}
|
|
3785
4255
|
function writeJson5File(filePath, value) {
|
|
3786
|
-
|
|
4256
|
+
fs27.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
3787
4257
|
}
|
|
3788
4258
|
function readJsonFile(filePath) {
|
|
3789
|
-
return JSON.parse(
|
|
4259
|
+
return JSON.parse(fs27.readFileSync(filePath, "utf8"));
|
|
3790
4260
|
}
|
|
3791
4261
|
function writeJsonFile(filePath, value) {
|
|
3792
|
-
|
|
4262
|
+
fs27.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
3793
4263
|
}
|
|
3794
4264
|
|
|
3795
4265
|
// src/project/createScaffold.ts
|
|
3796
4266
|
var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
|
|
3797
4267
|
async function pathExists(p) {
|
|
3798
4268
|
try {
|
|
3799
|
-
await
|
|
4269
|
+
await fs28.promises.access(p);
|
|
3800
4270
|
return true;
|
|
3801
4271
|
} catch {
|
|
3802
4272
|
return false;
|
|
3803
4273
|
}
|
|
3804
4274
|
}
|
|
3805
4275
|
async function copyDirRecursive(srcDir, destDir) {
|
|
3806
|
-
await
|
|
3807
|
-
const entries = await
|
|
4276
|
+
await fs28.promises.mkdir(destDir, { recursive: true });
|
|
4277
|
+
const entries = await fs28.promises.readdir(srcDir, { withFileTypes: true });
|
|
3808
4278
|
for (const entry of entries) {
|
|
3809
|
-
const src =
|
|
3810
|
-
const dest =
|
|
4279
|
+
const src = path27.join(srcDir, entry.name);
|
|
4280
|
+
const dest = path27.join(destDir, entry.name);
|
|
3811
4281
|
if (entry.isDirectory()) {
|
|
3812
4282
|
await copyDirRecursive(src, dest);
|
|
3813
4283
|
} else if (entry.isSymbolicLink()) {
|
|
3814
4284
|
continue;
|
|
3815
4285
|
} else if (entry.isFile()) {
|
|
3816
4286
|
if (entry.name === "template.json") continue;
|
|
3817
|
-
await
|
|
4287
|
+
await fs28.promises.copyFile(src, dest);
|
|
3818
4288
|
}
|
|
3819
4289
|
}
|
|
3820
4290
|
}
|
|
@@ -3822,9 +4292,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
|
|
|
3822
4292
|
const stack = [projectDir];
|
|
3823
4293
|
while (stack.length > 0) {
|
|
3824
4294
|
const currentDir = stack.pop();
|
|
3825
|
-
const entries = await
|
|
4295
|
+
const entries = await fs28.promises.readdir(currentDir, { withFileTypes: true });
|
|
3826
4296
|
for (const entry of entries) {
|
|
3827
|
-
const fullPath =
|
|
4297
|
+
const fullPath = path27.join(currentDir, entry.name);
|
|
3828
4298
|
if (entry.isDirectory()) {
|
|
3829
4299
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
3830
4300
|
stack.push(fullPath);
|
|
@@ -3846,23 +4316,23 @@ function toJavaPropertiesPath(p) {
|
|
|
3846
4316
|
function createOrUpdateLocalProperties(projectDir, sdkDir) {
|
|
3847
4317
|
const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
|
|
3848
4318
|
`;
|
|
3849
|
-
|
|
4319
|
+
fs28.writeFileSync(path27.join(projectDir, "local.properties"), content, "utf8");
|
|
3850
4320
|
}
|
|
3851
4321
|
function renameIfExists(fromPath, toPath) {
|
|
3852
|
-
if (
|
|
3853
|
-
|
|
4322
|
+
if (fs28.existsSync(fromPath) && fromPath !== toPath) {
|
|
4323
|
+
fs28.renameSync(fromPath, toPath);
|
|
3854
4324
|
}
|
|
3855
4325
|
}
|
|
3856
4326
|
function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
3857
|
-
const appJsonPath =
|
|
3858
|
-
if (
|
|
4327
|
+
const appJsonPath = path27.join(projectDir, "AppScope", "app.json5");
|
|
4328
|
+
if (fs28.existsSync(appJsonPath)) {
|
|
3859
4329
|
const appJson = readJson5File(appJsonPath);
|
|
3860
4330
|
appJson.app = appJson.app ?? {};
|
|
3861
4331
|
appJson.app.bundleName = args.bundleName;
|
|
3862
4332
|
writeJson5File(appJsonPath, appJson);
|
|
3863
4333
|
}
|
|
3864
|
-
const stringsPath =
|
|
3865
|
-
if (
|
|
4334
|
+
const stringsPath = path27.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
|
|
4335
|
+
if (fs28.existsSync(stringsPath)) {
|
|
3866
4336
|
const strings = readJsonFile(stringsPath);
|
|
3867
4337
|
if (Array.isArray(strings.string)) {
|
|
3868
4338
|
const appName = strings.string.find((s) => s.name === "app_name");
|
|
@@ -3870,8 +4340,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
3870
4340
|
}
|
|
3871
4341
|
writeJsonFile(stringsPath, strings);
|
|
3872
4342
|
}
|
|
3873
|
-
const buildProfilePath =
|
|
3874
|
-
if (
|
|
4343
|
+
const buildProfilePath = path27.join(projectDir, "build-profile.json5");
|
|
4344
|
+
if (fs28.existsSync(buildProfilePath)) {
|
|
3875
4345
|
const buildProfile = readJson5File(buildProfilePath);
|
|
3876
4346
|
buildProfile.app = buildProfile.app ?? {};
|
|
3877
4347
|
if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
|
|
@@ -3884,23 +4354,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
3884
4354
|
}
|
|
3885
4355
|
writeJson5File(buildProfilePath, buildProfile);
|
|
3886
4356
|
}
|
|
3887
|
-
const moduleJsonPath =
|
|
3888
|
-
if (
|
|
4357
|
+
const moduleJsonPath = path27.join(projectDir, args.moduleName, "src", "main", "module.json5");
|
|
4358
|
+
if (fs28.existsSync(moduleJsonPath)) {
|
|
3889
4359
|
const moduleJson = readJson5File(moduleJsonPath);
|
|
3890
4360
|
moduleJson.module = moduleJson.module ?? {};
|
|
3891
4361
|
moduleJson.module.name = args.moduleName;
|
|
3892
4362
|
writeJson5File(moduleJsonPath, moduleJson);
|
|
3893
4363
|
}
|
|
3894
|
-
const moduleOhPackagePath =
|
|
3895
|
-
if (
|
|
4364
|
+
const moduleOhPackagePath = path27.join(projectDir, args.moduleName, "oh-package.json5");
|
|
4365
|
+
if (fs28.existsSync(moduleOhPackagePath)) {
|
|
3896
4366
|
const pkg = readJson5File(moduleOhPackagePath);
|
|
3897
4367
|
pkg.name = args.moduleName;
|
|
3898
4368
|
writeJson5File(moduleOhPackagePath, pkg);
|
|
3899
4369
|
}
|
|
3900
|
-
const vscodeDir =
|
|
3901
|
-
|
|
4370
|
+
const vscodeDir = path27.join(projectDir, ".vscode");
|
|
4371
|
+
fs28.mkdirSync(vscodeDir, { recursive: true });
|
|
3902
4372
|
const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
|
|
3903
|
-
writeJsonFile(
|
|
4373
|
+
writeJsonFile(path27.join(vscodeDir, "settings.json"), {
|
|
3904
4374
|
"oniro.hapPath": hapPath,
|
|
3905
4375
|
"files.associations": { "*.json5": "jsonc" }
|
|
3906
4376
|
});
|
|
@@ -3917,7 +4387,7 @@ async function createScaffold(opts) {
|
|
|
3917
4387
|
if (!opts.location || !await pathExists(opts.location)) {
|
|
3918
4388
|
throw new OniroError(`Location does not exist: ${opts.location}`);
|
|
3919
4389
|
}
|
|
3920
|
-
const templateDir =
|
|
4390
|
+
const templateDir = path27.join(opts.templateRoot, opts.templateId);
|
|
3921
4391
|
if (!await pathExists(templateDir)) {
|
|
3922
4392
|
throw new OniroError(`Template not found: ${templateDir}`);
|
|
3923
4393
|
}
|
|
@@ -3952,17 +4422,17 @@ async function createScaffold(opts) {
|
|
|
3952
4422
|
}
|
|
3953
4423
|
}
|
|
3954
4424
|
}
|
|
3955
|
-
const projectDir =
|
|
4425
|
+
const projectDir = path27.join(opts.location, opts.projectName);
|
|
3956
4426
|
if (await pathExists(projectDir)) {
|
|
3957
4427
|
if (!opts.overwrite) {
|
|
3958
4428
|
throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
|
|
3959
4429
|
}
|
|
3960
|
-
await
|
|
4430
|
+
await fs28.promises.rm(projectDir, { recursive: true, force: true });
|
|
3961
4431
|
}
|
|
3962
4432
|
logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
|
|
3963
4433
|
await copyDirRecursive(templateDir, projectDir);
|
|
3964
4434
|
if (moduleName !== defaultModuleName) {
|
|
3965
|
-
renameIfExists(
|
|
4435
|
+
renameIfExists(path27.join(projectDir, defaultModuleName), path27.join(projectDir, moduleName));
|
|
3966
4436
|
}
|
|
3967
4437
|
updateTemplateConfigs(
|
|
3968
4438
|
projectDir,
|
|
@@ -3979,11 +4449,11 @@ async function createScaffold(opts) {
|
|
|
3979
4449
|
}
|
|
3980
4450
|
|
|
3981
4451
|
// src/project/listModules.ts
|
|
3982
|
-
var
|
|
3983
|
-
var
|
|
4452
|
+
var fs29 = __toESM(require("fs"), 1);
|
|
4453
|
+
var path28 = __toESM(require("path"), 1);
|
|
3984
4454
|
function listModules(opts) {
|
|
3985
|
-
const buildProfile =
|
|
3986
|
-
if (!
|
|
4455
|
+
const buildProfile = path28.join(opts.projectDir, "build-profile.json5");
|
|
4456
|
+
if (!fs29.existsSync(buildProfile)) {
|
|
3987
4457
|
throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
|
|
3988
4458
|
}
|
|
3989
4459
|
const parsed = readJson5File(buildProfile);
|
|
@@ -3995,12 +4465,12 @@ function listModules(opts) {
|
|
|
3995
4465
|
}
|
|
3996
4466
|
|
|
3997
4467
|
// src/project/abilities.ts
|
|
3998
|
-
var
|
|
3999
|
-
var
|
|
4468
|
+
var fs30 = __toESM(require("fs"), 1);
|
|
4469
|
+
var path29 = __toESM(require("path"), 1);
|
|
4000
4470
|
function listAbilities(opts) {
|
|
4001
4471
|
const moduleName = opts.moduleName ?? "entry";
|
|
4002
|
-
const moduleJsonPath =
|
|
4003
|
-
if (!
|
|
4472
|
+
const moduleJsonPath = path29.join(opts.projectDir, moduleName, "src", "main", "module.json5");
|
|
4473
|
+
if (!fs30.existsSync(moduleJsonPath)) {
|
|
4004
4474
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
4005
4475
|
}
|
|
4006
4476
|
const parsed = readJson5File(moduleJsonPath);
|
|
@@ -4008,12 +4478,12 @@ function listAbilities(opts) {
|
|
|
4008
4478
|
}
|
|
4009
4479
|
|
|
4010
4480
|
// src/project/prepareSigning.ts
|
|
4011
|
-
var
|
|
4012
|
-
var
|
|
4481
|
+
var fs31 = __toESM(require("fs"), 1);
|
|
4482
|
+
var path30 = __toESM(require("path"), 1);
|
|
4013
4483
|
function hasSigningArtifacts(dir) {
|
|
4014
|
-
if (!
|
|
4015
|
-
const buildProfile =
|
|
4016
|
-
if (!
|
|
4484
|
+
if (!fs31.existsSync(path30.join(dir, "signatures"))) return false;
|
|
4485
|
+
const buildProfile = path30.join(dir, "build-profile.json5");
|
|
4486
|
+
if (!fs31.existsSync(buildProfile)) return false;
|
|
4017
4487
|
try {
|
|
4018
4488
|
const parsed = readJson5File(buildProfile);
|
|
4019
4489
|
return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
|
|
@@ -4031,6 +4501,7 @@ function prepareSigning(opts) {
|
|
|
4031
4501
|
apl: opts.apl,
|
|
4032
4502
|
appFeature: opts.appFeature,
|
|
4033
4503
|
acls: opts.acls,
|
|
4504
|
+
appPrivilegeCapabilities: opts.appPrivilegeCapabilities,
|
|
4034
4505
|
passwords: opts.passwords,
|
|
4035
4506
|
logger: opts.logger
|
|
4036
4507
|
});
|
|
@@ -4059,19 +4530,31 @@ var PROPS = [
|
|
|
4059
4530
|
["model", "const.product.model"],
|
|
4060
4531
|
["manufacturer", "const.product.manufacturer"],
|
|
4061
4532
|
["brand", "const.product.brand"],
|
|
4533
|
+
["osDistName", "const.product.os.dist.name"],
|
|
4534
|
+
["osDistVersion", "const.product.os.dist.version"],
|
|
4062
4535
|
["osFullName", "const.ohos.fullname"],
|
|
4063
4536
|
["osReleaseType", "const.ohos.releasetype"],
|
|
4064
4537
|
["sdkApiVersion", "const.ohos.apiversion"],
|
|
4065
|
-
["buildVersion", "const.product.software.version"]
|
|
4538
|
+
["buildVersion", "const.product.software.version"],
|
|
4539
|
+
["abi", "const.product.cpu.abilist"],
|
|
4540
|
+
["deviceType", "const.product.devicetype"]
|
|
4066
4541
|
];
|
|
4067
4542
|
async function getDeviceInfo(opts) {
|
|
4068
4543
|
const info = { serial: opts.deviceSerial ?? "(default)", display: null };
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4544
|
+
try {
|
|
4545
|
+
const values = await paramGetMany(
|
|
4546
|
+
opts.config,
|
|
4547
|
+
PROPS.map(([, prop]) => prop),
|
|
4548
|
+
{ deviceSerial: opts.deviceSerial, timeoutMs: opts.timeoutMs ?? 1e4, logger: opts.logger }
|
|
4549
|
+
);
|
|
4550
|
+
for (const [field, prop] of PROPS) {
|
|
4551
|
+
const value = values[prop];
|
|
4072
4552
|
if (value) info[field] = value;
|
|
4073
|
-
} catch {
|
|
4074
4553
|
}
|
|
4554
|
+
} catch {
|
|
4555
|
+
}
|
|
4556
|
+
if (info.osDistName || info.osFullName) {
|
|
4557
|
+
info.osFamily = /harmonyos/i.test(info.osDistName ?? "") ? "HarmonyOS" : "OpenHarmony";
|
|
4075
4558
|
}
|
|
4076
4559
|
const screen = await dumpScreen({ config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger });
|
|
4077
4560
|
if (screen) info.display = { width: screen.width, height: screen.height };
|
|
@@ -4103,8 +4586,8 @@ async function diffHapAssets(opts) {
|
|
|
4103
4586
|
}
|
|
4104
4587
|
|
|
4105
4588
|
// src/install/apply.ts
|
|
4106
|
-
var
|
|
4107
|
-
var
|
|
4589
|
+
var fs32 = __toESM(require("fs"), 1);
|
|
4590
|
+
var path31 = __toESM(require("path"), 1);
|
|
4108
4591
|
function decideInstallMethod(s) {
|
|
4109
4592
|
if (!s.signInfoInconsistent) return "replace";
|
|
4110
4593
|
if (s.isSystemBundle && !s.allowUninstall) return "refuse";
|
|
@@ -4122,39 +4605,31 @@ async function pidOf(config, bundle, deviceSerial) {
|
|
|
4122
4605
|
const proc = await findRunningProcess({ config, bundle, deviceSerial });
|
|
4123
4606
|
return proc ? Number(proc.pid) : null;
|
|
4124
4607
|
}
|
|
4125
|
-
async function
|
|
4126
|
-
let
|
|
4127
|
-
if (hapPath) {
|
|
4128
|
-
|
|
4608
|
+
async function resolveHap(opts, logger) {
|
|
4609
|
+
let hap;
|
|
4610
|
+
if (opts.hapPath) {
|
|
4611
|
+
const hapPath = !path31.isAbsolute(opts.hapPath) && opts.projectDir ? path31.join(opts.projectDir, opts.hapPath) : opts.hapPath;
|
|
4612
|
+
hap = existingHapOrUnsigned(hapPath);
|
|
4613
|
+
if (!hap) throw new OniroError(`HAP not found at ${hapPath}.`);
|
|
4129
4614
|
} else {
|
|
4130
4615
|
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
|
-
}
|
|
4616
|
+
const picked = pickHap(await discoverHaps({ projectDir: opts.projectDir }), opts.module);
|
|
4617
|
+
if (!picked) throw new OniroError(`No HAP found${opts.module ? ` for module ${opts.module}` : ""}. Build first.`);
|
|
4618
|
+
hap = { path: picked.path, fallback: !picked.signed };
|
|
4146
4619
|
}
|
|
4147
|
-
if (
|
|
4148
|
-
return
|
|
4620
|
+
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path31.basename(hap.path)}.`);
|
|
4621
|
+
return hap;
|
|
4149
4622
|
}
|
|
4150
4623
|
async function applyChanges(opts) {
|
|
4151
4624
|
const logger = scopedLogger(opts.logger ?? noopLogger, "apply");
|
|
4152
4625
|
const { config, bundle, deviceSerial } = opts;
|
|
4153
4626
|
const isSystemBundle = opts.isSystemBundle ?? false;
|
|
4154
4627
|
const allowUninstall = opts.allowUninstall ?? false;
|
|
4155
|
-
const
|
|
4628
|
+
const hap = await resolveHap(opts, logger);
|
|
4629
|
+
const hapPath = hap.path;
|
|
4630
|
+
logger.info(`installing ${hapPath}`);
|
|
4156
4631
|
let assetsChanged = false;
|
|
4157
|
-
if (opts.installedHapPath &&
|
|
4632
|
+
if (opts.installedHapPath && fs32.existsSync(opts.installedHapPath)) {
|
|
4158
4633
|
try {
|
|
4159
4634
|
const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
|
|
4160
4635
|
assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
|
|
@@ -4175,12 +4650,21 @@ async function applyChanges(opts) {
|
|
|
4175
4650
|
if (decision === "uninstall-install") {
|
|
4176
4651
|
logger.warn(`sign-info inconsistent for ${bundle}; uninstalling then installing fresh.`);
|
|
4177
4652
|
await uninstallApp({ config, bundle, deviceSerial });
|
|
4178
|
-
|
|
4653
|
+
ensureInstallOk(
|
|
4654
|
+
await hdcExec({ config, args: ["install", hapPath], deviceSerial, timeoutMs: 3e5 }),
|
|
4655
|
+
`hdc install ${hapPath}`,
|
|
4656
|
+
hap
|
|
4657
|
+
);
|
|
4179
4658
|
installMethod = "uninstall-install";
|
|
4180
4659
|
} else {
|
|
4181
|
-
|
|
4660
|
+
ensureInstallOk(replaceRes, `hdc install -r ${hapPath}`, hap);
|
|
4182
4661
|
installMethod = "replace";
|
|
4183
4662
|
}
|
|
4663
|
+
if (!await isBundleInstalled({ config, bundle, deviceSerial })) {
|
|
4664
|
+
throw new OniroError(
|
|
4665
|
+
`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).`
|
|
4666
|
+
);
|
|
4667
|
+
}
|
|
4184
4668
|
let postInstallPid = await pidOf(config, bundle, deviceSerial);
|
|
4185
4669
|
const rebootDecision = decideReboot({ assetsChanged, isSystemBundle, preInstallPid, postInstallPid });
|
|
4186
4670
|
let method = installMethod;
|
|
@@ -4255,9 +4739,9 @@ var AUTH_PATHS = {
|
|
|
4255
4739
|
};
|
|
4256
4740
|
|
|
4257
4741
|
// src/harmonyos/auth/tokenStore.ts
|
|
4258
|
-
var
|
|
4742
|
+
var fs33 = __toESM(require("fs"), 1);
|
|
4259
4743
|
var os11 = __toESM(require("os"), 1);
|
|
4260
|
-
var
|
|
4744
|
+
var path32 = __toESM(require("path"), 1);
|
|
4261
4745
|
var crypto3 = __toESM(require("crypto"), 1);
|
|
4262
4746
|
var ALGORITHM = "aes-256-gcm";
|
|
4263
4747
|
var KEY_LENGTH = 32;
|
|
@@ -4293,7 +4777,7 @@ function permissionHint(dir) {
|
|
|
4293
4777
|
}
|
|
4294
4778
|
function ensureDir(dir) {
|
|
4295
4779
|
try {
|
|
4296
|
-
|
|
4780
|
+
fs33.mkdirSync(dir, { recursive: true, mode: DIR_MODE });
|
|
4297
4781
|
} catch (err) {
|
|
4298
4782
|
if (err.code === "EACCES") {
|
|
4299
4783
|
throw new OniroError(permissionHint(dir), err);
|
|
@@ -4304,17 +4788,17 @@ function ensureDir(dir) {
|
|
|
4304
4788
|
function createTokenStore(opts) {
|
|
4305
4789
|
const logger = opts.logger ?? noopLogger;
|
|
4306
4790
|
const authDir = opts.config.get("harmonyosAuthDir", defaultPaths.harmonyosAuthDir());
|
|
4307
|
-
const tokenPath =
|
|
4308
|
-
const keyPath =
|
|
4791
|
+
const tokenPath = path32.join(authDir, TOKEN_FILE);
|
|
4792
|
+
const keyPath = path32.join(os11.homedir(), ".local", "share", "oniro-app", "keys", KEY_FILE);
|
|
4309
4793
|
function loadOrCreateKey() {
|
|
4310
|
-
if (
|
|
4311
|
-
const existing =
|
|
4794
|
+
if (fs33.existsSync(keyPath)) {
|
|
4795
|
+
const existing = fs33.readFileSync(keyPath);
|
|
4312
4796
|
if (existing.length === KEY_LENGTH) return existing;
|
|
4313
4797
|
logger.warn("[harmonyos] The token key file was malformed; regenerating (you will need to log in again).");
|
|
4314
4798
|
}
|
|
4315
|
-
ensureDir(
|
|
4799
|
+
ensureDir(path32.dirname(keyPath));
|
|
4316
4800
|
const key = crypto3.randomBytes(KEY_LENGTH);
|
|
4317
|
-
|
|
4801
|
+
fs33.writeFileSync(keyPath, key, { mode: FILE_MODE });
|
|
4318
4802
|
return key;
|
|
4319
4803
|
}
|
|
4320
4804
|
return {
|
|
@@ -4324,12 +4808,12 @@ function createTokenStore(opts) {
|
|
|
4324
4808
|
const payload = Buffer.from(JSON.stringify(session), "utf8");
|
|
4325
4809
|
const blob = encrypt2(loadOrCreateKey(), payload);
|
|
4326
4810
|
ensureDir(authDir);
|
|
4327
|
-
|
|
4811
|
+
fs33.writeFileSync(tokenPath, JSON.stringify(blob, null, 2), { mode: FILE_MODE });
|
|
4328
4812
|
},
|
|
4329
4813
|
load() {
|
|
4330
|
-
if (!
|
|
4814
|
+
if (!fs33.existsSync(tokenPath)) return null;
|
|
4331
4815
|
try {
|
|
4332
|
-
const blob = JSON.parse(
|
|
4816
|
+
const blob = JSON.parse(fs33.readFileSync(tokenPath, "utf8"));
|
|
4333
4817
|
if (!isEncryptedBlob(blob)) return null;
|
|
4334
4818
|
const { jwtToken, siteId } = JSON.parse(decrypt2(loadOrCreateKey(), blob).toString("utf8"));
|
|
4335
4819
|
return typeof jwtToken === "string" && jwtToken && typeof siteId === "string" ? { jwtToken, siteId } : null;
|
|
@@ -4341,7 +4825,7 @@ function createTokenStore(opts) {
|
|
|
4341
4825
|
}
|
|
4342
4826
|
logger.debug(`[harmonyos] Discarding unreadable token at ${tokenPath}.`);
|
|
4343
4827
|
try {
|
|
4344
|
-
|
|
4828
|
+
fs33.rmSync(tokenPath, { force: true });
|
|
4345
4829
|
} catch {
|
|
4346
4830
|
}
|
|
4347
4831
|
return null;
|
|
@@ -4349,7 +4833,7 @@ function createTokenStore(opts) {
|
|
|
4349
4833
|
},
|
|
4350
4834
|
clear() {
|
|
4351
4835
|
try {
|
|
4352
|
-
|
|
4836
|
+
fs33.rmSync(tokenPath, { force: true });
|
|
4353
4837
|
} catch (err) {
|
|
4354
4838
|
throw new OniroError(`Failed to remove ${tokenPath}.`, err);
|
|
4355
4839
|
}
|
|
@@ -4463,8 +4947,8 @@ function isQuit(quit) {
|
|
|
4463
4947
|
async function startCallbackServer(opts) {
|
|
4464
4948
|
let resolveCallback;
|
|
4465
4949
|
let rejectCallback;
|
|
4466
|
-
const callback = new Promise((
|
|
4467
|
-
resolveCallback =
|
|
4950
|
+
const callback = new Promise((resolve7, reject) => {
|
|
4951
|
+
resolveCallback = resolve7;
|
|
4468
4952
|
rejectCallback = reject;
|
|
4469
4953
|
});
|
|
4470
4954
|
callback.catch(() => {
|
|
@@ -4523,9 +5007,9 @@ async function startCallbackServer(opts) {
|
|
|
4523
5007
|
}
|
|
4524
5008
|
});
|
|
4525
5009
|
server.keepAliveTimeout = 1;
|
|
4526
|
-
await new Promise((
|
|
5010
|
+
await new Promise((resolve7, reject) => {
|
|
4527
5011
|
server.once("error", (err) => reject(new OniroError("Failed to start the local login callback server.", err)));
|
|
4528
|
-
server.listen(0, "127.0.0.1",
|
|
5012
|
+
server.listen(0, "127.0.0.1", resolve7);
|
|
4529
5013
|
});
|
|
4530
5014
|
const port = server.address().port;
|
|
4531
5015
|
return {
|
|
@@ -4541,12 +5025,12 @@ async function startCallbackServer(opts) {
|
|
|
4541
5025
|
return Promise.race([callback, timeout]).finally(() => clearTimeout(timer));
|
|
4542
5026
|
},
|
|
4543
5027
|
stop() {
|
|
4544
|
-
return new Promise((
|
|
5028
|
+
return new Promise((resolve7) => {
|
|
4545
5029
|
server.closeAllConnections?.();
|
|
4546
|
-
const timer = setTimeout(
|
|
5030
|
+
const timer = setTimeout(resolve7, 100);
|
|
4547
5031
|
server.close(() => {
|
|
4548
5032
|
clearTimeout(timer);
|
|
4549
|
-
|
|
5033
|
+
resolve7();
|
|
4550
5034
|
});
|
|
4551
5035
|
});
|
|
4552
5036
|
}
|
|
@@ -4578,11 +5062,11 @@ function openBrowser(url) {
|
|
|
4578
5062
|
windowsHide: true
|
|
4579
5063
|
});
|
|
4580
5064
|
child.unref();
|
|
4581
|
-
return new Promise((
|
|
5065
|
+
return new Promise((resolve7, reject) => {
|
|
4582
5066
|
child.on("error", (err) => reject(new OniroError(`Failed to open a browser (${command}).`, err)));
|
|
4583
5067
|
child.on(
|
|
4584
5068
|
"exit",
|
|
4585
|
-
(code) => code === 0 ?
|
|
5069
|
+
(code) => code === 0 ? resolve7() : reject(new OniroError(`Browser launcher '${command}' exited with code ${code}.`))
|
|
4586
5070
|
);
|
|
4587
5071
|
});
|
|
4588
5072
|
}
|
|
@@ -4830,7 +5314,7 @@ function mapAgcError(operation, statusCode, reasonPhrase, body) {
|
|
|
4830
5314
|
}
|
|
4831
5315
|
|
|
4832
5316
|
// src/harmonyos/signing/profile.ts
|
|
4833
|
-
var
|
|
5317
|
+
var fs34 = __toESM(require("fs"), 1);
|
|
4834
5318
|
var import_node_crypto3 = require("crypto");
|
|
4835
5319
|
var import_node_forge = __toESM(require("node-forge"), 1);
|
|
4836
5320
|
function extractProfileJson(buffer) {
|
|
@@ -4862,7 +5346,7 @@ function extractProfileJson(buffer) {
|
|
|
4862
5346
|
function readProvisionProfile(profilePath) {
|
|
4863
5347
|
let raw;
|
|
4864
5348
|
try {
|
|
4865
|
-
const json = extractProfileJson(
|
|
5349
|
+
const json = extractProfileJson(fs34.readFileSync(profilePath));
|
|
4866
5350
|
if (!json) return null;
|
|
4867
5351
|
raw = JSON.parse(json);
|
|
4868
5352
|
} catch {
|
|
@@ -4891,7 +5375,7 @@ function parseCertificate(pem) {
|
|
|
4891
5375
|
}
|
|
4892
5376
|
function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
|
|
4893
5377
|
try {
|
|
4894
|
-
const der = import_node_forge.default.util.createBuffer(
|
|
5378
|
+
const der = import_node_forge.default.util.createBuffer(fs34.readFileSync(p12Path).toString("binary"));
|
|
4895
5379
|
const p12 = import_node_forge.default.pkcs12.pkcs12FromAsn1(import_node_forge.default.asn1.fromDer(der), keyPwd);
|
|
4896
5380
|
const certBag = import_node_forge.default.pki.oids.certBag ?? "1.2.840.113549.1.12.10.1.3";
|
|
4897
5381
|
const wanted = certificate.publicKey.export({ type: "spki", format: "der" });
|
|
@@ -4907,7 +5391,7 @@ function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
|
|
|
4907
5391
|
}
|
|
4908
5392
|
}
|
|
4909
5393
|
function verifySigningMaterial(opts) {
|
|
4910
|
-
const pems =
|
|
5394
|
+
const pems = fs34.readFileSync(opts.cerPath, "utf8").match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g);
|
|
4911
5395
|
const chain = (pems ?? []).map(parseCertificate);
|
|
4912
5396
|
const leaf = chain.find((c) => !c.ca) ?? chain.at(-1);
|
|
4913
5397
|
if (!leaf) throw new AgcError(SIGNING_ERRORS.CERT_INVALID);
|
|
@@ -4926,14 +5410,14 @@ function verifySigningMaterial(opts) {
|
|
|
4926
5410
|
|
|
4927
5411
|
// src/harmonyos/signing/autoSign.ts
|
|
4928
5412
|
var crypto9 = __toESM(require("crypto"), 1);
|
|
4929
|
-
var
|
|
4930
|
-
var
|
|
5413
|
+
var fs39 = __toESM(require("fs"), 1);
|
|
5414
|
+
var path38 = __toESM(require("path"), 1);
|
|
4931
5415
|
var import_json57 = __toESM(require("json5"), 1);
|
|
4932
5416
|
|
|
4933
5417
|
// src/harmonyos/signing/agc.ts
|
|
4934
5418
|
var crypto6 = __toESM(require("crypto"), 1);
|
|
4935
|
-
var
|
|
4936
|
-
var
|
|
5419
|
+
var fs35 = __toESM(require("fs"), 1);
|
|
5420
|
+
var path33 = __toESM(require("path"), 1);
|
|
4937
5421
|
var ENDPOINTS = {
|
|
4938
5422
|
CERT_LIST: "/api/cps/harmony-cert-manage/v1/cert/list",
|
|
4939
5423
|
CERT_ADD: "/api/cps/harmony-cert-manage/v1/cert/add",
|
|
@@ -5019,8 +5503,8 @@ function createAgcClient(http3, auth) {
|
|
|
5019
5503
|
if (target.sha256 && actual !== target.sha256.toLowerCase()) {
|
|
5020
5504
|
throw new ChecksumMismatchError(target.sha256, actual);
|
|
5021
5505
|
}
|
|
5022
|
-
|
|
5023
|
-
|
|
5506
|
+
fs35.mkdirSync(path33.dirname(dest), { recursive: true, mode: 448 });
|
|
5507
|
+
fs35.writeFileSync(dest, buffer, { mode: 384 });
|
|
5024
5508
|
}
|
|
5025
5509
|
};
|
|
5026
5510
|
}
|
|
@@ -5071,22 +5555,22 @@ async function registerDevices(agc, connected, logger) {
|
|
|
5071
5555
|
|
|
5072
5556
|
// src/harmonyos/signing/keystore.ts
|
|
5073
5557
|
var crypto7 = __toESM(require("crypto"), 1);
|
|
5074
|
-
var
|
|
5075
|
-
var
|
|
5558
|
+
var fs37 = __toESM(require("fs"), 1);
|
|
5559
|
+
var path35 = __toESM(require("path"), 1);
|
|
5076
5560
|
|
|
5077
5561
|
// src/harmonyos/java.ts
|
|
5078
|
-
var
|
|
5079
|
-
var
|
|
5562
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
5563
|
+
var path34 = __toESM(require("path"), 1);
|
|
5080
5564
|
var JAVA_BIN = process.platform === "win32" ? "java.exe" : "java";
|
|
5081
5565
|
function findJava(sdk, env = process.env) {
|
|
5082
5566
|
const candidates = [
|
|
5083
|
-
env.JAVA_HOME &&
|
|
5084
|
-
sdk &&
|
|
5567
|
+
env.JAVA_HOME && path34.join(env.JAVA_HOME, "bin", JAVA_BIN),
|
|
5568
|
+
sdk && path34.join(sdk.installRoot, "jbr", "bin", JAVA_BIN),
|
|
5085
5569
|
// macOS: the JBR is itself a bundle inside Studio's Contents.
|
|
5086
|
-
sdk &&
|
|
5087
|
-
...(env.PATH ?? "").split(
|
|
5570
|
+
sdk && path34.join(sdk.installRoot, "jbr", "Contents", "Home", "bin", JAVA_BIN),
|
|
5571
|
+
...(env.PATH ?? "").split(path34.delimiter).map((dir) => dir && path34.join(dir, JAVA_BIN))
|
|
5088
5572
|
];
|
|
5089
|
-
const found = candidates.find((c) => !!c &&
|
|
5573
|
+
const found = candidates.find((c) => !!c && fs36.existsSync(c));
|
|
5090
5574
|
if (found) return found;
|
|
5091
5575
|
throw new OniroError(
|
|
5092
5576
|
"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 +5584,13 @@ function redactArgs(args) {
|
|
|
5100
5584
|
return args.map((arg, i) => args[i - 1] === "-keyPwd" || args[i - 1] === "-keystorePwd" ? "******" : arg);
|
|
5101
5585
|
}
|
|
5102
5586
|
async function generateKeystoreAndCsr(opts) {
|
|
5103
|
-
const jar =
|
|
5104
|
-
if (!
|
|
5587
|
+
const jar = path35.join(opts.sdk.sdkPath, "default", "openharmony", "toolchains", "lib", "hap-sign-tool.jar");
|
|
5588
|
+
if (!fs37.existsSync(jar)) {
|
|
5105
5589
|
throw new OniroError(`hap-sign-tool.jar not found at ${jar}; the HarmonyOS SDK looks incomplete.`);
|
|
5106
5590
|
}
|
|
5107
5591
|
const java = findJava(opts.sdk);
|
|
5108
5592
|
const keyPwd = crypto7.randomBytes(12).toString("base64url").replaceAll(/[-_]/g, "");
|
|
5109
|
-
|
|
5593
|
+
fs37.mkdirSync(path35.dirname(opts.p12Path), { recursive: true, mode: 448 });
|
|
5110
5594
|
const run = async (what, args) => {
|
|
5111
5595
|
const argv = ["-jar", jar, ...args, "-keyAlias", KEY_ALIAS, "-keystoreFile", opts.p12Path, "-keystorePwd", keyPwd, "-keyPwd", keyPwd];
|
|
5112
5596
|
opts.logger.debug(`[harmonyos] ${java} ${redactArgs(argv).join(" ")}`);
|
|
@@ -5120,28 +5604,28 @@ ${detail}` : ""}`);
|
|
|
5120
5604
|
opts.logger.info("[harmonyos] Generating the local keystore and certificate signing request...");
|
|
5121
5605
|
await run("generate the key pair", ["generate-keypair", "-keyAlg", "ECC", "-keySize", "NIST-P-256"]);
|
|
5122
5606
|
await run("generate the CSR", ["generate-csr", "-subject", "CN=DebugKey", "-signAlg", SIGN_ALG, "-outFile", opts.csrPath]);
|
|
5123
|
-
return { keyPwd, csr:
|
|
5607
|
+
return { keyPwd, csr: fs37.readFileSync(opts.csrPath, "utf8") };
|
|
5124
5608
|
}
|
|
5125
5609
|
|
|
5126
5610
|
// src/harmonyos/signing/paths.ts
|
|
5127
5611
|
var crypto8 = __toESM(require("crypto"), 1);
|
|
5128
|
-
var
|
|
5612
|
+
var path36 = __toESM(require("path"), 1);
|
|
5129
5613
|
function sanitizeNamePart(raw) {
|
|
5130
5614
|
const safe = (raw?.trim() ?? "").replace(/[\\/:*?"<>|=.-]+/g, "_");
|
|
5131
5615
|
return safe.slice(0, 64) || "default";
|
|
5132
5616
|
}
|
|
5133
5617
|
function resolveSigningMaterialPaths(config, productName, projectRoot) {
|
|
5134
5618
|
const hash = crypto8.createHash("sha256").update(projectRoot, "utf8").digest("base64url").replaceAll(/[-_]/g, "");
|
|
5135
|
-
const base =
|
|
5619
|
+
const base = path36.join(
|
|
5136
5620
|
config.get("harmonyosSigningDir", defaultPaths.harmonyosSigningDir()),
|
|
5137
|
-
`${sanitizeNamePart(productName)}_${
|
|
5621
|
+
`${sanitizeNamePart(productName)}_${path36.basename(projectRoot)}_${hash}=`
|
|
5138
5622
|
);
|
|
5139
5623
|
return { p12Path: `${base}.p12`, csrPath: `${base}.csr`, cerPath: `${base}.cer`, profilePath: `${base}.p7b` };
|
|
5140
5624
|
}
|
|
5141
5625
|
|
|
5142
5626
|
// src/harmonyos/signing/project.ts
|
|
5143
|
-
var
|
|
5144
|
-
var
|
|
5627
|
+
var fs38 = __toESM(require("fs"), 1);
|
|
5628
|
+
var path37 = __toESM(require("path"), 1);
|
|
5145
5629
|
var import_json56 = __toESM(require("json5"), 1);
|
|
5146
5630
|
|
|
5147
5631
|
// src/harmonyos/signing/aclPermissionList.ts
|
|
@@ -5209,9 +5693,9 @@ var ACL_PERMISSIONS = /* @__PURE__ */ new Set([
|
|
|
5209
5693
|
|
|
5210
5694
|
// src/harmonyos/signing/project.ts
|
|
5211
5695
|
function readRequestedPermissions(moduleConfigPath) {
|
|
5212
|
-
if (!
|
|
5696
|
+
if (!fs38.existsSync(moduleConfigPath)) return [];
|
|
5213
5697
|
try {
|
|
5214
|
-
const parsed = import_json56.default.parse(
|
|
5698
|
+
const parsed = import_json56.default.parse(fs38.readFileSync(moduleConfigPath, "utf-8"));
|
|
5215
5699
|
return (parsed.module?.requestPermissions ?? []).map((p) => p?.name).filter((n) => typeof n === "string" && n.length > 0);
|
|
5216
5700
|
} catch {
|
|
5217
5701
|
return [];
|
|
@@ -5220,10 +5704,10 @@ function readRequestedPermissions(moduleConfigPath) {
|
|
|
5220
5704
|
function collectAclPermissions(projectDir, logger = noopLogger) {
|
|
5221
5705
|
const requested = /* @__PURE__ */ new Set();
|
|
5222
5706
|
for (const module2 of listModules({ projectDir })) {
|
|
5223
|
-
const moduleRoot =
|
|
5707
|
+
const moduleRoot = path37.resolve(projectDir, module2.srcPath);
|
|
5224
5708
|
for (const sourceSet of ["main", "ohosTest"]) {
|
|
5225
5709
|
for (const name of readRequestedPermissions(
|
|
5226
|
-
|
|
5710
|
+
path37.join(moduleRoot, "src", sourceSet, "module.json5")
|
|
5227
5711
|
)) {
|
|
5228
5712
|
requested.add(name);
|
|
5229
5713
|
}
|
|
@@ -5239,7 +5723,7 @@ function collectAclPermissions(projectDir, logger = noopLogger) {
|
|
|
5239
5723
|
// src/harmonyos/signing/autoSign.ts
|
|
5240
5724
|
function shouldRegenerate(input) {
|
|
5241
5725
|
if (input.force) return "--force was passed";
|
|
5242
|
-
const missing = Object.values(input.paths).find((file) => !
|
|
5726
|
+
const missing = Object.values(input.paths).find((file) => !fs39.existsSync(file));
|
|
5243
5727
|
if (missing) return `${missing} is missing`;
|
|
5244
5728
|
const config = input.buildProfile.app?.signingConfigs?.find((c) => c.name === input.productName);
|
|
5245
5729
|
if (config?.type !== "HarmonyOS" || config.material?.profile !== input.paths.profilePath) {
|
|
@@ -5278,16 +5762,16 @@ function writeSigningConfig(opts) {
|
|
|
5278
5762
|
for (const product of app.products ?? []) {
|
|
5279
5763
|
if (product.name === opts.productName) product.signingConfig = opts.productName;
|
|
5280
5764
|
}
|
|
5281
|
-
|
|
5765
|
+
fs39.writeFileSync(opts.buildProfilePath, JSON.stringify(opts.buildProfile, null, 2));
|
|
5282
5766
|
}
|
|
5283
5767
|
async function harmonyOsAutoSign(opts) {
|
|
5284
5768
|
const logger = opts.logger ?? noopLogger;
|
|
5285
5769
|
const productName = opts.productName ?? "default";
|
|
5286
|
-
const projectDir =
|
|
5287
|
-
const buildProfilePath =
|
|
5770
|
+
const projectDir = path38.resolve(opts.projectDir);
|
|
5771
|
+
const buildProfilePath = path38.join(projectDir, "build-profile.json5");
|
|
5288
5772
|
let buildProfile;
|
|
5289
5773
|
try {
|
|
5290
|
-
buildProfile = import_json57.default.parse(
|
|
5774
|
+
buildProfile = import_json57.default.parse(fs39.readFileSync(buildProfilePath, "utf-8"));
|
|
5291
5775
|
} catch (err) {
|
|
5292
5776
|
throw new OniroError(`Could not read ${buildProfilePath}: ${err.message}`, err);
|
|
5293
5777
|
}
|
|
@@ -5327,7 +5811,7 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5327
5811
|
logger.info(`[harmonyos] Regenerating signing material: ${reason}.`);
|
|
5328
5812
|
const agc = createAgcClient(opts.http ?? createHttpClient({ logger }), auth);
|
|
5329
5813
|
const deviceIds = await registerDevices(agc, connected, logger);
|
|
5330
|
-
for (const file of Object.values(paths))
|
|
5814
|
+
for (const file of Object.values(paths)) fs39.rmSync(file, { force: true });
|
|
5331
5815
|
const certName = `oniro_debug_${auth.teamId.replace(/[\\/.:]/g, "")}.cer`;
|
|
5332
5816
|
const stale = (await agc.listCertificates()).find((c) => c.certName === certName);
|
|
5333
5817
|
if (stale) {
|
|
@@ -5358,10 +5842,10 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5358
5842
|
try {
|
|
5359
5843
|
verifySigningMaterial({ ...paths, keyAlias: KEY_ALIAS, keyPwd });
|
|
5360
5844
|
} catch (err) {
|
|
5361
|
-
|
|
5845
|
+
fs39.rmSync(paths.profilePath, { force: true });
|
|
5362
5846
|
throw err;
|
|
5363
5847
|
}
|
|
5364
|
-
const materialDir =
|
|
5848
|
+
const materialDir = path38.join(path38.dirname(paths.p12Path), "material");
|
|
5365
5849
|
try {
|
|
5366
5850
|
getKey(materialDir);
|
|
5367
5851
|
} catch {
|
|
@@ -5373,7 +5857,7 @@ async function harmonyOsAutoSign(opts) {
|
|
|
5373
5857
|
}
|
|
5374
5858
|
|
|
5375
5859
|
// src/index.ts
|
|
5376
|
-
var VERSION = "0.
|
|
5860
|
+
var VERSION = "0.14.1";
|
|
5377
5861
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5378
5862
|
0 && (module.exports = {
|
|
5379
5863
|
ALL_SDKS,
|
|
@@ -5396,7 +5880,9 @@ var VERSION = "0.13.0";
|
|
|
5396
5880
|
TargetNotFoundError,
|
|
5397
5881
|
UnsupportedPlatformError,
|
|
5398
5882
|
VERSION,
|
|
5883
|
+
appSandboxDir,
|
|
5399
5884
|
applyChanges,
|
|
5885
|
+
assertDevicePath,
|
|
5400
5886
|
assertLayoutSelector,
|
|
5401
5887
|
attemptHdcConnection,
|
|
5402
5888
|
buildCmdWrapper,
|
|
@@ -5407,6 +5893,8 @@ var VERSION = "0.13.0";
|
|
|
5407
5893
|
buildInputCommand,
|
|
5408
5894
|
buildRawTouchCommand,
|
|
5409
5895
|
captureBurst,
|
|
5896
|
+
captureLog,
|
|
5897
|
+
cleanCodelinterOutput,
|
|
5410
5898
|
consoleLogger,
|
|
5411
5899
|
createHarmonyOsSession,
|
|
5412
5900
|
createInstallTempDir,
|
|
@@ -5422,9 +5910,12 @@ var VERSION = "0.13.0";
|
|
|
5422
5910
|
defaultPaths,
|
|
5423
5911
|
describeLayoutNode,
|
|
5424
5912
|
detectAaStartFailure,
|
|
5913
|
+
detectCmdToolsFlavour,
|
|
5914
|
+
detectInstallFailure,
|
|
5425
5915
|
detectProjectSdkVersion,
|
|
5426
5916
|
detectRuntimeOs,
|
|
5427
5917
|
detectSigningConfigNames,
|
|
5918
|
+
diagnoseBuildFailure,
|
|
5428
5919
|
diffEntryNames,
|
|
5429
5920
|
diffHapAssets,
|
|
5430
5921
|
discoverHaps,
|
|
@@ -5437,11 +5928,13 @@ var VERSION = "0.13.0";
|
|
|
5437
5928
|
dumpWindow,
|
|
5438
5929
|
encryptPwd,
|
|
5439
5930
|
ensureFreeSpace,
|
|
5931
|
+
ensureInstallOk,
|
|
5440
5932
|
ensureOhModules,
|
|
5441
5933
|
ensureOk,
|
|
5442
5934
|
ensureRemoteOk,
|
|
5443
5935
|
escapeCmdArgument,
|
|
5444
5936
|
escapeCmdCommand,
|
|
5937
|
+
existingHapOrUnsigned,
|
|
5445
5938
|
extractTarball,
|
|
5446
5939
|
extractZipWithProgress,
|
|
5447
5940
|
findAppProcessId,
|
|
@@ -5450,6 +5943,7 @@ var VERSION = "0.13.0";
|
|
|
5450
5943
|
findHarmonyOsSdk,
|
|
5451
5944
|
findKeyboardWindow,
|
|
5452
5945
|
findLayoutNodes,
|
|
5946
|
+
findMissingProjectSdk,
|
|
5453
5947
|
findRunningProcess,
|
|
5454
5948
|
flattenLayout,
|
|
5455
5949
|
forceStop,
|
|
@@ -5463,6 +5957,7 @@ var VERSION = "0.13.0";
|
|
|
5463
5957
|
getDeviceInfo,
|
|
5464
5958
|
getDisplaySize,
|
|
5465
5959
|
getEmulatorDir,
|
|
5960
|
+
getEmulatorStatus,
|
|
5466
5961
|
getFreeSpaceBytes,
|
|
5467
5962
|
getHdcPath,
|
|
5468
5963
|
getHvigorwPath,
|
|
@@ -5478,15 +5973,21 @@ var VERSION = "0.13.0";
|
|
|
5478
5973
|
getSupportedSdksForUi,
|
|
5479
5974
|
harmonyOsAutoSign,
|
|
5480
5975
|
harmonyOsSdkLabelForApi,
|
|
5976
|
+
hdcClientFailure,
|
|
5481
5977
|
hdcExec,
|
|
5978
|
+
hdcTargetArgs,
|
|
5979
|
+
hdcTargetArgsFor,
|
|
5482
5980
|
hideKeyboard,
|
|
5483
5981
|
installApp,
|
|
5484
5982
|
installCmdTools,
|
|
5485
5983
|
installEmulator,
|
|
5984
|
+
installFailureReason,
|
|
5985
|
+
isBundleInstalled,
|
|
5486
5986
|
isCmdToolsInstalled,
|
|
5487
5987
|
isEmulatorInstalled,
|
|
5488
5988
|
isOutOfSpaceError,
|
|
5489
5989
|
isRamBackedPath,
|
|
5990
|
+
isUnsignedHap,
|
|
5490
5991
|
isValidBundleName,
|
|
5491
5992
|
isValidProjectName,
|
|
5492
5993
|
killProcessTree,
|
|
@@ -5501,16 +6002,21 @@ var VERSION = "0.13.0";
|
|
|
5501
6002
|
nonInteractivePrompter,
|
|
5502
6003
|
noopLogger,
|
|
5503
6004
|
noopProgress,
|
|
6005
|
+
normaliseLocalPath,
|
|
5504
6006
|
paramGet,
|
|
6007
|
+
paramGetMany,
|
|
5505
6008
|
paramSet,
|
|
5506
6009
|
parseBounds,
|
|
5507
6010
|
parseCodelinterFindings,
|
|
6011
|
+
parseCodelinterReport,
|
|
5508
6012
|
parseDeviceList,
|
|
5509
6013
|
parseHilogLine,
|
|
5510
6014
|
parseImeBundles,
|
|
5511
6015
|
parseMainAbilityFromBmDump,
|
|
6016
|
+
parseParamValues,
|
|
5512
6017
|
parseRemoteExit,
|
|
5513
6018
|
performInput,
|
|
6019
|
+
pickHap,
|
|
5514
6020
|
pickSigningKind,
|
|
5515
6021
|
pickTarget,
|
|
5516
6022
|
prepareSigning,
|
|
@@ -5525,6 +6031,7 @@ var VERSION = "0.13.0";
|
|
|
5525
6031
|
removeSdk,
|
|
5526
6032
|
removeTempWorkDir,
|
|
5527
6033
|
requireHarmonyOsSdk,
|
|
6034
|
+
resolveDeviceSerial,
|
|
5528
6035
|
resolveKeyEvent,
|
|
5529
6036
|
resolveTmpRoot,
|
|
5530
6037
|
runCodelinter,
|
|
@@ -5549,6 +6056,7 @@ var VERSION = "0.13.0";
|
|
|
5549
6056
|
toLongPath,
|
|
5550
6057
|
toSpaceError,
|
|
5551
6058
|
uninstallApp,
|
|
6059
|
+
unsignedHapRejection,
|
|
5552
6060
|
validateTemplateLayout,
|
|
5553
6061
|
verifySha256,
|
|
5554
6062
|
waitForBoot,
|