@oniroproject/core 0.8.0 → 0.9.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 +360 -232
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +91 -3
- package/dist/index.d.ts +91 -3
- package/dist/index.js +354 -233
- 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
|
}
|
|
@@ -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,8 +1965,8 @@ 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
1972
|
const result = await hdcExec({ config: opts.config, args: ["install", hapPath], timeoutMs: 3e5 });
|
|
@@ -1957,10 +2051,16 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1957
2051
|
const timeoutMs = options.timeoutMs ?? 1e3;
|
|
1958
2052
|
const hdc = getHdcPath(config);
|
|
1959
2053
|
return new Promise((resolve4, reject) => {
|
|
1960
|
-
|
|
2054
|
+
let proc;
|
|
2055
|
+
try {
|
|
2056
|
+
proc = spawnCompat(hdc, ["track-jpid"]);
|
|
2057
|
+
} catch (err) {
|
|
2058
|
+
reject(new OniroError(`Failed to spawn ${hdc}: ${err instanceof Error ? err.message : String(err)}`, err));
|
|
2059
|
+
return;
|
|
2060
|
+
}
|
|
1961
2061
|
const processes = [];
|
|
1962
2062
|
let resolved = false;
|
|
1963
|
-
proc.stdout
|
|
2063
|
+
proc.stdout?.on("data", (data) => {
|
|
1964
2064
|
for (const line of data.toString().split("\n").filter(Boolean)) {
|
|
1965
2065
|
const match = line.match(/^(\d+)\s+(.+)$/);
|
|
1966
2066
|
if (!match) continue;
|
|
@@ -1969,13 +2069,13 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1969
2069
|
processes.push({ pid, name });
|
|
1970
2070
|
if (options.targetProcessName && name === options.targetProcessName && !resolved) {
|
|
1971
2071
|
resolved = true;
|
|
1972
|
-
proc
|
|
2072
|
+
killProcessTree(proc);
|
|
1973
2073
|
resolve4(pid);
|
|
1974
2074
|
return;
|
|
1975
2075
|
}
|
|
1976
2076
|
}
|
|
1977
2077
|
});
|
|
1978
|
-
proc.stderr
|
|
2078
|
+
proc.stderr?.on("data", (data) => {
|
|
1979
2079
|
logger.warn(`[hdc track-jpid] ${data.toString()}`);
|
|
1980
2080
|
});
|
|
1981
2081
|
proc.on("error", (err) => {
|
|
@@ -1987,7 +2087,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
1987
2087
|
const timeout = setTimeout(() => {
|
|
1988
2088
|
if (resolved) return;
|
|
1989
2089
|
resolved = true;
|
|
1990
|
-
proc
|
|
2090
|
+
killProcessTree(proc);
|
|
1991
2091
|
if (options.targetProcessName) {
|
|
1992
2092
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
1993
2093
|
} else {
|
|
@@ -2145,12 +2245,12 @@ async function reboot(opts) {
|
|
|
2145
2245
|
}
|
|
2146
2246
|
|
|
2147
2247
|
// src/hdc/screen.ts
|
|
2148
|
-
import * as
|
|
2248
|
+
import * as fs18 from "fs";
|
|
2149
2249
|
import * as os8 from "os";
|
|
2150
|
-
import * as
|
|
2250
|
+
import * as path18 from "path";
|
|
2151
2251
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
2152
2252
|
function tmpName(ext) {
|
|
2153
|
-
return
|
|
2253
|
+
return path18.join(os8.tmpdir(), `oniro_screen_${randomBytes2(6).toString("hex")}.${ext}`);
|
|
2154
2254
|
}
|
|
2155
2255
|
async function takeScreenshot(opts) {
|
|
2156
2256
|
const remote = "/data/local/tmp/oniro_screenshot.jpeg";
|
|
@@ -2160,11 +2260,11 @@ async function takeScreenshot(opts) {
|
|
|
2160
2260
|
const local = tmpName("jpeg");
|
|
2161
2261
|
try {
|
|
2162
2262
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
2163
|
-
const pixels = await
|
|
2263
|
+
const pixels = await fs18.promises.readFile(local);
|
|
2164
2264
|
const size = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial }) ?? { width: 0, height: 0 };
|
|
2165
2265
|
return { pixels, width: size.width, height: size.height };
|
|
2166
2266
|
} finally {
|
|
2167
|
-
|
|
2267
|
+
fs18.promises.unlink(local).catch(() => {
|
|
2168
2268
|
});
|
|
2169
2269
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
2170
2270
|
});
|
|
@@ -2183,9 +2283,9 @@ async function captureBurst(opts) {
|
|
|
2183
2283
|
const local = tmpName(`burst_${i}.jpeg`);
|
|
2184
2284
|
try {
|
|
2185
2285
|
await recvFile({ config: opts.config, remote: `${remoteDir}/f${i}.jpeg`, local, deviceSerial: opts.deviceSerial });
|
|
2186
|
-
frames.push(await
|
|
2286
|
+
frames.push(await fs18.promises.readFile(local));
|
|
2187
2287
|
} finally {
|
|
2188
|
-
|
|
2288
|
+
fs18.promises.unlink(local).catch(() => {
|
|
2189
2289
|
});
|
|
2190
2290
|
}
|
|
2191
2291
|
}
|
|
@@ -2311,9 +2411,9 @@ async function sendRawTouch(opts) {
|
|
|
2311
2411
|
}
|
|
2312
2412
|
|
|
2313
2413
|
// src/hdc/dump.ts
|
|
2314
|
-
import * as
|
|
2414
|
+
import * as fs19 from "fs";
|
|
2315
2415
|
import * as os9 from "os";
|
|
2316
|
-
import * as
|
|
2416
|
+
import * as path19 from "path";
|
|
2317
2417
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
2318
2418
|
function parseBounds(s) {
|
|
2319
2419
|
const m = /^\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]$/.exec(s ?? "");
|
|
@@ -2398,10 +2498,10 @@ async function dumpLayout(opts) {
|
|
|
2398
2498
|
if (!m) throw new OniroError(`Could not parse dumpLayout output:
|
|
2399
2499
|
${dump.stdout}`);
|
|
2400
2500
|
const remote = m[1];
|
|
2401
|
-
const local =
|
|
2501
|
+
const local = path19.join(os9.tmpdir(), `oniro_layout_${randomBytes3(6).toString("hex")}.json`);
|
|
2402
2502
|
try {
|
|
2403
2503
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
2404
|
-
const parsed = JSON.parse(await
|
|
2504
|
+
const parsed = JSON.parse(await fs19.promises.readFile(local, "utf8"));
|
|
2405
2505
|
const display = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial });
|
|
2406
2506
|
if (opts.prune === false) {
|
|
2407
2507
|
return { display, tree: parsed };
|
|
@@ -2410,7 +2510,7 @@ ${dump.stdout}`);
|
|
|
2410
2510
|
const tree = Array.isArray(prunedRaw) ? { children: prunedRaw } : prunedRaw ?? { children: [] };
|
|
2411
2511
|
return { display, tree };
|
|
2412
2512
|
} finally {
|
|
2413
|
-
|
|
2513
|
+
fs19.promises.unlink(local).catch(() => {
|
|
2414
2514
|
});
|
|
2415
2515
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
2416
2516
|
});
|
|
@@ -2418,14 +2518,21 @@ ${dump.stdout}`);
|
|
|
2418
2518
|
}
|
|
2419
2519
|
|
|
2420
2520
|
// src/hdc/hilog.ts
|
|
2421
|
-
import { spawn as spawn4 } from "child_process";
|
|
2422
2521
|
function setHilogLevel(opts) {
|
|
2423
2522
|
const logger = opts.logger ?? noopLogger;
|
|
2424
2523
|
const hdc = getHdcPath(opts.config);
|
|
2425
2524
|
return new Promise((resolve4, reject) => {
|
|
2426
|
-
|
|
2525
|
+
let child;
|
|
2526
|
+
try {
|
|
2527
|
+
child = spawnCompat(hdc, ["shell", "hilog", "-b", opts.level]);
|
|
2528
|
+
} catch (err) {
|
|
2529
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2530
|
+
logger.error(`[hilog] failed to spawn hdc: ${msg}`);
|
|
2531
|
+
reject(err instanceof Error ? err : new Error(msg));
|
|
2532
|
+
return;
|
|
2533
|
+
}
|
|
2427
2534
|
let stderr = "";
|
|
2428
|
-
child.stderr
|
|
2535
|
+
child.stderr?.on("data", (chunk) => {
|
|
2429
2536
|
stderr += chunk.toString();
|
|
2430
2537
|
});
|
|
2431
2538
|
child.once("error", (err) => {
|
|
@@ -2454,7 +2561,7 @@ function streamHilog(opts) {
|
|
|
2454
2561
|
if (opts.domain !== void 0 && `${opts.domain}` !== "") {
|
|
2455
2562
|
args.push("-D", `${opts.domain}`);
|
|
2456
2563
|
}
|
|
2457
|
-
return
|
|
2564
|
+
return spawnCompat(hdc, args);
|
|
2458
2565
|
}
|
|
2459
2566
|
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
2567
|
function parseHilogLine(line) {
|
|
@@ -2500,10 +2607,7 @@ function waitForLog(opts) {
|
|
|
2500
2607
|
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
2501
2608
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
2502
2609
|
if (child) {
|
|
2503
|
-
|
|
2504
|
-
child.kill("SIGKILL");
|
|
2505
|
-
} catch {
|
|
2506
|
-
}
|
|
2610
|
+
killProcessTree(child);
|
|
2507
2611
|
child = null;
|
|
2508
2612
|
}
|
|
2509
2613
|
};
|
|
@@ -2519,6 +2623,7 @@ function waitForLog(opts) {
|
|
|
2519
2623
|
cleanup();
|
|
2520
2624
|
reject(err);
|
|
2521
2625
|
};
|
|
2626
|
+
const failWith = (err) => fail(err instanceof Error ? err : new Error(String(err)));
|
|
2522
2627
|
const onAbort = () => fail(new CancelledError("waitForLog cancelled."));
|
|
2523
2628
|
const timer = setTimeout(
|
|
2524
2629
|
() => fail(new OniroError(`No log line matched ${String(opts.pattern)} within ${opts.timeoutMs}ms.`)),
|
|
@@ -2548,13 +2653,13 @@ function waitForLog(opts) {
|
|
|
2548
2653
|
if (settled || child !== stream) return;
|
|
2549
2654
|
child = null;
|
|
2550
2655
|
if (Date.now() < deadline) {
|
|
2551
|
-
reconnectTimer = setTimeout(() => void spawnStream(), 1e3);
|
|
2656
|
+
reconnectTimer = setTimeout(() => void spawnStream().catch(failWith), 1e3);
|
|
2552
2657
|
}
|
|
2553
2658
|
};
|
|
2554
2659
|
stream.once("close", onEnd);
|
|
2555
2660
|
stream.once("error", onEnd);
|
|
2556
2661
|
};
|
|
2557
|
-
void spawnStream();
|
|
2662
|
+
void spawnStream().catch(failWith);
|
|
2558
2663
|
});
|
|
2559
2664
|
}
|
|
2560
2665
|
function watchLog(opts) {
|
|
@@ -2567,10 +2672,7 @@ function watchLog(opts) {
|
|
|
2567
2672
|
clearTimeout(timer);
|
|
2568
2673
|
opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
2569
2674
|
if (child) {
|
|
2570
|
-
|
|
2571
|
-
child.kill("SIGKILL");
|
|
2572
|
-
} catch {
|
|
2573
|
-
}
|
|
2675
|
+
killProcessTree(child);
|
|
2574
2676
|
child = null;
|
|
2575
2677
|
}
|
|
2576
2678
|
};
|
|
@@ -2603,7 +2705,12 @@ function watchLog(opts) {
|
|
|
2603
2705
|
if (entry && opts.pattern.test(entryText(entry))) matches.push(entry);
|
|
2604
2706
|
}
|
|
2605
2707
|
});
|
|
2606
|
-
})()
|
|
2708
|
+
})().catch((err) => {
|
|
2709
|
+
if (settled) return;
|
|
2710
|
+
settled = true;
|
|
2711
|
+
cleanup();
|
|
2712
|
+
reject(err instanceof Error ? err : new Error(String(err)));
|
|
2713
|
+
});
|
|
2607
2714
|
});
|
|
2608
2715
|
}
|
|
2609
2716
|
async function dumpLog(opts) {
|
|
@@ -2630,9 +2737,8 @@ async function dumpLog(opts) {
|
|
|
2630
2737
|
}
|
|
2631
2738
|
|
|
2632
2739
|
// src/build/runHvigorw.ts
|
|
2633
|
-
import * as
|
|
2634
|
-
import * as
|
|
2635
|
-
import { spawn as spawn5 } from "child_process";
|
|
2740
|
+
import * as fs20 from "fs";
|
|
2741
|
+
import * as path20 from "path";
|
|
2636
2742
|
function buildHvigorwArgs(opts) {
|
|
2637
2743
|
const args = [opts.task ?? "assembleHap", "--mode", "module"];
|
|
2638
2744
|
args.push("-p", `product=${opts.product ?? "default"}`);
|
|
@@ -2644,19 +2750,23 @@ function buildHvigorwArgs(opts) {
|
|
|
2644
2750
|
return args;
|
|
2645
2751
|
}
|
|
2646
2752
|
function runHvigorw(opts) {
|
|
2647
|
-
const { config
|
|
2753
|
+
const { config } = opts;
|
|
2754
|
+
const projectDir = toLongPath(opts.projectDir);
|
|
2648
2755
|
const logger = opts.logger ?? noopLogger;
|
|
2649
|
-
if (!
|
|
2756
|
+
if (!fs20.existsSync(path20.join(projectDir, "build-profile.json5"))) {
|
|
2650
2757
|
throw new OniroError(`Not an OpenHarmony project: ${projectDir} (build-profile.json5 not found).`);
|
|
2651
2758
|
}
|
|
2652
|
-
if (!
|
|
2759
|
+
if (!fs20.existsSync(getCmdToolsPath(config))) {
|
|
2653
2760
|
throw new CmdToolsNotInstalledError(getCmdToolsPath(config));
|
|
2654
2761
|
}
|
|
2655
2762
|
const hvigorw = getHvigorwPath(config, projectDir);
|
|
2763
|
+
if (!fs20.existsSync(hvigorw)) {
|
|
2764
|
+
throw new OniroError(`hvigorw wrapper not found at ${hvigorw}.`);
|
|
2765
|
+
}
|
|
2656
2766
|
const args = buildHvigorwArgs(opts);
|
|
2657
2767
|
if (process.platform !== "win32") {
|
|
2658
2768
|
try {
|
|
2659
|
-
|
|
2769
|
+
fs20.chmodSync(hvigorw, 493);
|
|
2660
2770
|
} catch {
|
|
2661
2771
|
}
|
|
2662
2772
|
}
|
|
@@ -2670,26 +2780,29 @@ function runHvigorw(opts) {
|
|
|
2670
2780
|
return;
|
|
2671
2781
|
}
|
|
2672
2782
|
logger.info(`[build] ${hvigorw} ${args.join(" ")}`);
|
|
2673
|
-
|
|
2783
|
+
let child;
|
|
2784
|
+
try {
|
|
2785
|
+
child = spawnCompat(hvigorw, args, { cwd: projectDir, env });
|
|
2786
|
+
} catch (err) {
|
|
2787
|
+
reject(new OniroError(`Failed to start hvigorw: ${err instanceof Error ? err.message : String(err)}`, err));
|
|
2788
|
+
return;
|
|
2789
|
+
}
|
|
2674
2790
|
let settled = false;
|
|
2675
2791
|
const cleanup = () => opts.abortSignal?.removeEventListener("abort", onAbort);
|
|
2676
2792
|
const onAbort = () => {
|
|
2677
2793
|
if (settled) return;
|
|
2678
2794
|
settled = true;
|
|
2679
2795
|
cleanup();
|
|
2680
|
-
|
|
2681
|
-
child.kill("SIGKILL");
|
|
2682
|
-
} catch {
|
|
2683
|
-
}
|
|
2796
|
+
killProcessTree(child);
|
|
2684
2797
|
reject(new CancelledError("hvigorw build cancelled."));
|
|
2685
2798
|
};
|
|
2686
2799
|
opts.abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
2687
|
-
child.stdout
|
|
2800
|
+
child.stdout?.on("data", (chunk) => {
|
|
2688
2801
|
const text = chunk.toString();
|
|
2689
2802
|
opts.onOutput?.(text, "stdout");
|
|
2690
2803
|
logger.info(text.trimEnd());
|
|
2691
2804
|
});
|
|
2692
|
-
child.stderr
|
|
2805
|
+
child.stderr?.on("data", (chunk) => {
|
|
2693
2806
|
const text = chunk.toString();
|
|
2694
2807
|
opts.onOutput?.(text, "stderr");
|
|
2695
2808
|
logger.warn(text.trimEnd());
|
|
@@ -2712,8 +2825,8 @@ function runHvigorw(opts) {
|
|
|
2712
2825
|
}
|
|
2713
2826
|
|
|
2714
2827
|
// src/build/discoverHaps.ts
|
|
2715
|
-
import * as
|
|
2716
|
-
import * as
|
|
2828
|
+
import * as fs21 from "fs";
|
|
2829
|
+
import * as path21 from "path";
|
|
2717
2830
|
function moduleOfHap(hapFileName) {
|
|
2718
2831
|
const dash = hapFileName.indexOf("-");
|
|
2719
2832
|
return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
|
|
@@ -2724,9 +2837,9 @@ async function discoverHaps(opts) {
|
|
|
2724
2837
|
const result = {};
|
|
2725
2838
|
const walk = async (dir, depth) => {
|
|
2726
2839
|
if (depth > maxDepth) return;
|
|
2727
|
-
const entries = await
|
|
2840
|
+
const entries = await fs21.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
2728
2841
|
for (const e of entries) {
|
|
2729
|
-
const full =
|
|
2842
|
+
const full = path21.join(dir, e.name);
|
|
2730
2843
|
if (e.isDirectory()) {
|
|
2731
2844
|
if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
|
|
2732
2845
|
await walk(full, depth + 1);
|
|
@@ -2743,8 +2856,8 @@ async function discoverHaps(opts) {
|
|
|
2743
2856
|
}
|
|
2744
2857
|
|
|
2745
2858
|
// src/build/ohpm.ts
|
|
2746
|
-
import * as
|
|
2747
|
-
import * as
|
|
2859
|
+
import * as fs22 from "fs";
|
|
2860
|
+
import * as path22 from "path";
|
|
2748
2861
|
function runOhpm(opts) {
|
|
2749
2862
|
return runProcess({
|
|
2750
2863
|
command: getOhpmPath(opts.config),
|
|
@@ -2757,7 +2870,7 @@ function runOhpm(opts) {
|
|
|
2757
2870
|
});
|
|
2758
2871
|
}
|
|
2759
2872
|
async function ensureOhModules(opts) {
|
|
2760
|
-
if (
|
|
2873
|
+
if (fs22.existsSync(path22.join(opts.projectDir, "oh_modules"))) {
|
|
2761
2874
|
return { installed: false };
|
|
2762
2875
|
}
|
|
2763
2876
|
const res = await runOhpm({
|
|
@@ -2809,10 +2922,11 @@ async function buildHap(opts) {
|
|
|
2809
2922
|
const logger = scopedLogger(opts.logger ?? noopLogger, "build");
|
|
2810
2923
|
const warnings = [];
|
|
2811
2924
|
const start = Date.now();
|
|
2925
|
+
const projectDir = toLongPath(opts.projectDir);
|
|
2812
2926
|
if (opts.autoInstallDeps !== false) {
|
|
2813
2927
|
const r = await ensureOhModules({
|
|
2814
2928
|
config: opts.config,
|
|
2815
|
-
projectDir
|
|
2929
|
+
projectDir,
|
|
2816
2930
|
abortSignal: opts.abortSignal,
|
|
2817
2931
|
onOutput: opts.onOutput,
|
|
2818
2932
|
logger: opts.logger
|
|
@@ -2821,7 +2935,7 @@ async function buildHap(opts) {
|
|
|
2821
2935
|
}
|
|
2822
2936
|
const { exitCode } = await runHvigorw({
|
|
2823
2937
|
config: opts.config,
|
|
2824
|
-
projectDir
|
|
2938
|
+
projectDir,
|
|
2825
2939
|
product: opts.product,
|
|
2826
2940
|
module: opts.module,
|
|
2827
2941
|
buildMode: opts.mode,
|
|
@@ -2831,7 +2945,7 @@ async function buildHap(opts) {
|
|
|
2831
2945
|
onOutput: opts.onOutput,
|
|
2832
2946
|
logger: opts.logger
|
|
2833
2947
|
});
|
|
2834
|
-
const discoveredHaps = await discoverHaps({ projectDir
|
|
2948
|
+
const discoveredHaps = await discoverHaps({ projectDir });
|
|
2835
2949
|
const anySigned = Object.values(discoveredHaps).some((m) => m.signed.length > 0);
|
|
2836
2950
|
if (!anySigned) {
|
|
2837
2951
|
warnings.push(
|
|
@@ -2852,21 +2966,21 @@ function isValidBundleName(bundleName) {
|
|
|
2852
2966
|
}
|
|
2853
2967
|
|
|
2854
2968
|
// src/project/templates.ts
|
|
2855
|
-
import * as
|
|
2856
|
-
import * as
|
|
2969
|
+
import * as fs23 from "fs";
|
|
2970
|
+
import * as path23 from "path";
|
|
2857
2971
|
function toHumanTemplateName(folderName) {
|
|
2858
2972
|
return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
2859
2973
|
}
|
|
2860
2974
|
function listTemplates(templateRoot) {
|
|
2861
|
-
if (!
|
|
2862
|
-
const entries =
|
|
2975
|
+
if (!fs23.existsSync(templateRoot)) return [];
|
|
2976
|
+
const entries = fs23.readdirSync(templateRoot, { withFileTypes: true });
|
|
2863
2977
|
return entries.filter((e) => e.isDirectory()).map((e) => {
|
|
2864
|
-
const dir =
|
|
2865
|
-
const metaPath =
|
|
2978
|
+
const dir = path23.join(templateRoot, e.name);
|
|
2979
|
+
const metaPath = path23.join(dir, "template.json");
|
|
2866
2980
|
let meta = {};
|
|
2867
|
-
if (
|
|
2981
|
+
if (fs23.existsSync(metaPath)) {
|
|
2868
2982
|
try {
|
|
2869
|
-
meta = JSON.parse(
|
|
2983
|
+
meta = JSON.parse(fs23.readFileSync(metaPath, "utf8"));
|
|
2870
2984
|
} catch {
|
|
2871
2985
|
}
|
|
2872
2986
|
}
|
|
@@ -2881,57 +2995,57 @@ function listTemplates(templateRoot) {
|
|
|
2881
2995
|
function validateTemplateLayout(templateDir, defaultModuleName) {
|
|
2882
2996
|
const required = [
|
|
2883
2997
|
"build-profile.json5",
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2998
|
+
path23.join("AppScope", "app.json5"),
|
|
2999
|
+
path23.join(defaultModuleName, "src", "main", "module.json5"),
|
|
3000
|
+
path23.join(defaultModuleName, "oh-package.json5"),
|
|
2887
3001
|
"hvigorfile.ts"
|
|
2888
3002
|
];
|
|
2889
|
-
return required.filter((rel) => !
|
|
3003
|
+
return required.filter((rel) => !fs23.existsSync(path23.join(templateDir, rel)));
|
|
2890
3004
|
}
|
|
2891
3005
|
|
|
2892
3006
|
// src/project/createScaffold.ts
|
|
2893
|
-
import * as
|
|
2894
|
-
import * as
|
|
3007
|
+
import * as fs25 from "fs";
|
|
3008
|
+
import * as path24 from "path";
|
|
2895
3009
|
|
|
2896
3010
|
// src/project/jsonHelpers.ts
|
|
2897
|
-
import * as
|
|
3011
|
+
import * as fs24 from "fs";
|
|
2898
3012
|
import JSON54 from "json5";
|
|
2899
3013
|
function readJson5File(filePath) {
|
|
2900
|
-
return JSON54.parse(
|
|
3014
|
+
return JSON54.parse(fs24.readFileSync(filePath, "utf8"));
|
|
2901
3015
|
}
|
|
2902
3016
|
function writeJson5File(filePath, value) {
|
|
2903
|
-
|
|
3017
|
+
fs24.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
2904
3018
|
}
|
|
2905
3019
|
function readJsonFile(filePath) {
|
|
2906
|
-
return JSON.parse(
|
|
3020
|
+
return JSON.parse(fs24.readFileSync(filePath, "utf8"));
|
|
2907
3021
|
}
|
|
2908
3022
|
function writeJsonFile(filePath, value) {
|
|
2909
|
-
|
|
3023
|
+
fs24.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
2910
3024
|
}
|
|
2911
3025
|
|
|
2912
3026
|
// src/project/createScaffold.ts
|
|
2913
3027
|
var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
|
|
2914
3028
|
async function pathExists(p) {
|
|
2915
3029
|
try {
|
|
2916
|
-
await
|
|
3030
|
+
await fs25.promises.access(p);
|
|
2917
3031
|
return true;
|
|
2918
3032
|
} catch {
|
|
2919
3033
|
return false;
|
|
2920
3034
|
}
|
|
2921
3035
|
}
|
|
2922
3036
|
async function copyDirRecursive(srcDir, destDir) {
|
|
2923
|
-
await
|
|
2924
|
-
const entries = await
|
|
3037
|
+
await fs25.promises.mkdir(destDir, { recursive: true });
|
|
3038
|
+
const entries = await fs25.promises.readdir(srcDir, { withFileTypes: true });
|
|
2925
3039
|
for (const entry of entries) {
|
|
2926
|
-
const src =
|
|
2927
|
-
const dest =
|
|
3040
|
+
const src = path24.join(srcDir, entry.name);
|
|
3041
|
+
const dest = path24.join(destDir, entry.name);
|
|
2928
3042
|
if (entry.isDirectory()) {
|
|
2929
3043
|
await copyDirRecursive(src, dest);
|
|
2930
3044
|
} else if (entry.isSymbolicLink()) {
|
|
2931
3045
|
continue;
|
|
2932
3046
|
} else if (entry.isFile()) {
|
|
2933
3047
|
if (entry.name === "template.json") continue;
|
|
2934
|
-
await
|
|
3048
|
+
await fs25.promises.copyFile(src, dest);
|
|
2935
3049
|
}
|
|
2936
3050
|
}
|
|
2937
3051
|
}
|
|
@@ -2939,9 +3053,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
|
|
|
2939
3053
|
const stack = [projectDir];
|
|
2940
3054
|
while (stack.length > 0) {
|
|
2941
3055
|
const currentDir = stack.pop();
|
|
2942
|
-
const entries = await
|
|
3056
|
+
const entries = await fs25.promises.readdir(currentDir, { withFileTypes: true });
|
|
2943
3057
|
for (const entry of entries) {
|
|
2944
|
-
const fullPath =
|
|
3058
|
+
const fullPath = path24.join(currentDir, entry.name);
|
|
2945
3059
|
if (entry.isDirectory()) {
|
|
2946
3060
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
2947
3061
|
stack.push(fullPath);
|
|
@@ -2963,23 +3077,23 @@ function toJavaPropertiesPath(p) {
|
|
|
2963
3077
|
function createOrUpdateLocalProperties(projectDir, sdkDir) {
|
|
2964
3078
|
const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
|
|
2965
3079
|
`;
|
|
2966
|
-
|
|
3080
|
+
fs25.writeFileSync(path24.join(projectDir, "local.properties"), content, "utf8");
|
|
2967
3081
|
}
|
|
2968
3082
|
function renameIfExists(fromPath, toPath) {
|
|
2969
|
-
if (
|
|
2970
|
-
|
|
3083
|
+
if (fs25.existsSync(fromPath) && fromPath !== toPath) {
|
|
3084
|
+
fs25.renameSync(fromPath, toPath);
|
|
2971
3085
|
}
|
|
2972
3086
|
}
|
|
2973
3087
|
function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
2974
|
-
const appJsonPath =
|
|
2975
|
-
if (
|
|
3088
|
+
const appJsonPath = path24.join(projectDir, "AppScope", "app.json5");
|
|
3089
|
+
if (fs25.existsSync(appJsonPath)) {
|
|
2976
3090
|
const appJson = readJson5File(appJsonPath);
|
|
2977
3091
|
appJson.app = appJson.app ?? {};
|
|
2978
3092
|
appJson.app.bundleName = args.bundleName;
|
|
2979
3093
|
writeJson5File(appJsonPath, appJson);
|
|
2980
3094
|
}
|
|
2981
|
-
const stringsPath =
|
|
2982
|
-
if (
|
|
3095
|
+
const stringsPath = path24.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
|
|
3096
|
+
if (fs25.existsSync(stringsPath)) {
|
|
2983
3097
|
const strings = readJsonFile(stringsPath);
|
|
2984
3098
|
if (Array.isArray(strings.string)) {
|
|
2985
3099
|
const appName = strings.string.find((s) => s.name === "app_name");
|
|
@@ -2987,8 +3101,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
2987
3101
|
}
|
|
2988
3102
|
writeJsonFile(stringsPath, strings);
|
|
2989
3103
|
}
|
|
2990
|
-
const buildProfilePath =
|
|
2991
|
-
if (
|
|
3104
|
+
const buildProfilePath = path24.join(projectDir, "build-profile.json5");
|
|
3105
|
+
if (fs25.existsSync(buildProfilePath)) {
|
|
2992
3106
|
const buildProfile = readJson5File(buildProfilePath);
|
|
2993
3107
|
buildProfile.app = buildProfile.app ?? {};
|
|
2994
3108
|
if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
|
|
@@ -3001,23 +3115,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
3001
3115
|
}
|
|
3002
3116
|
writeJson5File(buildProfilePath, buildProfile);
|
|
3003
3117
|
}
|
|
3004
|
-
const moduleJsonPath =
|
|
3005
|
-
if (
|
|
3118
|
+
const moduleJsonPath = path24.join(projectDir, args.moduleName, "src", "main", "module.json5");
|
|
3119
|
+
if (fs25.existsSync(moduleJsonPath)) {
|
|
3006
3120
|
const moduleJson = readJson5File(moduleJsonPath);
|
|
3007
3121
|
moduleJson.module = moduleJson.module ?? {};
|
|
3008
3122
|
moduleJson.module.name = args.moduleName;
|
|
3009
3123
|
writeJson5File(moduleJsonPath, moduleJson);
|
|
3010
3124
|
}
|
|
3011
|
-
const moduleOhPackagePath =
|
|
3012
|
-
if (
|
|
3125
|
+
const moduleOhPackagePath = path24.join(projectDir, args.moduleName, "oh-package.json5");
|
|
3126
|
+
if (fs25.existsSync(moduleOhPackagePath)) {
|
|
3013
3127
|
const pkg = readJson5File(moduleOhPackagePath);
|
|
3014
3128
|
pkg.name = args.moduleName;
|
|
3015
3129
|
writeJson5File(moduleOhPackagePath, pkg);
|
|
3016
3130
|
}
|
|
3017
|
-
const vscodeDir =
|
|
3018
|
-
|
|
3131
|
+
const vscodeDir = path24.join(projectDir, ".vscode");
|
|
3132
|
+
fs25.mkdirSync(vscodeDir, { recursive: true });
|
|
3019
3133
|
const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
|
|
3020
|
-
writeJsonFile(
|
|
3134
|
+
writeJsonFile(path24.join(vscodeDir, "settings.json"), {
|
|
3021
3135
|
"oniro.hapPath": hapPath,
|
|
3022
3136
|
"files.associations": { "*.json5": "jsonc" }
|
|
3023
3137
|
});
|
|
@@ -3034,7 +3148,7 @@ async function createScaffold(opts) {
|
|
|
3034
3148
|
if (!opts.location || !await pathExists(opts.location)) {
|
|
3035
3149
|
throw new OniroError(`Location does not exist: ${opts.location}`);
|
|
3036
3150
|
}
|
|
3037
|
-
const templateDir =
|
|
3151
|
+
const templateDir = path24.join(opts.templateRoot, opts.templateId);
|
|
3038
3152
|
if (!await pathExists(templateDir)) {
|
|
3039
3153
|
throw new OniroError(`Template not found: ${templateDir}`);
|
|
3040
3154
|
}
|
|
@@ -3047,17 +3161,17 @@ async function createScaffold(opts) {
|
|
|
3047
3161
|
throw new OniroError(`Template '${opts.templateId}' is missing required files:
|
|
3048
3162
|
- ${missing.join("\n- ")}`);
|
|
3049
3163
|
}
|
|
3050
|
-
const projectDir =
|
|
3164
|
+
const projectDir = path24.join(opts.location, opts.projectName);
|
|
3051
3165
|
if (await pathExists(projectDir)) {
|
|
3052
3166
|
if (!opts.overwrite) {
|
|
3053
3167
|
throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
|
|
3054
3168
|
}
|
|
3055
|
-
await
|
|
3169
|
+
await fs25.promises.rm(projectDir, { recursive: true, force: true });
|
|
3056
3170
|
}
|
|
3057
3171
|
logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
|
|
3058
3172
|
await copyDirRecursive(templateDir, projectDir);
|
|
3059
3173
|
if (moduleName !== defaultModuleName) {
|
|
3060
|
-
renameIfExists(
|
|
3174
|
+
renameIfExists(path24.join(projectDir, defaultModuleName), path24.join(projectDir, moduleName));
|
|
3061
3175
|
}
|
|
3062
3176
|
updateTemplateConfigs(
|
|
3063
3177
|
projectDir,
|
|
@@ -3074,11 +3188,11 @@ async function createScaffold(opts) {
|
|
|
3074
3188
|
}
|
|
3075
3189
|
|
|
3076
3190
|
// src/project/listModules.ts
|
|
3077
|
-
import * as
|
|
3078
|
-
import * as
|
|
3191
|
+
import * as fs26 from "fs";
|
|
3192
|
+
import * as path25 from "path";
|
|
3079
3193
|
function listModules(opts) {
|
|
3080
|
-
const buildProfile =
|
|
3081
|
-
if (!
|
|
3194
|
+
const buildProfile = path25.join(opts.projectDir, "build-profile.json5");
|
|
3195
|
+
if (!fs26.existsSync(buildProfile)) {
|
|
3082
3196
|
throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
|
|
3083
3197
|
}
|
|
3084
3198
|
const parsed = readJson5File(buildProfile);
|
|
@@ -3090,12 +3204,12 @@ function listModules(opts) {
|
|
|
3090
3204
|
}
|
|
3091
3205
|
|
|
3092
3206
|
// src/project/abilities.ts
|
|
3093
|
-
import * as
|
|
3094
|
-
import * as
|
|
3207
|
+
import * as fs27 from "fs";
|
|
3208
|
+
import * as path26 from "path";
|
|
3095
3209
|
function listAbilities(opts) {
|
|
3096
3210
|
const moduleName = opts.moduleName ?? "entry";
|
|
3097
|
-
const moduleJsonPath =
|
|
3098
|
-
if (!
|
|
3211
|
+
const moduleJsonPath = path26.join(opts.projectDir, moduleName, "src", "main", "module.json5");
|
|
3212
|
+
if (!fs27.existsSync(moduleJsonPath)) {
|
|
3099
3213
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
3100
3214
|
}
|
|
3101
3215
|
const parsed = readJson5File(moduleJsonPath);
|
|
@@ -3103,12 +3217,12 @@ function listAbilities(opts) {
|
|
|
3103
3217
|
}
|
|
3104
3218
|
|
|
3105
3219
|
// src/project/prepareSigning.ts
|
|
3106
|
-
import * as
|
|
3107
|
-
import * as
|
|
3220
|
+
import * as fs28 from "fs";
|
|
3221
|
+
import * as path27 from "path";
|
|
3108
3222
|
function hasSigningArtifacts(dir) {
|
|
3109
|
-
if (!
|
|
3110
|
-
const buildProfile =
|
|
3111
|
-
if (!
|
|
3223
|
+
if (!fs28.existsSync(path27.join(dir, "signatures"))) return false;
|
|
3224
|
+
const buildProfile = path27.join(dir, "build-profile.json5");
|
|
3225
|
+
if (!fs28.existsSync(buildProfile)) return false;
|
|
3112
3226
|
try {
|
|
3113
3227
|
const parsed = readJson5File(buildProfile);
|
|
3114
3228
|
return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
|
|
@@ -3198,8 +3312,8 @@ async function diffHapAssets(opts) {
|
|
|
3198
3312
|
}
|
|
3199
3313
|
|
|
3200
3314
|
// src/install/apply.ts
|
|
3201
|
-
import * as
|
|
3202
|
-
import * as
|
|
3315
|
+
import * as fs29 from "fs";
|
|
3316
|
+
import * as path28 from "path";
|
|
3203
3317
|
function decideInstallMethod(s) {
|
|
3204
3318
|
if (!s.signInfoInconsistent) return "replace";
|
|
3205
3319
|
if (s.isSystemBundle && !s.allowUninstall) return "refuse";
|
|
@@ -3220,7 +3334,7 @@ async function pidOf(config, bundle, deviceSerial) {
|
|
|
3220
3334
|
async function resolveHapPath(opts) {
|
|
3221
3335
|
let hapPath = opts.hapPath;
|
|
3222
3336
|
if (hapPath) {
|
|
3223
|
-
if (!
|
|
3337
|
+
if (!path28.isAbsolute(hapPath) && opts.projectDir) hapPath = path28.join(opts.projectDir, hapPath);
|
|
3224
3338
|
} else {
|
|
3225
3339
|
if (!opts.projectDir) throw new OniroError("applyChanges requires hapPath or projectDir.");
|
|
3226
3340
|
const haps = await discoverHaps({ projectDir: opts.projectDir });
|
|
@@ -3239,7 +3353,7 @@ async function resolveHapPath(opts) {
|
|
|
3239
3353
|
hapPath = withSigned[0][1].signed[0];
|
|
3240
3354
|
}
|
|
3241
3355
|
}
|
|
3242
|
-
if (!
|
|
3356
|
+
if (!fs29.existsSync(hapPath)) throw new OniroError(`HAP not found at ${hapPath}.`);
|
|
3243
3357
|
return hapPath;
|
|
3244
3358
|
}
|
|
3245
3359
|
async function applyChanges(opts) {
|
|
@@ -3249,7 +3363,7 @@ async function applyChanges(opts) {
|
|
|
3249
3363
|
const allowUninstall = opts.allowUninstall ?? false;
|
|
3250
3364
|
const hapPath = await resolveHapPath(opts);
|
|
3251
3365
|
let assetsChanged = false;
|
|
3252
|
-
if (opts.installedHapPath &&
|
|
3366
|
+
if (opts.installedHapPath && fs29.existsSync(opts.installedHapPath)) {
|
|
3253
3367
|
try {
|
|
3254
3368
|
const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
|
|
3255
3369
|
assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
|
|
@@ -3291,7 +3405,7 @@ async function applyChanges(opts) {
|
|
|
3291
3405
|
}
|
|
3292
3406
|
|
|
3293
3407
|
// src/index.ts
|
|
3294
|
-
var VERSION = "0.
|
|
3408
|
+
var VERSION = "0.9.0";
|
|
3295
3409
|
export {
|
|
3296
3410
|
ALL_SDKS,
|
|
3297
3411
|
APL_VALUES,
|
|
@@ -3310,6 +3424,7 @@ export {
|
|
|
3310
3424
|
VERSION,
|
|
3311
3425
|
applyChanges,
|
|
3312
3426
|
attemptHdcConnection,
|
|
3427
|
+
buildCmdWrapper,
|
|
3313
3428
|
buildGestureCommands,
|
|
3314
3429
|
buildGestureUitestCommand,
|
|
3315
3430
|
buildHap,
|
|
@@ -3346,6 +3461,8 @@ export {
|
|
|
3346
3461
|
ensureOhModules,
|
|
3347
3462
|
ensureOk,
|
|
3348
3463
|
ensureRemoteOk,
|
|
3464
|
+
escapeCmdArgument,
|
|
3465
|
+
escapeCmdCommand,
|
|
3349
3466
|
extractTarball,
|
|
3350
3467
|
extractZipWithProgress,
|
|
3351
3468
|
findAppProcessId,
|
|
@@ -3384,12 +3501,14 @@ export {
|
|
|
3384
3501
|
isRamBackedPath,
|
|
3385
3502
|
isValidBundleName,
|
|
3386
3503
|
isValidProjectName,
|
|
3504
|
+
killProcessTree,
|
|
3387
3505
|
launchApp,
|
|
3388
3506
|
listAbilities,
|
|
3389
3507
|
listDevices,
|
|
3390
3508
|
listModules,
|
|
3391
3509
|
listRunningProcesses,
|
|
3392
3510
|
listTemplates,
|
|
3511
|
+
needsCmdWrapper,
|
|
3393
3512
|
nonInteractivePrompter,
|
|
3394
3513
|
noopLogger,
|
|
3395
3514
|
noopProgress,
|
|
@@ -3426,11 +3545,13 @@ export {
|
|
|
3426
3545
|
setHilogLevel,
|
|
3427
3546
|
shell,
|
|
3428
3547
|
shellChecked,
|
|
3548
|
+
spawnCompat,
|
|
3429
3549
|
startEmulator,
|
|
3430
3550
|
staticConfig,
|
|
3431
3551
|
stopEmulator,
|
|
3432
3552
|
streamHilog,
|
|
3433
3553
|
takeScreenshot,
|
|
3554
|
+
toLongPath,
|
|
3434
3555
|
toSpaceError,
|
|
3435
3556
|
uninstallApp,
|
|
3436
3557
|
validateTemplateLayout,
|