@oniroproject/core 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +375 -244
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +92 -3
- package/dist/index.d.ts +92 -3
- package/dist/index.js +369 -245
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -217,6 +217,14 @@ function getCmdToolsPath(config) {
|
|
|
217
217
|
function getEmulatorDir(config) {
|
|
218
218
|
return config.get("emulatorDir", defaultPaths.emulatorDir());
|
|
219
219
|
}
|
|
220
|
+
function toLongPath(p, platform7 = os3.platform()) {
|
|
221
|
+
if (platform7 !== "win32") return p;
|
|
222
|
+
try {
|
|
223
|
+
return fs.realpathSync.native(p);
|
|
224
|
+
} catch {
|
|
225
|
+
return p;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
220
228
|
function pickExisting(candidates) {
|
|
221
229
|
for (const c of candidates) {
|
|
222
230
|
if (fs.existsSync(c)) return c;
|
|
@@ -252,12 +260,11 @@ function getHdcPath(config) {
|
|
|
252
260
|
}
|
|
253
261
|
return path2.join(base, "hdc");
|
|
254
262
|
}
|
|
255
|
-
function getHvigorwPath(config, projectDir) {
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
]);
|
|
263
|
+
function getHvigorwPath(config, projectDir, platform7 = os3.platform()) {
|
|
264
|
+
const posixFirst = ["hvigorw", "hvigorw.bat", "hvigorw.cmd"];
|
|
265
|
+
const windowsFirst = ["hvigorw.bat", "hvigorw.cmd", "hvigorw"];
|
|
266
|
+
const names = platform7 === "win32" ? windowsFirst : posixFirst;
|
|
267
|
+
const local = pickExisting(names.map((n) => path2.join(projectDir, n)));
|
|
261
268
|
if (fs.existsSync(local) && isProjectLocalHvigorwWorking(projectDir)) {
|
|
262
269
|
return local;
|
|
263
270
|
}
|
|
@@ -337,7 +344,7 @@ function createInstallTempDir(opts) {
|
|
|
337
344
|
} catch (err) {
|
|
338
345
|
const fallback = os4.tmpdir();
|
|
339
346
|
if (requested || isOutOfSpaceError(err) || path4.resolve(fallback) === path4.resolve(root)) throw err;
|
|
340
|
-
const reason = err instanceof Error ? err.message.split(
|
|
347
|
+
const reason = err instanceof Error ? err.message.split(/\r?\n/)[0] : String(err);
|
|
341
348
|
(opts.logger ?? noopLogger).warn(`${reason} Falling back to '${fallback}'.`);
|
|
342
349
|
return { dir: createTempWorkDir(fallback, opts.prefix), root: fallback };
|
|
343
350
|
}
|
|
@@ -789,8 +796,82 @@ async function downloadAndInstallSdk(opts) {
|
|
|
789
796
|
// src/cmdTools/install.ts
|
|
790
797
|
import * as fs10 from "fs";
|
|
791
798
|
import * as os6 from "os";
|
|
799
|
+
import * as path11 from "path";
|
|
800
|
+
import { spawnSync } from "child_process";
|
|
801
|
+
|
|
802
|
+
// src/hdc/spawnCompat.ts
|
|
792
803
|
import * as path10 from "path";
|
|
793
|
-
import {
|
|
804
|
+
import { spawn } from "child_process";
|
|
805
|
+
var WINDOWS_BATCH_RE = /\.(bat|cmd)$/i;
|
|
806
|
+
var CMD_META_RE = /([()[\]%!^"`<>&|;, *?])/g;
|
|
807
|
+
var CMD_SHIM_RE = /node_modules[\\/]\.bin[\\/][^\\/]+\.cmd$/i;
|
|
808
|
+
var UNSAFE_CMD_CHARS_RE = /["\r\n\0]/;
|
|
809
|
+
function needsCmdWrapper(command, platform7 = process.platform) {
|
|
810
|
+
return platform7 === "win32" && WINDOWS_BATCH_RE.test(command);
|
|
811
|
+
}
|
|
812
|
+
function escapeCmdArgument(arg, doubleEscapeMetaChars = false) {
|
|
813
|
+
let out = String(arg);
|
|
814
|
+
out = out.replace(/(\\*)"/g, '$1$1\\"');
|
|
815
|
+
out = out.replace(/(\\*)$/, "$1$1");
|
|
816
|
+
out = `"${out}"`;
|
|
817
|
+
out = out.replace(CMD_META_RE, "^$1");
|
|
818
|
+
if (doubleEscapeMetaChars) out = out.replace(CMD_META_RE, "^$1");
|
|
819
|
+
return out;
|
|
820
|
+
}
|
|
821
|
+
function escapeCmdCommand(command) {
|
|
822
|
+
return command.replace(CMD_META_RE, "^$1");
|
|
823
|
+
}
|
|
824
|
+
function buildCmdWrapper(command, args) {
|
|
825
|
+
assertCmdSafe(command, `command ${command}`);
|
|
826
|
+
args.forEach((a, i) => assertCmdSafe(a, `argument ${i} (${a})`));
|
|
827
|
+
const normalized = path10.normalize(command);
|
|
828
|
+
const double = CMD_SHIM_RE.test(normalized);
|
|
829
|
+
const line = [escapeCmdCommand(normalized), ...args.map((a) => escapeCmdArgument(a, double))].join(" ");
|
|
830
|
+
return {
|
|
831
|
+
command: process.env.ComSpec ?? process.env.COMSPEC ?? "cmd.exe",
|
|
832
|
+
args: ["/d", "/s", "/c", `"${line}"`]
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
function assertCmdSafe(value, label) {
|
|
836
|
+
if (UNSAFE_CMD_CHARS_RE.test(value)) {
|
|
837
|
+
throw new OniroError(
|
|
838
|
+
`Cannot run a Windows batch wrapper with a quote, newline or NUL in the ${label}: cmd.exe cannot pass it through unambiguously.`
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
function spawnCompat(command, args, options = {}) {
|
|
843
|
+
if (!needsCmdWrapper(command)) {
|
|
844
|
+
return spawn(command, [...args], { ...options, shell: false });
|
|
845
|
+
}
|
|
846
|
+
const wrapped = buildCmdWrapper(command, args);
|
|
847
|
+
return spawn(wrapped.command, wrapped.args, {
|
|
848
|
+
...options,
|
|
849
|
+
shell: false,
|
|
850
|
+
// The line is already escaped; stop Node from re-quoting it.
|
|
851
|
+
windowsVerbatimArguments: true
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
function killProcessTree(child) {
|
|
855
|
+
if (process.platform === "win32" && typeof child.pid === "number") {
|
|
856
|
+
try {
|
|
857
|
+
const killer = spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], { stdio: "ignore" });
|
|
858
|
+
killer.on("error", () => {
|
|
859
|
+
try {
|
|
860
|
+
child.kill("SIGKILL");
|
|
861
|
+
} catch {
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
return;
|
|
865
|
+
} catch {
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
try {
|
|
869
|
+
child.kill("SIGKILL");
|
|
870
|
+
} catch {
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
// src/cmdTools/install.ts
|
|
794
875
|
function getCmdToolsDownloadUrl(config, platform7 = os6.platform()) {
|
|
795
876
|
if (platform7 === "linux") {
|
|
796
877
|
return config.get("cmdToolsUrlLinux", defaultPaths.cmdToolsUrlLinux);
|
|
@@ -817,16 +898,16 @@ function getCmdToolsDownloadUrl(config, platform7 = os6.platform()) {
|
|
|
817
898
|
}
|
|
818
899
|
function findCmdToolsSourceDir(extractPath) {
|
|
819
900
|
const known = [
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
901
|
+
path11.join(extractPath, "command-line-tools"),
|
|
902
|
+
path11.join(extractPath, "oh-command-line-tools"),
|
|
903
|
+
path11.join(extractPath, "commandline-tools")
|
|
823
904
|
];
|
|
824
905
|
for (const c of known) {
|
|
825
906
|
if (fs10.existsSync(c)) return c;
|
|
826
907
|
}
|
|
827
|
-
const entries = fs10.readdirSync(extractPath, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) =>
|
|
908
|
+
const entries = fs10.readdirSync(extractPath, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path11.join(extractPath, e.name));
|
|
828
909
|
for (const dir of entries) {
|
|
829
|
-
if (fs10.existsSync(
|
|
910
|
+
if (fs10.existsSync(path11.join(dir, "bin"))) return dir;
|
|
830
911
|
}
|
|
831
912
|
throw new OniroError("Could not locate command line tools folder in the extracted archive.");
|
|
832
913
|
}
|
|
@@ -838,12 +919,12 @@ async function installCmdTools(opts) {
|
|
|
838
919
|
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
839
920
|
config,
|
|
840
921
|
override: opts.tmpDir,
|
|
841
|
-
installRoot:
|
|
922
|
+
installRoot: path11.dirname(CMD_PATH),
|
|
842
923
|
prefix: "oniro-cmdtools-",
|
|
843
924
|
logger
|
|
844
925
|
});
|
|
845
|
-
const zipPath = opts.localZipPath ??
|
|
846
|
-
const extractPath =
|
|
926
|
+
const zipPath = opts.localZipPath ?? path11.join(tmpDir, "oh-command-line-tools.zip");
|
|
927
|
+
const extractPath = path11.join(tmpDir, "oh-command-line-tools");
|
|
847
928
|
try {
|
|
848
929
|
if (!opts.localZipPath) {
|
|
849
930
|
const url = getCmdToolsDownloadUrl(config);
|
|
@@ -855,8 +936,8 @@ async function installCmdTools(opts) {
|
|
|
855
936
|
fs10.mkdirSync(CMD_PATH, { recursive: true });
|
|
856
937
|
const srcDir = findCmdToolsSourceDir(extractPath);
|
|
857
938
|
for (const entry of fs10.readdirSync(srcDir)) {
|
|
858
|
-
const src =
|
|
859
|
-
const dest =
|
|
939
|
+
const src = path11.join(srcDir, entry);
|
|
940
|
+
const dest = path11.join(CMD_PATH, entry);
|
|
860
941
|
if (fs10.statSync(src).isDirectory()) {
|
|
861
942
|
if (fs10.existsSync(dest)) fs10.rmSync(dest, { recursive: true, force: true });
|
|
862
943
|
movePath(src, dest);
|
|
@@ -864,10 +945,10 @@ async function installCmdTools(opts) {
|
|
|
864
945
|
fs10.copyFileSync(src, dest);
|
|
865
946
|
}
|
|
866
947
|
}
|
|
867
|
-
const binDir =
|
|
948
|
+
const binDir = path11.join(CMD_PATH, "bin");
|
|
868
949
|
if (fs10.existsSync(binDir) && os6.platform() !== "win32") {
|
|
869
950
|
for (const file of fs10.readdirSync(binDir)) {
|
|
870
|
-
fs10.chmodSync(
|
|
951
|
+
fs10.chmodSync(path11.join(binDir, file), 493);
|
|
871
952
|
}
|
|
872
953
|
}
|
|
873
954
|
progress?.report({ message: "Finalizing installation...", increment: 5 });
|
|
@@ -880,14 +961,14 @@ async function installCmdTools(opts) {
|
|
|
880
961
|
}
|
|
881
962
|
function getCmdToolsStatus(config) {
|
|
882
963
|
const cmdPath = getCmdToolsPath(config);
|
|
883
|
-
const binDir =
|
|
964
|
+
const binDir = path11.join(cmdPath, "bin");
|
|
884
965
|
const candidates = os6.platform() === "win32" ? ["ohpm.exe", "ohpm.cmd", "ohpm.bat", "ohpm"] : ["ohpm"];
|
|
885
|
-
const bin = candidates.map((c) =>
|
|
966
|
+
const bin = candidates.map((c) => path11.join(binDir, c)).find((p) => fs10.existsSync(p));
|
|
886
967
|
if (!bin) {
|
|
887
968
|
return { installed: false, status: "Not installed" };
|
|
888
969
|
}
|
|
889
970
|
try {
|
|
890
|
-
const versionFile =
|
|
971
|
+
const versionFile = path11.join(cmdPath, "version.txt");
|
|
891
972
|
if (fs10.existsSync(versionFile)) {
|
|
892
973
|
const content = fs10.readFileSync(versionFile, "utf8");
|
|
893
974
|
for (const line of content.split(/\r?\n/)) {
|
|
@@ -898,7 +979,14 @@ function getCmdToolsStatus(config) {
|
|
|
898
979
|
} catch {
|
|
899
980
|
}
|
|
900
981
|
try {
|
|
901
|
-
const
|
|
982
|
+
const wrapped = needsCmdWrapper(bin);
|
|
983
|
+
const probe = wrapped ? buildCmdWrapper(bin, ["-v"]) : { command: bin, args: ["-v"] };
|
|
984
|
+
const res = spawnSync(probe.command, probe.args, {
|
|
985
|
+
encoding: "utf8",
|
|
986
|
+
windowsVerbatimArguments: wrapped
|
|
987
|
+
});
|
|
988
|
+
if (res.error || res.status !== 0) throw res.error ?? new Error(`exit ${String(res.status)}`);
|
|
989
|
+
const version = res.stdout.trim();
|
|
902
990
|
return { installed: true, status: `Installed (${version})` };
|
|
903
991
|
} catch {
|
|
904
992
|
return { installed: true, status: "Installed (version unknown)" };
|
|
@@ -916,7 +1004,7 @@ function removeCmdTools(config) {
|
|
|
916
1004
|
|
|
917
1005
|
// src/sign/encryptKey.ts
|
|
918
1006
|
import * as fs11 from "fs";
|
|
919
|
-
import * as
|
|
1007
|
+
import * as path12 from "path";
|
|
920
1008
|
import * as crypto2 from "crypto";
|
|
921
1009
|
var DAEMON_ROOT_KEY_COMPONENT_LENGTH = 16;
|
|
922
1010
|
var DAEMON_SALT_KEY_LENGTH = 16;
|
|
@@ -988,7 +1076,7 @@ function getRootKey(fdComponents, salt) {
|
|
|
988
1076
|
function createAndStoreKey(dir, keyLength) {
|
|
989
1077
|
const key = crypto2.randomBytes(keyLength);
|
|
990
1078
|
const hash = crypto2.createHash("sha256").update(key).digest("hex");
|
|
991
|
-
const filePath =
|
|
1079
|
+
const filePath = path12.join(dir, hash);
|
|
992
1080
|
fs11.writeFileSync(filePath, key);
|
|
993
1081
|
fs11.chmodSync(filePath, KEY_FILE_PERMISSIONS);
|
|
994
1082
|
return key;
|
|
@@ -997,23 +1085,23 @@ function createAndStoreEnKey(rootKey, ceDir) {
|
|
|
997
1085
|
const workKey = crypto2.randomBytes(DAEMON_WORK_KEY_LENGTH);
|
|
998
1086
|
const encrypted = encrypt(rootKey, workKey);
|
|
999
1087
|
const hash = crypto2.createHash("sha256").update(encrypted).digest("hex");
|
|
1000
|
-
const filePath =
|
|
1088
|
+
const filePath = path12.join(ceDir, hash);
|
|
1001
1089
|
fs11.writeFileSync(filePath, encrypted);
|
|
1002
1090
|
fs11.chmodSync(filePath, KEY_FILE_PERMISSIONS);
|
|
1003
1091
|
}
|
|
1004
1092
|
function createMaterial(materialPath) {
|
|
1005
1093
|
fs11.mkdirSync(materialPath, { recursive: true });
|
|
1006
1094
|
fs11.chmodSync(materialPath, KEY_FILE_DIRECTORY_PERMISSIONS);
|
|
1007
|
-
const fdDir =
|
|
1008
|
-
const acDir =
|
|
1009
|
-
const ceDir =
|
|
1095
|
+
const fdDir = path12.join(materialPath, "fd");
|
|
1096
|
+
const acDir = path12.join(materialPath, "ac");
|
|
1097
|
+
const ceDir = path12.join(materialPath, "ce");
|
|
1010
1098
|
fs11.mkdirSync(fdDir, { recursive: true });
|
|
1011
1099
|
fs11.mkdirSync(acDir, { recursive: true });
|
|
1012
1100
|
fs11.mkdirSync(ceDir, { recursive: true });
|
|
1013
1101
|
const fdSubDirs = ["0", "1", "2"];
|
|
1014
1102
|
const fdComponents = [];
|
|
1015
1103
|
for (const sub of fdSubDirs) {
|
|
1016
|
-
const subDir =
|
|
1104
|
+
const subDir = path12.join(fdDir, sub);
|
|
1017
1105
|
fs11.mkdirSync(subDir, { recursive: true });
|
|
1018
1106
|
const comp = createAndStoreKey(subDir, DAEMON_ROOT_KEY_COMPONENT_LENGTH);
|
|
1019
1107
|
fdComponents.push(comp);
|
|
@@ -1030,17 +1118,17 @@ function readSingleFile(dir) {
|
|
|
1030
1118
|
if (files.length !== 1) {
|
|
1031
1119
|
throw new Error(`Signing material in ${dir} is illegal (expected exactly one file).`);
|
|
1032
1120
|
}
|
|
1033
|
-
return fs11.readFileSync(
|
|
1121
|
+
return fs11.readFileSync(path12.join(dir, files[0]));
|
|
1034
1122
|
}
|
|
1035
1123
|
function getKey(materialPath) {
|
|
1036
1124
|
if (!fs11.existsSync(materialPath) || !fs11.statSync(materialPath).isDirectory()) {
|
|
1037
1125
|
throw new Error("Material directory does not exist.");
|
|
1038
1126
|
}
|
|
1039
|
-
const fdDir =
|
|
1040
|
-
const fdComponents = ["0", "1", "2"].map((sub) => readSingleFile(
|
|
1041
|
-
const salt = readSingleFile(
|
|
1127
|
+
const fdDir = path12.join(materialPath, "fd");
|
|
1128
|
+
const fdComponents = ["0", "1", "2"].map((sub) => readSingleFile(path12.join(fdDir, sub)));
|
|
1129
|
+
const salt = readSingleFile(path12.join(materialPath, "ac"));
|
|
1042
1130
|
const rootKey = getRootKey(fdComponents, salt);
|
|
1043
|
-
const workMaterial = readSingleFile(
|
|
1131
|
+
const workMaterial = readSingleFile(path12.join(materialPath, "ce"));
|
|
1044
1132
|
return decrypt(rootKey, workMaterial);
|
|
1045
1133
|
}
|
|
1046
1134
|
function encryptPwd(password, materialPath) {
|
|
@@ -1056,8 +1144,8 @@ function decryptPwd(encryptedHex, materialPath) {
|
|
|
1056
1144
|
|
|
1057
1145
|
// src/sign/generateSigningConfigs.ts
|
|
1058
1146
|
import * as fs12 from "fs";
|
|
1059
|
-
import * as
|
|
1060
|
-
import { execFileSync
|
|
1147
|
+
import * as path13 from "path";
|
|
1148
|
+
import { execFileSync } from "child_process";
|
|
1061
1149
|
import JSON52 from "json5";
|
|
1062
1150
|
|
|
1063
1151
|
// src/sign/applicationCert.ts
|
|
@@ -1126,13 +1214,13 @@ var SIGNING_KIND_CONFIG = {
|
|
|
1126
1214
|
};
|
|
1127
1215
|
function copyFilesToProject(projectDir, paths, kind, logger, applicationCertPath) {
|
|
1128
1216
|
logger.info("[sign] Copying signing material into project...");
|
|
1129
|
-
const signaturesDir =
|
|
1217
|
+
const signaturesDir = path13.join(projectDir, "signatures");
|
|
1130
1218
|
fs12.mkdirSync(signaturesDir, { recursive: true });
|
|
1131
|
-
fs12.copyFileSync(paths.keystore,
|
|
1132
|
-
fs12.copyFileSync(paths.profileCert,
|
|
1133
|
-
fs12.copyFileSync(paths.unsignedProfileTemplate,
|
|
1219
|
+
fs12.copyFileSync(paths.keystore, path13.join(signaturesDir, "OpenHarmony.p12"));
|
|
1220
|
+
fs12.copyFileSync(paths.profileCert, path13.join(signaturesDir, "OpenHarmonyProfileRelease.pem"));
|
|
1221
|
+
fs12.copyFileSync(paths.unsignedProfileTemplate, path13.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json"));
|
|
1134
1222
|
if (kind === "application-release") {
|
|
1135
|
-
const dest =
|
|
1223
|
+
const dest = path13.join(signaturesDir, "OpenHarmonyApplication.cer");
|
|
1136
1224
|
if (applicationCertPath) {
|
|
1137
1225
|
fs12.copyFileSync(applicationCertPath, dest);
|
|
1138
1226
|
} else {
|
|
@@ -1155,8 +1243,8 @@ function extractLeafCertificate(chainPath) {
|
|
|
1155
1243
|
function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}) {
|
|
1156
1244
|
const kind = options.kind ?? pickSigningKind(apl);
|
|
1157
1245
|
logger.info(`[sign] Modifying profile template (apl=${apl}, app-feature=${appFeature}, kind=${kind})...`);
|
|
1158
|
-
const appJsonPath =
|
|
1159
|
-
const profileTemplatePath =
|
|
1246
|
+
const appJsonPath = path13.join(projectDir, "AppScope/app.json5");
|
|
1247
|
+
const profileTemplatePath = path13.join(projectDir, "signatures/UnsgnedReleasedProfileTemplate.json");
|
|
1160
1248
|
if (!fs12.existsSync(appJsonPath)) {
|
|
1161
1249
|
throw new OniroError(`${appJsonPath} does not exist.`);
|
|
1162
1250
|
}
|
|
@@ -1181,7 +1269,7 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
|
|
|
1181
1269
|
profileTemplate["bundle-info"]["bundle-name"] = appJson.app.bundleName;
|
|
1182
1270
|
profileTemplate["bundle-info"]["apl"] = apl;
|
|
1183
1271
|
profileTemplate["bundle-info"]["app-feature"] = appFeature;
|
|
1184
|
-
const distCertChainPath =
|
|
1272
|
+
const distCertChainPath = path13.join(
|
|
1185
1273
|
projectDir,
|
|
1186
1274
|
"signatures",
|
|
1187
1275
|
SIGNING_KIND_CONFIG[kind].certBasename
|
|
@@ -1195,9 +1283,9 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
|
|
|
1195
1283
|
}
|
|
1196
1284
|
function generateP7bFile(projectDir, paths, logger, passwords) {
|
|
1197
1285
|
logger.info("[sign] Generating P7b profile via hap-sign-tool...");
|
|
1198
|
-
const signaturesDir =
|
|
1199
|
-
const profileTemplatePath =
|
|
1200
|
-
const outputProfilePath =
|
|
1286
|
+
const signaturesDir = path13.join(projectDir, "signatures");
|
|
1287
|
+
const profileTemplatePath = path13.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json");
|
|
1288
|
+
const outputProfilePath = path13.join(signaturesDir, "app1-profile.p7b");
|
|
1201
1289
|
const args = [
|
|
1202
1290
|
"-jar",
|
|
1203
1291
|
paths.signTool,
|
|
@@ -1222,7 +1310,7 @@ function generateP7bFile(projectDir, paths, logger, passwords) {
|
|
|
1222
1310
|
passwords.store
|
|
1223
1311
|
];
|
|
1224
1312
|
try {
|
|
1225
|
-
|
|
1313
|
+
execFileSync("java", args, { stdio: "inherit" });
|
|
1226
1314
|
} catch (e) {
|
|
1227
1315
|
throw new OniroError(
|
|
1228
1316
|
`hap-sign-tool failed. Ensure a JDK (with keytool/java) is on PATH. Underlying error: ${e.message}`,
|
|
@@ -1231,7 +1319,7 @@ function generateP7bFile(projectDir, paths, logger, passwords) {
|
|
|
1231
1319
|
}
|
|
1232
1320
|
}
|
|
1233
1321
|
function detectSigningConfigNames(projectDir) {
|
|
1234
|
-
const buildProfilePath =
|
|
1322
|
+
const buildProfilePath = path13.join(projectDir, "build-profile.json5");
|
|
1235
1323
|
if (!fs12.existsSync(buildProfilePath)) return ["default"];
|
|
1236
1324
|
let parsed;
|
|
1237
1325
|
try {
|
|
@@ -1252,8 +1340,8 @@ function detectSigningConfigNames(projectDir) {
|
|
|
1252
1340
|
}
|
|
1253
1341
|
function updateBuildProfile(projectDir, kind, logger, passwords) {
|
|
1254
1342
|
logger.info("[sign] Writing signing configs into build-profile.json5...");
|
|
1255
|
-
const materialDir =
|
|
1256
|
-
const buildProfilePath =
|
|
1343
|
+
const materialDir = path13.join(projectDir, "signatures", "material");
|
|
1344
|
+
const buildProfilePath = path13.join(projectDir, "build-profile.json5");
|
|
1257
1345
|
const encryptedStorePassword = encryptPwd(passwords.store, materialDir);
|
|
1258
1346
|
const encryptedKeyPassword = encryptPwd(passwords.key, materialDir);
|
|
1259
1347
|
let buildProfile = { app: {} };
|
|
@@ -1284,7 +1372,7 @@ function updateBuildProfile(projectDir, kind, logger, passwords) {
|
|
|
1284
1372
|
}
|
|
1285
1373
|
function prepareMaterialDirectory(projectDir, logger) {
|
|
1286
1374
|
logger.info("[sign] Generating fresh signing material...");
|
|
1287
|
-
const materialDir =
|
|
1375
|
+
const materialDir = path13.join(projectDir, "signatures", "material");
|
|
1288
1376
|
if (fs12.existsSync(materialDir)) {
|
|
1289
1377
|
fs12.rmSync(materialDir, { recursive: true, force: true });
|
|
1290
1378
|
}
|
|
@@ -1309,15 +1397,15 @@ function generateSigningConfigs(options) {
|
|
|
1309
1397
|
"Could not detect project SDK version (compileSdkVersion missing in build-profile.json5)."
|
|
1310
1398
|
);
|
|
1311
1399
|
}
|
|
1312
|
-
const sdkPath =
|
|
1400
|
+
const sdkPath = path13.join(sdkHome, String(sdkVersion));
|
|
1313
1401
|
if (!fs12.existsSync(sdkPath)) {
|
|
1314
1402
|
throw new OniroError(`SDK path does not exist: ${sdkPath}`);
|
|
1315
1403
|
}
|
|
1316
1404
|
const paths = {
|
|
1317
|
-
signTool:
|
|
1318
|
-
keystore:
|
|
1319
|
-
profileCert:
|
|
1320
|
-
unsignedProfileTemplate:
|
|
1405
|
+
signTool: path13.join(sdkPath, "toolchains/lib/hap-sign-tool.jar"),
|
|
1406
|
+
keystore: path13.join(sdkPath, "toolchains/lib/OpenHarmony.p12"),
|
|
1407
|
+
profileCert: path13.join(sdkPath, "toolchains/lib/OpenHarmonyProfileRelease.pem"),
|
|
1408
|
+
unsignedProfileTemplate: path13.join(sdkPath, "toolchains/lib/UnsgnedReleasedProfileTemplate.json")
|
|
1321
1409
|
};
|
|
1322
1410
|
const kind = pickSigningKind(apl);
|
|
1323
1411
|
const passwords = options.passwords ?? DEFAULT_PASSWORDS;
|
|
@@ -1332,7 +1420,7 @@ function generateSigningConfigs(options) {
|
|
|
1332
1420
|
|
|
1333
1421
|
// src/emulator/install.ts
|
|
1334
1422
|
import * as fs13 from "fs";
|
|
1335
|
-
import * as
|
|
1423
|
+
import * as path14 from "path";
|
|
1336
1424
|
async function installEmulator(opts) {
|
|
1337
1425
|
const { config, progress, abortSignal } = opts;
|
|
1338
1426
|
const logger = opts.logger ?? noopLogger;
|
|
@@ -1342,18 +1430,18 @@ async function installEmulator(opts) {
|
|
|
1342
1430
|
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
1343
1431
|
config,
|
|
1344
1432
|
override: opts.tmpDir,
|
|
1345
|
-
installRoot:
|
|
1433
|
+
installRoot: path14.dirname(emulatorDir),
|
|
1346
1434
|
prefix: "oniro-emulator-",
|
|
1347
1435
|
logger
|
|
1348
1436
|
});
|
|
1349
|
-
const tmpZip =
|
|
1437
|
+
const tmpZip = path14.join(tmpDir, "oniro_emulator.zip");
|
|
1350
1438
|
try {
|
|
1351
1439
|
fs13.mkdirSync(emulatorDir, { recursive: true });
|
|
1352
1440
|
progress?.report({ message: "Downloading emulator...", increment: 0 });
|
|
1353
1441
|
await downloadFile({ url, dest: tmpZip, progress, abortSignal, start: 0, range: 50, what, tmpRoot });
|
|
1354
1442
|
progress?.report({ message: "Extracting emulator...", increment: 0 });
|
|
1355
1443
|
await extractZipWithProgress({ zipPath: tmpZip, dest: emulatorDir, progress, start: 50, range: 45, logger });
|
|
1356
|
-
const runSh =
|
|
1444
|
+
const runSh = path14.join(emulatorDir, "images", "run.sh");
|
|
1357
1445
|
if (fs13.existsSync(runSh)) {
|
|
1358
1446
|
fs13.chmodSync(runSh, 493);
|
|
1359
1447
|
}
|
|
@@ -1365,8 +1453,8 @@ async function installEmulator(opts) {
|
|
|
1365
1453
|
}
|
|
1366
1454
|
}
|
|
1367
1455
|
function isEmulatorInstalled(config) {
|
|
1368
|
-
const imagesDir =
|
|
1369
|
-
return fs13.existsSync(
|
|
1456
|
+
const imagesDir = path14.join(getEmulatorDir(config), "images");
|
|
1457
|
+
return fs13.existsSync(path14.join(imagesDir, "run.sh")) || fs13.existsSync(path14.join(imagesDir, "run.bat"));
|
|
1370
1458
|
}
|
|
1371
1459
|
function removeEmulator(config) {
|
|
1372
1460
|
const emulatorDir = getEmulatorDir(config);
|
|
@@ -1376,13 +1464,16 @@ function removeEmulator(config) {
|
|
|
1376
1464
|
}
|
|
1377
1465
|
|
|
1378
1466
|
// src/emulator/lifecycle.ts
|
|
1379
|
-
import * as
|
|
1467
|
+
import * as fs15 from "fs";
|
|
1380
1468
|
import * as os7 from "os";
|
|
1381
|
-
import * as
|
|
1469
|
+
import * as path15 from "path";
|
|
1382
1470
|
import { spawn as spawn2 } from "child_process";
|
|
1383
1471
|
|
|
1384
1472
|
// src/hdc/exec.ts
|
|
1385
|
-
import
|
|
1473
|
+
import * as fs14 from "fs";
|
|
1474
|
+
function errorMessage(err) {
|
|
1475
|
+
return err instanceof Error ? err.message : String(err);
|
|
1476
|
+
}
|
|
1386
1477
|
function runProcess(opts) {
|
|
1387
1478
|
const { command, args, cwd, env, onOutput } = opts;
|
|
1388
1479
|
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
@@ -1392,7 +1483,17 @@ function runProcess(opts) {
|
|
|
1392
1483
|
reject(new CancelledError(`Command aborted before start: ${command}`));
|
|
1393
1484
|
return;
|
|
1394
1485
|
}
|
|
1395
|
-
|
|
1486
|
+
if (needsCmdWrapper(command) && !fs14.existsSync(command)) {
|
|
1487
|
+
reject(new OniroError(`Failed to spawn ${command}: ENOENT (no such file)`));
|
|
1488
|
+
return;
|
|
1489
|
+
}
|
|
1490
|
+
let child;
|
|
1491
|
+
try {
|
|
1492
|
+
child = spawnCompat(command, args, { cwd, env });
|
|
1493
|
+
} catch (err) {
|
|
1494
|
+
reject(new OniroError(`Failed to spawn ${command}: ${errorMessage(err)}`, err));
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1396
1497
|
let stdout = "";
|
|
1397
1498
|
let stderr = "";
|
|
1398
1499
|
let settled = false;
|
|
@@ -1405,26 +1506,20 @@ function runProcess(opts) {
|
|
|
1405
1506
|
if (settled) return;
|
|
1406
1507
|
settled = true;
|
|
1407
1508
|
cleanup();
|
|
1408
|
-
|
|
1409
|
-
child.kill("SIGKILL");
|
|
1410
|
-
} catch {
|
|
1411
|
-
}
|
|
1509
|
+
killProcessTree(child);
|
|
1412
1510
|
reject(new CancelledError(`Command aborted: ${command} ${args.join(" ")}`));
|
|
1413
1511
|
};
|
|
1414
1512
|
const timer = setTimeout(() => {
|
|
1415
1513
|
timedOut = true;
|
|
1416
|
-
|
|
1417
|
-
child.kill("SIGKILL");
|
|
1418
|
-
} catch {
|
|
1419
|
-
}
|
|
1514
|
+
killProcessTree(child);
|
|
1420
1515
|
}, timeoutMs);
|
|
1421
1516
|
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
1422
|
-
child.stdout
|
|
1517
|
+
child.stdout?.on("data", (d) => {
|
|
1423
1518
|
const s = d.toString();
|
|
1424
1519
|
stdout += s;
|
|
1425
1520
|
onOutput?.(s, "stdout");
|
|
1426
1521
|
});
|
|
1427
|
-
child.stderr
|
|
1522
|
+
child.stderr?.on("data", (d) => {
|
|
1428
1523
|
const s = d.toString();
|
|
1429
1524
|
stderr += s;
|
|
1430
1525
|
onOutput?.(s, "stderr");
|
|
@@ -1496,7 +1591,7 @@ function ensureRemoteOk(result, command) {
|
|
|
1496
1591
|
}
|
|
1497
1592
|
|
|
1498
1593
|
// src/emulator/lifecycle.ts
|
|
1499
|
-
var PID_FILE =
|
|
1594
|
+
var PID_FILE = path15.join(os7.tmpdir(), "oniro_emulator.pid");
|
|
1500
1595
|
async function attemptHdcConnection(config, address = "127.0.0.1:55555", logger = noopLogger) {
|
|
1501
1596
|
try {
|
|
1502
1597
|
await hdcExec({ config, args: ["start", "-r"], logger });
|
|
@@ -1509,24 +1604,24 @@ async function attemptHdcConnection(config, address = "127.0.0.1:55555", logger
|
|
|
1509
1604
|
}
|
|
1510
1605
|
}
|
|
1511
1606
|
function resolveLauncher(imagesPath, headless, connect) {
|
|
1512
|
-
const runSh =
|
|
1513
|
-
const runBat =
|
|
1607
|
+
const runSh = path15.join(imagesPath, "run.sh");
|
|
1608
|
+
const runBat = path15.join(imagesPath, "run.bat");
|
|
1514
1609
|
const extra = [];
|
|
1515
1610
|
if (headless) extra.push("--headless");
|
|
1516
1611
|
if (connect) extra.push("--connect", connect);
|
|
1517
1612
|
if (os7.platform() === "win32") {
|
|
1518
|
-
if (
|
|
1613
|
+
if (fs15.existsSync(runBat)) {
|
|
1519
1614
|
return { command: "cmd.exe", args: ["/c", runBat, ...extra], cwd: imagesPath };
|
|
1520
1615
|
}
|
|
1521
|
-
if (
|
|
1616
|
+
if (fs15.existsSync(runSh)) {
|
|
1522
1617
|
return { command: "bash", args: [runSh, ...extra], cwd: imagesPath };
|
|
1523
1618
|
}
|
|
1524
1619
|
throw new OniroError(`No emulator launcher (run.bat or run.sh) found in ${imagesPath}.`);
|
|
1525
1620
|
}
|
|
1526
|
-
if (
|
|
1621
|
+
if (fs15.existsSync(runSh)) {
|
|
1527
1622
|
return { command: "bash", args: [runSh, ...extra], cwd: imagesPath };
|
|
1528
1623
|
}
|
|
1529
|
-
if (
|
|
1624
|
+
if (fs15.existsSync(runBat)) {
|
|
1530
1625
|
return { command: "bash", args: [runBat, ...extra], cwd: imagesPath };
|
|
1531
1626
|
}
|
|
1532
1627
|
throw new OniroError(`No emulator launcher (run.sh or run.bat) found in ${imagesPath}.`);
|
|
@@ -1534,9 +1629,9 @@ function resolveLauncher(imagesPath, headless, connect) {
|
|
|
1534
1629
|
async function startEmulator(opts) {
|
|
1535
1630
|
const { config } = opts;
|
|
1536
1631
|
const logger = opts.logger ?? noopLogger;
|
|
1537
|
-
if (os7.platform() !== "win32" &&
|
|
1632
|
+
if (os7.platform() !== "win32" && fs15.existsSync(PID_FILE)) {
|
|
1538
1633
|
try {
|
|
1539
|
-
const pid = Number(
|
|
1634
|
+
const pid = Number(fs15.readFileSync(PID_FILE, "utf8").trim());
|
|
1540
1635
|
if (Number.isFinite(pid) && pid > 0) {
|
|
1541
1636
|
try {
|
|
1542
1637
|
process.kill(pid, 0);
|
|
@@ -1552,13 +1647,13 @@ async function startEmulator(opts) {
|
|
|
1552
1647
|
logger.warn(`Could not read PID file: ${err.message}`);
|
|
1553
1648
|
}
|
|
1554
1649
|
}
|
|
1555
|
-
const imagesPath =
|
|
1556
|
-
if (!
|
|
1650
|
+
const imagesPath = path15.join(getEmulatorDir(config), "images");
|
|
1651
|
+
if (!fs15.existsSync(imagesPath)) {
|
|
1557
1652
|
throw new OniroError(`Emulator images directory not found at ${imagesPath}. Run \`oniro-app emulator install\` first.`);
|
|
1558
1653
|
}
|
|
1559
1654
|
const launcher = resolveLauncher(imagesPath, opts.headless === true, opts.connect);
|
|
1560
1655
|
const logPath = opts.logFile ?? (os7.platform() === "win32" ? "NUL" : "/dev/null");
|
|
1561
|
-
const logFd =
|
|
1656
|
+
const logFd = fs15.openSync(logPath, "a");
|
|
1562
1657
|
let child;
|
|
1563
1658
|
try {
|
|
1564
1659
|
child = spawn2(launcher.command, [...launcher.args], {
|
|
@@ -1568,12 +1663,12 @@ async function startEmulator(opts) {
|
|
|
1568
1663
|
windowsHide: true
|
|
1569
1664
|
});
|
|
1570
1665
|
} finally {
|
|
1571
|
-
|
|
1666
|
+
fs15.closeSync(logFd);
|
|
1572
1667
|
}
|
|
1573
1668
|
if (!child.pid) {
|
|
1574
1669
|
throw new OniroError(`Failed to spawn launcher (${launcher.command} ${launcher.args.join(" ")}).`);
|
|
1575
1670
|
}
|
|
1576
|
-
|
|
1671
|
+
fs15.writeFileSync(PID_FILE, String(child.pid));
|
|
1577
1672
|
child.unref();
|
|
1578
1673
|
logger.info(`Emulator launched (PID ${child.pid}). Logs: ${logPath}`);
|
|
1579
1674
|
const earlyExit = new Promise((resolve4) => {
|
|
@@ -1620,24 +1715,24 @@ ${tail}` : ""}`);
|
|
|
1620
1715
|
}
|
|
1621
1716
|
function readTail(filePath, bytes) {
|
|
1622
1717
|
try {
|
|
1623
|
-
const stat =
|
|
1718
|
+
const stat = fs15.statSync(filePath);
|
|
1624
1719
|
const start = Math.max(0, stat.size - bytes);
|
|
1625
|
-
const fd =
|
|
1720
|
+
const fd = fs15.openSync(filePath, "r");
|
|
1626
1721
|
try {
|
|
1627
1722
|
const buf = Buffer.alloc(stat.size - start);
|
|
1628
|
-
|
|
1723
|
+
fs15.readSync(fd, buf, 0, buf.length, start);
|
|
1629
1724
|
return buf.toString("utf8");
|
|
1630
1725
|
} finally {
|
|
1631
|
-
|
|
1726
|
+
fs15.closeSync(fd);
|
|
1632
1727
|
}
|
|
1633
1728
|
} catch {
|
|
1634
1729
|
return "";
|
|
1635
1730
|
}
|
|
1636
1731
|
}
|
|
1637
1732
|
async function stopEmulator(logger = noopLogger) {
|
|
1638
|
-
if (
|
|
1733
|
+
if (fs15.existsSync(PID_FILE)) {
|
|
1639
1734
|
try {
|
|
1640
|
-
const pid = Number(
|
|
1735
|
+
const pid = Number(fs15.readFileSync(PID_FILE, "utf8").trim());
|
|
1641
1736
|
if (Number.isFinite(pid) && pid > 0) {
|
|
1642
1737
|
try {
|
|
1643
1738
|
process.kill(pid, "SIGTERM");
|
|
@@ -1656,7 +1751,7 @@ async function stopEmulator(logger = noopLogger) {
|
|
|
1656
1751
|
} catch (err) {
|
|
1657
1752
|
logger.warn(`[emulator] could not run ${killCmd}: ${err.message}`);
|
|
1658
1753
|
}
|
|
1659
|
-
|
|
1754
|
+
fs15.rm(PID_FILE, { force: true }, (err) => {
|
|
1660
1755
|
if (err) logger.warn(`Could not remove PID file: ${err.message}`);
|
|
1661
1756
|
});
|
|
1662
1757
|
}
|
|
@@ -1823,21 +1918,20 @@ async function waitForCondition(opts) {
|
|
|
1823
1918
|
}
|
|
1824
1919
|
|
|
1825
1920
|
// src/hdc/app.ts
|
|
1826
|
-
import * as
|
|
1827
|
-
import * as
|
|
1828
|
-
import { spawn as spawn3 } from "child_process";
|
|
1921
|
+
import * as fs17 from "fs";
|
|
1922
|
+
import * as path17 from "path";
|
|
1829
1923
|
|
|
1830
1924
|
// src/hdc/project.ts
|
|
1831
|
-
import * as
|
|
1832
|
-
import * as
|
|
1925
|
+
import * as fs16 from "fs";
|
|
1926
|
+
import * as path16 from "path";
|
|
1833
1927
|
import JSON53 from "json5";
|
|
1834
1928
|
function readJson5(filePath) {
|
|
1835
|
-
const content =
|
|
1929
|
+
const content = fs16.readFileSync(filePath, "utf-8");
|
|
1836
1930
|
return JSON53.parse(content);
|
|
1837
1931
|
}
|
|
1838
1932
|
function getBundleName(projectDir) {
|
|
1839
|
-
const appJsonPath =
|
|
1840
|
-
if (!
|
|
1933
|
+
const appJsonPath = path16.join(projectDir, "AppScope", "app.json5");
|
|
1934
|
+
if (!fs16.existsSync(appJsonPath)) {
|
|
1841
1935
|
throw new OniroError(`Could not find app.json5 at ${appJsonPath}`);
|
|
1842
1936
|
}
|
|
1843
1937
|
const appJson = readJson5(appJsonPath);
|
|
@@ -1847,8 +1941,8 @@ function getBundleName(projectDir) {
|
|
|
1847
1941
|
return appJson.app.bundleName;
|
|
1848
1942
|
}
|
|
1849
1943
|
function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
1850
|
-
const moduleJsonPath =
|
|
1851
|
-
if (!
|
|
1944
|
+
const moduleJsonPath = path16.join(projectDir, moduleName, "src", "main", "module.json5");
|
|
1945
|
+
if (!fs16.existsSync(moduleJsonPath)) {
|
|
1852
1946
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
1853
1947
|
}
|
|
1854
1948
|
const moduleJson = readJson5(moduleJsonPath);
|
|
@@ -1871,11 +1965,16 @@ function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
|
1871
1965
|
async function installApp(opts) {
|
|
1872
1966
|
const logger = scopedLogger(opts.logger ?? noopLogger, "hdc");
|
|
1873
1967
|
const relativeHapPath = opts.hapPath ?? opts.config.get("hapPath", defaultPaths.hapPath);
|
|
1874
|
-
const hapPath =
|
|
1875
|
-
if (!
|
|
1968
|
+
const hapPath = path17.isAbsolute(relativeHapPath) ? relativeHapPath : path17.join(opts.projectDir, relativeHapPath);
|
|
1969
|
+
if (!fs17.existsSync(hapPath)) {
|
|
1876
1970
|
throw new OniroError(`HAP file not found at: ${hapPath}. Build and sign the app first.`);
|
|
1877
1971
|
}
|
|
1878
|
-
const result = await hdcExec({
|
|
1972
|
+
const result = await hdcExec({
|
|
1973
|
+
config: opts.config,
|
|
1974
|
+
args: ["install", hapPath],
|
|
1975
|
+
deviceSerial: opts.deviceSerial,
|
|
1976
|
+
timeoutMs: 3e5
|
|
1977
|
+
});
|
|
1879
1978
|
if (result.stdout.trim()) logger.info(result.stdout.trim());
|
|
1880
1979
|
if (result.stderr.trim()) logger.warn(result.stderr.trim());
|
|
1881
1980
|
ensureOk(result, `hdc install ${hapPath}`);
|
|
@@ -1957,11 +2056,17 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1957
2056
|
const timeoutMs = options.timeoutMs ?? 1e3;
|
|
1958
2057
|
const hdc = getHdcPath(config);
|
|
1959
2058
|
return new Promise((resolve4, reject) => {
|
|
1960
|
-
|
|
2059
|
+
let proc;
|
|
2060
|
+
try {
|
|
2061
|
+
proc = spawnCompat(hdc, ["track-jpid"]);
|
|
2062
|
+
} catch (err) {
|
|
2063
|
+
reject(new OniroError(`Failed to spawn ${hdc}: ${err instanceof Error ? err.message : String(err)}`, err));
|
|
2064
|
+
return;
|
|
2065
|
+
}
|
|
1961
2066
|
const processes = [];
|
|
1962
2067
|
let resolved = false;
|
|
1963
|
-
proc.stdout
|
|
1964
|
-
for (const line of data.toString().split(
|
|
2068
|
+
proc.stdout?.on("data", (data) => {
|
|
2069
|
+
for (const line of data.toString().split(/\r?\n/).filter(Boolean)) {
|
|
1965
2070
|
const match = line.match(/^(\d+)\s+(.+)$/);
|
|
1966
2071
|
if (!match) continue;
|
|
1967
2072
|
const pid = match[1];
|
|
@@ -1969,13 +2074,13 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1969
2074
|
processes.push({ pid, name });
|
|
1970
2075
|
if (options.targetProcessName && name === options.targetProcessName && !resolved) {
|
|
1971
2076
|
resolved = true;
|
|
1972
|
-
proc
|
|
2077
|
+
killProcessTree(proc);
|
|
1973
2078
|
resolve4(pid);
|
|
1974
2079
|
return;
|
|
1975
2080
|
}
|
|
1976
2081
|
}
|
|
1977
2082
|
});
|
|
1978
|
-
proc.stderr
|
|
2083
|
+
proc.stderr?.on("data", (data) => {
|
|
1979
2084
|
logger.warn(`[hdc track-jpid] ${data.toString()}`);
|
|
1980
2085
|
});
|
|
1981
2086
|
proc.on("error", (err) => {
|
|
@@ -1987,7 +2092,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1987
2092
|
const timeout = setTimeout(() => {
|
|
1988
2093
|
if (resolved) return;
|
|
1989
2094
|
resolved = true;
|
|
1990
|
-
proc
|
|
2095
|
+
killProcessTree(proc);
|
|
1991
2096
|
if (options.targetProcessName) {
|
|
1992
2097
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
1993
2098
|
} else {
|
|
@@ -2145,12 +2250,12 @@ async function reboot(opts) {
|
|
|
2145
2250
|
}
|
|
2146
2251
|
|
|
2147
2252
|
// src/hdc/screen.ts
|
|
2148
|
-
import * as
|
|
2253
|
+
import * as fs18 from "fs";
|
|
2149
2254
|
import * as os8 from "os";
|
|
2150
|
-
import * as
|
|
2255
|
+
import * as path18 from "path";
|
|
2151
2256
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
2152
2257
|
function tmpName(ext) {
|
|
2153
|
-
return
|
|
2258
|
+
return path18.join(os8.tmpdir(), `oniro_screen_${randomBytes2(6).toString("hex")}.${ext}`);
|
|
2154
2259
|
}
|
|
2155
2260
|
async function takeScreenshot(opts) {
|
|
2156
2261
|
const remote = "/data/local/tmp/oniro_screenshot.jpeg";
|
|
@@ -2160,11 +2265,11 @@ async function takeScreenshot(opts) {
|
|
|
2160
2265
|
const local = tmpName("jpeg");
|
|
2161
2266
|
try {
|
|
2162
2267
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
2163
|
-
const pixels = await
|
|
2268
|
+
const pixels = await fs18.promises.readFile(local);
|
|
2164
2269
|
const size = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial }) ?? { width: 0, height: 0 };
|
|
2165
2270
|
return { pixels, width: size.width, height: size.height };
|
|
2166
2271
|
} finally {
|
|
2167
|
-
|
|
2272
|
+
fs18.promises.unlink(local).catch(() => {
|
|
2168
2273
|
});
|
|
2169
2274
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
2170
2275
|
});
|
|
@@ -2183,9 +2288,9 @@ async function captureBurst(opts) {
|
|
|
2183
2288
|
const local = tmpName(`burst_${i}.jpeg`);
|
|
2184
2289
|
try {
|
|
2185
2290
|
await recvFile({ config: opts.config, remote: `${remoteDir}/f${i}.jpeg`, local, deviceSerial: opts.deviceSerial });
|
|
2186
|
-
frames.push(await
|
|
2291
|
+
frames.push(await fs18.promises.readFile(local));
|
|
2187
2292
|
} finally {
|
|
2188
|
-
|
|
2293
|
+
fs18.promises.unlink(local).catch(() => {
|
|
2189
2294
|
});
|
|
2190
2295
|
}
|
|
2191
2296
|
}
|
|
@@ -2311,9 +2416,9 @@ async function sendRawTouch(opts) {
|
|
|
2311
2416
|
}
|
|
2312
2417
|
|
|
2313
2418
|
// src/hdc/dump.ts
|
|
2314
|
-
import * as
|
|
2419
|
+
import * as fs19 from "fs";
|
|
2315
2420
|
import * as os9 from "os";
|
|
2316
|
-
import * as
|
|
2421
|
+
import * as path19 from "path";
|
|
2317
2422
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
2318
2423
|
function parseBounds(s) {
|
|
2319
2424
|
const m = /^\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]$/.exec(s ?? "");
|
|
@@ -2398,10 +2503,10 @@ async function dumpLayout(opts) {
|
|
|
2398
2503
|
if (!m) throw new OniroError(`Could not parse dumpLayout output:
|
|
2399
2504
|
${dump.stdout}`);
|
|
2400
2505
|
const remote = m[1];
|
|
2401
|
-
const local =
|
|
2506
|
+
const local = path19.join(os9.tmpdir(), `oniro_layout_${randomBytes3(6).toString("hex")}.json`);
|
|
2402
2507
|
try {
|
|
2403
2508
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
2404
|
-
const parsed = JSON.parse(await
|
|
2509
|
+
const parsed = JSON.parse(await fs19.promises.readFile(local, "utf8"));
|
|
2405
2510
|
const display = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial });
|
|
2406
2511
|
if (opts.prune === false) {
|
|
2407
2512
|
return { display, tree: parsed };
|
|
@@ -2410,7 +2515,7 @@ ${dump.stdout}`);
|
|
|
2410
2515
|
const tree = Array.isArray(prunedRaw) ? { children: prunedRaw } : prunedRaw ?? { children: [] };
|
|
2411
2516
|
return { display, tree };
|
|
2412
2517
|
} finally {
|
|
2413
|
-
|
|
2518
|
+
fs19.promises.unlink(local).catch(() => {
|
|
2414
2519
|
});
|
|
2415
2520
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
2416
2521
|
});
|
|
@@ -2418,14 +2523,21 @@ ${dump.stdout}`);
|
|
|
2418
2523
|
}
|
|
2419
2524
|
|
|
2420
2525
|
// src/hdc/hilog.ts
|
|
2421
|
-
import { spawn as spawn4 } from "child_process";
|
|
2422
2526
|
function setHilogLevel(opts) {
|
|
2423
2527
|
const logger = opts.logger ?? noopLogger;
|
|
2424
2528
|
const hdc = getHdcPath(opts.config);
|
|
2425
2529
|
return new Promise((resolve4, reject) => {
|
|
2426
|
-
|
|
2530
|
+
let child;
|
|
2531
|
+
try {
|
|
2532
|
+
child = spawnCompat(hdc, ["shell", "hilog", "-b", opts.level]);
|
|
2533
|
+
} catch (err) {
|
|
2534
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2535
|
+
logger.error(`[hilog] failed to spawn hdc: ${msg}`);
|
|
2536
|
+
reject(err instanceof Error ? err : new Error(msg));
|
|
2537
|
+
return;
|
|
2538
|
+
}
|
|
2427
2539
|
let stderr = "";
|
|
2428
|
-
child.stderr
|
|
2540
|
+
child.stderr?.on("data", (chunk) => {
|
|
2429
2541
|
stderr += chunk.toString();
|
|
2430
2542
|
});
|
|
2431
2543
|
child.once("error", (err) => {
|
|
@@ -2454,7 +2566,7 @@ function streamHilog(opts) {
|
|
|
2454
2566
|
if (opts.domain !== void 0 && `${opts.domain}` !== "") {
|
|
2455
2567
|
args.push("-D", `${opts.domain}`);
|
|
2456
2568
|
}
|
|
2457
|
-
return
|
|
2569
|
+
return spawnCompat(hdc, args);
|
|
2458
2570
|
}
|
|
2459
2571
|
var HILOG_LINE_RE = /^(\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\s+(\d+)\s+(\d+)\s+([DIWEF])\s+(\S+):\s+(.*)$/;
|
|
2460
2572
|
function parseHilogLine(line) {
|
|
@@ -2500,10 +2612,7 @@ function waitForLog(opts) {
|
|
|
2500
2612
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
2501
2613
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
2502
2614
|
if (child) {
|
|
2503
|
-
|
|
2504
|
-
child.kill("SIGKILL");
|
|
2505
|
-
} catch {
|
|
2506
|
-
}
|
|
2615
|
+
killProcessTree(child);
|
|
2507
2616
|
child = null;
|
|
2508
2617
|
}
|
|
2509
2618
|
};
|
|
@@ -2519,6 +2628,7 @@ function waitForLog(opts) {
|
|
|
2519
2628
|
cleanup();
|
|
2520
2629
|
reject(err);
|
|
2521
2630
|
};
|
|
2631
|
+
const failWith = (err) => fail(err instanceof Error ? err : new Error(String(err)));
|
|
2522
2632
|
const onAbort = () => fail(new CancelledError("waitForLog cancelled."));
|
|
2523
2633
|
const timer = setTimeout(
|
|
2524
2634
|
() => fail(new OniroError(`No log line matched ${String(opts.pattern)} within ${opts.timeoutMs}ms.`)),
|
|
@@ -2533,10 +2643,9 @@ function waitForLog(opts) {
|
|
|
2533
2643
|
child = stream;
|
|
2534
2644
|
stream.stdout.on("data", (d) => {
|
|
2535
2645
|
buf += d.toString();
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
buf = buf.slice(idx + 1);
|
|
2646
|
+
const lines = buf.split(/\r?\n/);
|
|
2647
|
+
buf = lines.pop() ?? "";
|
|
2648
|
+
for (const line of lines) {
|
|
2540
2649
|
const entry = parseHilogLine(line);
|
|
2541
2650
|
if (entry && opts.pattern.test(entryText(entry))) {
|
|
2542
2651
|
finish(entry);
|
|
@@ -2548,13 +2657,13 @@ function waitForLog(opts) {
|
|
|
2548
2657
|
if (settled || child !== stream) return;
|
|
2549
2658
|
child = null;
|
|
2550
2659
|
if (Date.now() < deadline) {
|
|
2551
|
-
reconnectTimer = setTimeout(() => void spawnStream(), 1e3);
|
|
2660
|
+
reconnectTimer = setTimeout(() => void spawnStream().catch(failWith), 1e3);
|
|
2552
2661
|
}
|
|
2553
2662
|
};
|
|
2554
2663
|
stream.once("close", onEnd);
|
|
2555
2664
|
stream.once("error", onEnd);
|
|
2556
2665
|
};
|
|
2557
|
-
void spawnStream();
|
|
2666
|
+
void spawnStream().catch(failWith);
|
|
2558
2667
|
});
|
|
2559
2668
|
}
|
|
2560
2669
|
function watchLog(opts) {
|
|
@@ -2567,10 +2676,7 @@ function watchLog(opts) {
|
|
|
2567
2676
|
clearTimeout(timer);
|
|
2568
2677
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
2569
2678
|
if (child) {
|
|
2570
|
-
|
|
2571
|
-
child.kill("SIGKILL");
|
|
2572
|
-
} catch {
|
|
2573
|
-
}
|
|
2679
|
+
killProcessTree(child);
|
|
2574
2680
|
child = null;
|
|
2575
2681
|
}
|
|
2576
2682
|
};
|
|
@@ -2595,15 +2701,19 @@ function watchLog(opts) {
|
|
|
2595
2701
|
child = stream;
|
|
2596
2702
|
stream.stdout.on("data", (d) => {
|
|
2597
2703
|
buf += d.toString();
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
buf = buf.slice(idx + 1);
|
|
2704
|
+
const lines = buf.split(/\r?\n/);
|
|
2705
|
+
buf = lines.pop() ?? "";
|
|
2706
|
+
for (const line of lines) {
|
|
2602
2707
|
const entry = parseHilogLine(line);
|
|
2603
2708
|
if (entry && opts.pattern.test(entryText(entry))) matches.push(entry);
|
|
2604
2709
|
}
|
|
2605
2710
|
});
|
|
2606
|
-
})()
|
|
2711
|
+
})().catch((err) => {
|
|
2712
|
+
if (settled) return;
|
|
2713
|
+
settled = true;
|
|
2714
|
+
cleanup();
|
|
2715
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
2716
|
+
});
|
|
2607
2717
|
});
|
|
2608
2718
|
}
|
|
2609
2719
|
async function dumpLog(opts) {
|
|
@@ -2626,13 +2736,12 @@ async function dumpLog(opts) {
|
|
|
2626
2736
|
timeoutMs: opts.timeoutMs ?? 3e4,
|
|
2627
2737
|
logger: opts.logger
|
|
2628
2738
|
});
|
|
2629
|
-
return res.stdout.split(
|
|
2739
|
+
return res.stdout.split(/\r?\n/).map((line) => parseHilogLine(line)).filter((e) => e !== null);
|
|
2630
2740
|
}
|
|
2631
2741
|
|
|
2632
2742
|
// src/build/runHvigorw.ts
|
|
2633
|
-
import * as
|
|
2634
|
-
import * as
|
|
2635
|
-
import { spawn as spawn5 } from "child_process";
|
|
2743
|
+
import * as fs20 from "fs";
|
|
2744
|
+
import * as path20 from "path";
|
|
2636
2745
|
function buildHvigorwArgs(opts) {
|
|
2637
2746
|
const args = [opts.task ?? "assembleHap", "--mode", "module"];
|
|
2638
2747
|
args.push("-p", `product=${opts.product ?? "default"}`);
|
|
@@ -2644,19 +2753,23 @@ function buildHvigorwArgs(opts) {
|
|
|
2644
2753
|
return args;
|
|
2645
2754
|
}
|
|
2646
2755
|
function runHvigorw(opts) {
|
|
2647
|
-
const { config
|
|
2756
|
+
const { config } = opts;
|
|
2757
|
+
const projectDir = toLongPath(opts.projectDir);
|
|
2648
2758
|
const logger = opts.logger ?? noopLogger;
|
|
2649
|
-
if (!
|
|
2759
|
+
if (!fs20.existsSync(path20.join(projectDir, "build-profile.json5"))) {
|
|
2650
2760
|
throw new OniroError(`Not an OpenHarmony project: ${projectDir} (build-profile.json5 not found).`);
|
|
2651
2761
|
}
|
|
2652
|
-
if (!
|
|
2762
|
+
if (!fs20.existsSync(getCmdToolsPath(config))) {
|
|
2653
2763
|
throw new CmdToolsNotInstalledError(getCmdToolsPath(config));
|
|
2654
2764
|
}
|
|
2655
2765
|
const hvigorw = getHvigorwPath(config, projectDir);
|
|
2766
|
+
if (!fs20.existsSync(hvigorw)) {
|
|
2767
|
+
throw new OniroError(`hvigorw wrapper not found at ${hvigorw}.`);
|
|
2768
|
+
}
|
|
2656
2769
|
const args = buildHvigorwArgs(opts);
|
|
2657
2770
|
if (process.platform !== "win32") {
|
|
2658
2771
|
try {
|
|
2659
|
-
|
|
2772
|
+
fs20.chmodSync(hvigorw, 493);
|
|
2660
2773
|
} catch {
|
|
2661
2774
|
}
|
|
2662
2775
|
}
|
|
@@ -2670,26 +2783,29 @@ function runHvigorw(opts) {
|
|
|
2670
2783
|
return;
|
|
2671
2784
|
}
|
|
2672
2785
|
logger.info(`[build] ${hvigorw} ${args.join(" ")}`);
|
|
2673
|
-
|
|
2786
|
+
let child;
|
|
2787
|
+
try {
|
|
2788
|
+
child = spawnCompat(hvigorw, args, { cwd: projectDir, env });
|
|
2789
|
+
} catch (err) {
|
|
2790
|
+
reject(new OniroError(`Failed to start hvigorw: ${err instanceof Error ? err.message : String(err)}`, err));
|
|
2791
|
+
return;
|
|
2792
|
+
}
|
|
2674
2793
|
let settled = false;
|
|
2675
2794
|
const cleanup = () => opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
2676
2795
|
const onAbort = () => {
|
|
2677
2796
|
if (settled) return;
|
|
2678
2797
|
settled = true;
|
|
2679
2798
|
cleanup();
|
|
2680
|
-
|
|
2681
|
-
child.kill("SIGKILL");
|
|
2682
|
-
} catch {
|
|
2683
|
-
}
|
|
2799
|
+
killProcessTree(child);
|
|
2684
2800
|
reject(new CancelledError("hvigorw build cancelled."));
|
|
2685
2801
|
};
|
|
2686
2802
|
opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
2687
|
-
child.stdout
|
|
2803
|
+
child.stdout?.on("data", (chunk) => {
|
|
2688
2804
|
const text = chunk.toString();
|
|
2689
2805
|
opts.onOutput?.(text, "stdout");
|
|
2690
2806
|
logger.info(text.trimEnd());
|
|
2691
2807
|
});
|
|
2692
|
-
child.stderr
|
|
2808
|
+
child.stderr?.on("data", (chunk) => {
|
|
2693
2809
|
const text = chunk.toString();
|
|
2694
2810
|
opts.onOutput?.(text, "stderr");
|
|
2695
2811
|
logger.warn(text.trimEnd());
|
|
@@ -2712,8 +2828,8 @@ function runHvigorw(opts) {
|
|
|
2712
2828
|
}
|
|
2713
2829
|
|
|
2714
2830
|
// src/build/discoverHaps.ts
|
|
2715
|
-
import * as
|
|
2716
|
-
import * as
|
|
2831
|
+
import * as fs21 from "fs";
|
|
2832
|
+
import * as path21 from "path";
|
|
2717
2833
|
function moduleOfHap(hapFileName) {
|
|
2718
2834
|
const dash = hapFileName.indexOf("-");
|
|
2719
2835
|
return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
|
|
@@ -2724,9 +2840,9 @@ async function discoverHaps(opts) {
|
|
|
2724
2840
|
const result = {};
|
|
2725
2841
|
const walk = async (dir, depth) => {
|
|
2726
2842
|
if (depth > maxDepth) return;
|
|
2727
|
-
const entries = await
|
|
2843
|
+
const entries = await fs21.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
2728
2844
|
for (const e of entries) {
|
|
2729
|
-
const full =
|
|
2845
|
+
const full = path21.join(dir, e.name);
|
|
2730
2846
|
if (e.isDirectory()) {
|
|
2731
2847
|
if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
|
|
2732
2848
|
await walk(full, depth + 1);
|
|
@@ -2743,8 +2859,8 @@ async function discoverHaps(opts) {
|
|
|
2743
2859
|
}
|
|
2744
2860
|
|
|
2745
2861
|
// src/build/ohpm.ts
|
|
2746
|
-
import * as
|
|
2747
|
-
import * as
|
|
2862
|
+
import * as fs22 from "fs";
|
|
2863
|
+
import * as path22 from "path";
|
|
2748
2864
|
function runOhpm(opts) {
|
|
2749
2865
|
return runProcess({
|
|
2750
2866
|
command: getOhpmPath(opts.config),
|
|
@@ -2757,7 +2873,7 @@ function runOhpm(opts) {
|
|
|
2757
2873
|
});
|
|
2758
2874
|
}
|
|
2759
2875
|
async function ensureOhModules(opts) {
|
|
2760
|
-
if (
|
|
2876
|
+
if (fs22.existsSync(path22.join(opts.projectDir, "oh_modules"))) {
|
|
2761
2877
|
return { installed: false };
|
|
2762
2878
|
}
|
|
2763
2879
|
const res = await runOhpm({
|
|
@@ -2809,10 +2925,11 @@ async function buildHap(opts) {
|
|
|
2809
2925
|
const logger = scopedLogger(opts.logger ?? noopLogger, "build");
|
|
2810
2926
|
const warnings = [];
|
|
2811
2927
|
const start = Date.now();
|
|
2928
|
+
const projectDir = toLongPath(opts.projectDir);
|
|
2812
2929
|
if (opts.autoInstallDeps !== false) {
|
|
2813
2930
|
const r = await ensureOhModules({
|
|
2814
2931
|
config: opts.config,
|
|
2815
|
-
projectDir
|
|
2932
|
+
projectDir,
|
|
2816
2933
|
abortSignal: opts.abortSignal,
|
|
2817
2934
|
onOutput: opts.onOutput,
|
|
2818
2935
|
logger: opts.logger
|
|
@@ -2821,7 +2938,7 @@ async function buildHap(opts) {
|
|
|
2821
2938
|
}
|
|
2822
2939
|
const { exitCode } = await runHvigorw({
|
|
2823
2940
|
config: opts.config,
|
|
2824
|
-
projectDir
|
|
2941
|
+
projectDir,
|
|
2825
2942
|
product: opts.product,
|
|
2826
2943
|
module: opts.module,
|
|
2827
2944
|
buildMode: opts.mode,
|
|
@@ -2831,7 +2948,7 @@ async function buildHap(opts) {
|
|
|
2831
2948
|
onOutput: opts.onOutput,
|
|
2832
2949
|
logger: opts.logger
|
|
2833
2950
|
});
|
|
2834
|
-
const discoveredHaps = await discoverHaps({ projectDir
|
|
2951
|
+
const discoveredHaps = await discoverHaps({ projectDir });
|
|
2835
2952
|
const anySigned = Object.values(discoveredHaps).some((m) => m.signed.length > 0);
|
|
2836
2953
|
if (!anySigned) {
|
|
2837
2954
|
warnings.push(
|
|
@@ -2852,21 +2969,21 @@ function isValidBundleName(bundleName) {
|
|
|
2852
2969
|
}
|
|
2853
2970
|
|
|
2854
2971
|
// src/project/templates.ts
|
|
2855
|
-
import * as
|
|
2856
|
-
import * as
|
|
2972
|
+
import * as fs23 from "fs";
|
|
2973
|
+
import * as path23 from "path";
|
|
2857
2974
|
function toHumanTemplateName(folderName) {
|
|
2858
2975
|
return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
2859
2976
|
}
|
|
2860
2977
|
function listTemplates(templateRoot) {
|
|
2861
|
-
if (!
|
|
2862
|
-
const entries =
|
|
2978
|
+
if (!fs23.existsSync(templateRoot)) return [];
|
|
2979
|
+
const entries = fs23.readdirSync(templateRoot, { withFileTypes: true });
|
|
2863
2980
|
return entries.filter((e) => e.isDirectory()).map((e) => {
|
|
2864
|
-
const dir =
|
|
2865
|
-
const metaPath =
|
|
2981
|
+
const dir = path23.join(templateRoot, e.name);
|
|
2982
|
+
const metaPath = path23.join(dir, "template.json");
|
|
2866
2983
|
let meta = {};
|
|
2867
|
-
if (
|
|
2984
|
+
if (fs23.existsSync(metaPath)) {
|
|
2868
2985
|
try {
|
|
2869
|
-
meta = JSON.parse(
|
|
2986
|
+
meta = JSON.parse(fs23.readFileSync(metaPath, "utf8"));
|
|
2870
2987
|
} catch {
|
|
2871
2988
|
}
|
|
2872
2989
|
}
|
|
@@ -2881,57 +2998,57 @@ function listTemplates(templateRoot) {
|
|
|
2881
2998
|
function validateTemplateLayout(templateDir, defaultModuleName) {
|
|
2882
2999
|
const required = [
|
|
2883
3000
|
"build-profile.json5",
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
3001
|
+
path23.join("AppScope", "app.json5"),
|
|
3002
|
+
path23.join(defaultModuleName, "src", "main", "module.json5"),
|
|
3003
|
+
path23.join(defaultModuleName, "oh-package.json5"),
|
|
2887
3004
|
"hvigorfile.ts"
|
|
2888
3005
|
];
|
|
2889
|
-
return required.filter((rel) => !
|
|
3006
|
+
return required.filter((rel) => !fs23.existsSync(path23.join(templateDir, rel)));
|
|
2890
3007
|
}
|
|
2891
3008
|
|
|
2892
3009
|
// src/project/createScaffold.ts
|
|
2893
|
-
import * as
|
|
2894
|
-
import * as
|
|
3010
|
+
import * as fs25 from "fs";
|
|
3011
|
+
import * as path24 from "path";
|
|
2895
3012
|
|
|
2896
3013
|
// src/project/jsonHelpers.ts
|
|
2897
|
-
import * as
|
|
3014
|
+
import * as fs24 from "fs";
|
|
2898
3015
|
import JSON54 from "json5";
|
|
2899
3016
|
function readJson5File(filePath) {
|
|
2900
|
-
return JSON54.parse(
|
|
3017
|
+
return JSON54.parse(fs24.readFileSync(filePath, "utf8"));
|
|
2901
3018
|
}
|
|
2902
3019
|
function writeJson5File(filePath, value) {
|
|
2903
|
-
|
|
3020
|
+
fs24.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
2904
3021
|
}
|
|
2905
3022
|
function readJsonFile(filePath) {
|
|
2906
|
-
return JSON.parse(
|
|
3023
|
+
return JSON.parse(fs24.readFileSync(filePath, "utf8"));
|
|
2907
3024
|
}
|
|
2908
3025
|
function writeJsonFile(filePath, value) {
|
|
2909
|
-
|
|
3026
|
+
fs24.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
2910
3027
|
}
|
|
2911
3028
|
|
|
2912
3029
|
// src/project/createScaffold.ts
|
|
2913
3030
|
var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
|
|
2914
3031
|
async function pathExists(p) {
|
|
2915
3032
|
try {
|
|
2916
|
-
await
|
|
3033
|
+
await fs25.promises.access(p);
|
|
2917
3034
|
return true;
|
|
2918
3035
|
} catch {
|
|
2919
3036
|
return false;
|
|
2920
3037
|
}
|
|
2921
3038
|
}
|
|
2922
3039
|
async function copyDirRecursive(srcDir, destDir) {
|
|
2923
|
-
await
|
|
2924
|
-
const entries = await
|
|
3040
|
+
await fs25.promises.mkdir(destDir, { recursive: true });
|
|
3041
|
+
const entries = await fs25.promises.readdir(srcDir, { withFileTypes: true });
|
|
2925
3042
|
for (const entry of entries) {
|
|
2926
|
-
const src =
|
|
2927
|
-
const dest =
|
|
3043
|
+
const src = path24.join(srcDir, entry.name);
|
|
3044
|
+
const dest = path24.join(destDir, entry.name);
|
|
2928
3045
|
if (entry.isDirectory()) {
|
|
2929
3046
|
await copyDirRecursive(src, dest);
|
|
2930
3047
|
} else if (entry.isSymbolicLink()) {
|
|
2931
3048
|
continue;
|
|
2932
3049
|
} else if (entry.isFile()) {
|
|
2933
3050
|
if (entry.name === "template.json") continue;
|
|
2934
|
-
await
|
|
3051
|
+
await fs25.promises.copyFile(src, dest);
|
|
2935
3052
|
}
|
|
2936
3053
|
}
|
|
2937
3054
|
}
|
|
@@ -2939,9 +3056,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
|
|
|
2939
3056
|
const stack = [projectDir];
|
|
2940
3057
|
while (stack.length > 0) {
|
|
2941
3058
|
const currentDir = stack.pop();
|
|
2942
|
-
const entries = await
|
|
3059
|
+
const entries = await fs25.promises.readdir(currentDir, { withFileTypes: true });
|
|
2943
3060
|
for (const entry of entries) {
|
|
2944
|
-
const fullPath =
|
|
3061
|
+
const fullPath = path24.join(currentDir, entry.name);
|
|
2945
3062
|
if (entry.isDirectory()) {
|
|
2946
3063
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
2947
3064
|
stack.push(fullPath);
|
|
@@ -2963,23 +3080,23 @@ function toJavaPropertiesPath(p) {
|
|
|
2963
3080
|
function createOrUpdateLocalProperties(projectDir, sdkDir) {
|
|
2964
3081
|
const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
|
|
2965
3082
|
`;
|
|
2966
|
-
|
|
3083
|
+
fs25.writeFileSync(path24.join(projectDir, "local.properties"), content, "utf8");
|
|
2967
3084
|
}
|
|
2968
3085
|
function renameIfExists(fromPath, toPath) {
|
|
2969
|
-
if (
|
|
2970
|
-
|
|
3086
|
+
if (fs25.existsSync(fromPath) && fromPath !== toPath) {
|
|
3087
|
+
fs25.renameSync(fromPath, toPath);
|
|
2971
3088
|
}
|
|
2972
3089
|
}
|
|
2973
3090
|
function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
2974
|
-
const appJsonPath =
|
|
2975
|
-
if (
|
|
3091
|
+
const appJsonPath = path24.join(projectDir, "AppScope", "app.json5");
|
|
3092
|
+
if (fs25.existsSync(appJsonPath)) {
|
|
2976
3093
|
const appJson = readJson5File(appJsonPath);
|
|
2977
3094
|
appJson.app = appJson.app ?? {};
|
|
2978
3095
|
appJson.app.bundleName = args.bundleName;
|
|
2979
3096
|
writeJson5File(appJsonPath, appJson);
|
|
2980
3097
|
}
|
|
2981
|
-
const stringsPath =
|
|
2982
|
-
if (
|
|
3098
|
+
const stringsPath = path24.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
|
|
3099
|
+
if (fs25.existsSync(stringsPath)) {
|
|
2983
3100
|
const strings = readJsonFile(stringsPath);
|
|
2984
3101
|
if (Array.isArray(strings.string)) {
|
|
2985
3102
|
const appName = strings.string.find((s) => s.name === "app_name");
|
|
@@ -2987,8 +3104,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
2987
3104
|
}
|
|
2988
3105
|
writeJsonFile(stringsPath, strings);
|
|
2989
3106
|
}
|
|
2990
|
-
const buildProfilePath =
|
|
2991
|
-
if (
|
|
3107
|
+
const buildProfilePath = path24.join(projectDir, "build-profile.json5");
|
|
3108
|
+
if (fs25.existsSync(buildProfilePath)) {
|
|
2992
3109
|
const buildProfile = readJson5File(buildProfilePath);
|
|
2993
3110
|
buildProfile.app = buildProfile.app ?? {};
|
|
2994
3111
|
if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
|
|
@@ -3001,23 +3118,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
3001
3118
|
}
|
|
3002
3119
|
writeJson5File(buildProfilePath, buildProfile);
|
|
3003
3120
|
}
|
|
3004
|
-
const moduleJsonPath =
|
|
3005
|
-
if (
|
|
3121
|
+
const moduleJsonPath = path24.join(projectDir, args.moduleName, "src", "main", "module.json5");
|
|
3122
|
+
if (fs25.existsSync(moduleJsonPath)) {
|
|
3006
3123
|
const moduleJson = readJson5File(moduleJsonPath);
|
|
3007
3124
|
moduleJson.module = moduleJson.module ?? {};
|
|
3008
3125
|
moduleJson.module.name = args.moduleName;
|
|
3009
3126
|
writeJson5File(moduleJsonPath, moduleJson);
|
|
3010
3127
|
}
|
|
3011
|
-
const moduleOhPackagePath =
|
|
3012
|
-
if (
|
|
3128
|
+
const moduleOhPackagePath = path24.join(projectDir, args.moduleName, "oh-package.json5");
|
|
3129
|
+
if (fs25.existsSync(moduleOhPackagePath)) {
|
|
3013
3130
|
const pkg = readJson5File(moduleOhPackagePath);
|
|
3014
3131
|
pkg.name = args.moduleName;
|
|
3015
3132
|
writeJson5File(moduleOhPackagePath, pkg);
|
|
3016
3133
|
}
|
|
3017
|
-
const vscodeDir =
|
|
3018
|
-
|
|
3134
|
+
const vscodeDir = path24.join(projectDir, ".vscode");
|
|
3135
|
+
fs25.mkdirSync(vscodeDir, { recursive: true });
|
|
3019
3136
|
const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
|
|
3020
|
-
writeJsonFile(
|
|
3137
|
+
writeJsonFile(path24.join(vscodeDir, "settings.json"), {
|
|
3021
3138
|
"oniro.hapPath": hapPath,
|
|
3022
3139
|
"files.associations": { "*.json5": "jsonc" }
|
|
3023
3140
|
});
|
|
@@ -3034,7 +3151,7 @@ async function createScaffold(opts) {
|
|
|
3034
3151
|
if (!opts.location || !await pathExists(opts.location)) {
|
|
3035
3152
|
throw new OniroError(`Location does not exist: ${opts.location}`);
|
|
3036
3153
|
}
|
|
3037
|
-
const templateDir =
|
|
3154
|
+
const templateDir = path24.join(opts.templateRoot, opts.templateId);
|
|
3038
3155
|
if (!await pathExists(templateDir)) {
|
|
3039
3156
|
throw new OniroError(`Template not found: ${templateDir}`);
|
|
3040
3157
|
}
|
|
@@ -3047,17 +3164,17 @@ async function createScaffold(opts) {
|
|
|
3047
3164
|
throw new OniroError(`Template '${opts.templateId}' is missing required files:
|
|
3048
3165
|
- ${missing.join("\n- ")}`);
|
|
3049
3166
|
}
|
|
3050
|
-
const projectDir =
|
|
3167
|
+
const projectDir = path24.join(opts.location, opts.projectName);
|
|
3051
3168
|
if (await pathExists(projectDir)) {
|
|
3052
3169
|
if (!opts.overwrite) {
|
|
3053
3170
|
throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
|
|
3054
3171
|
}
|
|
3055
|
-
await
|
|
3172
|
+
await fs25.promises.rm(projectDir, { recursive: true, force: true });
|
|
3056
3173
|
}
|
|
3057
3174
|
logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
|
|
3058
3175
|
await copyDirRecursive(templateDir, projectDir);
|
|
3059
3176
|
if (moduleName !== defaultModuleName) {
|
|
3060
|
-
renameIfExists(
|
|
3177
|
+
renameIfExists(path24.join(projectDir, defaultModuleName), path24.join(projectDir, moduleName));
|
|
3061
3178
|
}
|
|
3062
3179
|
updateTemplateConfigs(
|
|
3063
3180
|
projectDir,
|
|
@@ -3074,11 +3191,11 @@ async function createScaffold(opts) {
|
|
|
3074
3191
|
}
|
|
3075
3192
|
|
|
3076
3193
|
// src/project/listModules.ts
|
|
3077
|
-
import * as
|
|
3078
|
-
import * as
|
|
3194
|
+
import * as fs26 from "fs";
|
|
3195
|
+
import * as path25 from "path";
|
|
3079
3196
|
function listModules(opts) {
|
|
3080
|
-
const buildProfile =
|
|
3081
|
-
if (!
|
|
3197
|
+
const buildProfile = path25.join(opts.projectDir, "build-profile.json5");
|
|
3198
|
+
if (!fs26.existsSync(buildProfile)) {
|
|
3082
3199
|
throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
|
|
3083
3200
|
}
|
|
3084
3201
|
const parsed = readJson5File(buildProfile);
|
|
@@ -3090,12 +3207,12 @@ function listModules(opts) {
|
|
|
3090
3207
|
}
|
|
3091
3208
|
|
|
3092
3209
|
// src/project/abilities.ts
|
|
3093
|
-
import * as
|
|
3094
|
-
import * as
|
|
3210
|
+
import * as fs27 from "fs";
|
|
3211
|
+
import * as path26 from "path";
|
|
3095
3212
|
function listAbilities(opts) {
|
|
3096
3213
|
const moduleName = opts.moduleName ?? "entry";
|
|
3097
|
-
const moduleJsonPath =
|
|
3098
|
-
if (!
|
|
3214
|
+
const moduleJsonPath = path26.join(opts.projectDir, moduleName, "src", "main", "module.json5");
|
|
3215
|
+
if (!fs27.existsSync(moduleJsonPath)) {
|
|
3099
3216
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
3100
3217
|
}
|
|
3101
3218
|
const parsed = readJson5File(moduleJsonPath);
|
|
@@ -3103,12 +3220,12 @@ function listAbilities(opts) {
|
|
|
3103
3220
|
}
|
|
3104
3221
|
|
|
3105
3222
|
// src/project/prepareSigning.ts
|
|
3106
|
-
import * as
|
|
3107
|
-
import * as
|
|
3223
|
+
import * as fs28 from "fs";
|
|
3224
|
+
import * as path27 from "path";
|
|
3108
3225
|
function hasSigningArtifacts(dir) {
|
|
3109
|
-
if (!
|
|
3110
|
-
const buildProfile =
|
|
3111
|
-
if (!
|
|
3226
|
+
if (!fs28.existsSync(path27.join(dir, "signatures"))) return false;
|
|
3227
|
+
const buildProfile = path27.join(dir, "build-profile.json5");
|
|
3228
|
+
if (!fs28.existsSync(buildProfile)) return false;
|
|
3112
3229
|
try {
|
|
3113
3230
|
const parsed = readJson5File(buildProfile);
|
|
3114
3231
|
return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
|
|
@@ -3198,8 +3315,8 @@ async function diffHapAssets(opts) {
|
|
|
3198
3315
|
}
|
|
3199
3316
|
|
|
3200
3317
|
// src/install/apply.ts
|
|
3201
|
-
import * as
|
|
3202
|
-
import * as
|
|
3318
|
+
import * as fs29 from "fs";
|
|
3319
|
+
import * as path28 from "path";
|
|
3203
3320
|
function decideInstallMethod(s) {
|
|
3204
3321
|
if (!s.signInfoInconsistent) return "replace";
|
|
3205
3322
|
if (s.isSystemBundle && !s.allowUninstall) return "refuse";
|
|
@@ -3220,7 +3337,7 @@ async function pidOf(config, bundle, deviceSerial) {
|
|
|
3220
3337
|
async function resolveHapPath(opts) {
|
|
3221
3338
|
let hapPath = opts.hapPath;
|
|
3222
3339
|
if (hapPath) {
|
|
3223
|
-
if (!
|
|
3340
|
+
if (!path28.isAbsolute(hapPath) && opts.projectDir) hapPath = path28.join(opts.projectDir, hapPath);
|
|
3224
3341
|
} else {
|
|
3225
3342
|
if (!opts.projectDir) throw new OniroError("applyChanges requires hapPath or projectDir.");
|
|
3226
3343
|
const haps = await discoverHaps({ projectDir: opts.projectDir });
|
|
@@ -3239,7 +3356,7 @@ async function resolveHapPath(opts) {
|
|
|
3239
3356
|
hapPath = withSigned[0][1].signed[0];
|
|
3240
3357
|
}
|
|
3241
3358
|
}
|
|
3242
|
-
if (!
|
|
3359
|
+
if (!fs29.existsSync(hapPath)) throw new OniroError(`HAP not found at ${hapPath}.`);
|
|
3243
3360
|
return hapPath;
|
|
3244
3361
|
}
|
|
3245
3362
|
async function applyChanges(opts) {
|
|
@@ -3249,7 +3366,7 @@ async function applyChanges(opts) {
|
|
|
3249
3366
|
const allowUninstall = opts.allowUninstall ?? false;
|
|
3250
3367
|
const hapPath = await resolveHapPath(opts);
|
|
3251
3368
|
let assetsChanged = false;
|
|
3252
|
-
if (opts.installedHapPath &&
|
|
3369
|
+
if (opts.installedHapPath && fs29.existsSync(opts.installedHapPath)) {
|
|
3253
3370
|
try {
|
|
3254
3371
|
const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
|
|
3255
3372
|
assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
|
|
@@ -3291,7 +3408,7 @@ async function applyChanges(opts) {
|
|
|
3291
3408
|
}
|
|
3292
3409
|
|
|
3293
3410
|
// src/index.ts
|
|
3294
|
-
var VERSION = "0.
|
|
3411
|
+
var VERSION = "0.10.0";
|
|
3295
3412
|
export {
|
|
3296
3413
|
ALL_SDKS,
|
|
3297
3414
|
APL_VALUES,
|
|
@@ -3310,6 +3427,7 @@ export {
|
|
|
3310
3427
|
VERSION,
|
|
3311
3428
|
applyChanges,
|
|
3312
3429
|
attemptHdcConnection,
|
|
3430
|
+
buildCmdWrapper,
|
|
3313
3431
|
buildGestureCommands,
|
|
3314
3432
|
buildGestureUitestCommand,
|
|
3315
3433
|
buildHap,
|
|
@@ -3346,6 +3464,8 @@ export {
|
|
|
3346
3464
|
ensureOhModules,
|
|
3347
3465
|
ensureOk,
|
|
3348
3466
|
ensureRemoteOk,
|
|
3467
|
+
escapeCmdArgument,
|
|
3468
|
+
escapeCmdCommand,
|
|
3349
3469
|
extractTarball,
|
|
3350
3470
|
extractZipWithProgress,
|
|
3351
3471
|
findAppProcessId,
|
|
@@ -3384,12 +3504,14 @@ export {
|
|
|
3384
3504
|
isRamBackedPath,
|
|
3385
3505
|
isValidBundleName,
|
|
3386
3506
|
isValidProjectName,
|
|
3507
|
+
killProcessTree,
|
|
3387
3508
|
launchApp,
|
|
3388
3509
|
listAbilities,
|
|
3389
3510
|
listDevices,
|
|
3390
3511
|
listModules,
|
|
3391
3512
|
listRunningProcesses,
|
|
3392
3513
|
listTemplates,
|
|
3514
|
+
needsCmdWrapper,
|
|
3393
3515
|
nonInteractivePrompter,
|
|
3394
3516
|
noopLogger,
|
|
3395
3517
|
noopProgress,
|
|
@@ -3426,11 +3548,13 @@ export {
|
|
|
3426
3548
|
setHilogLevel,
|
|
3427
3549
|
shell,
|
|
3428
3550
|
shellChecked,
|
|
3551
|
+
spawnCompat,
|
|
3429
3552
|
startEmulator,
|
|
3430
3553
|
staticConfig,
|
|
3431
3554
|
stopEmulator,
|
|
3432
3555
|
streamHilog,
|
|
3433
3556
|
takeScreenshot,
|
|
3557
|
+
toLongPath,
|
|
3434
3558
|
toSpaceError,
|
|
3435
3559
|
uninstallApp,
|
|
3436
3560
|
validateTemplateLayout,
|