@oniroproject/core 0.15.1 → 0.16.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 +672 -358
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +107 -1
- package/dist/index.d.ts +107 -1
- package/dist/index.js +665 -357
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -45,6 +45,7 @@ __export(index_exports, {
|
|
|
45
45
|
OHOS_DAILY_BUILDS_URL: () => OHOS_DAILY_BUILDS_URL,
|
|
46
46
|
OHOS_URL_BASE: () => OHOS_URL_BASE,
|
|
47
47
|
OniroError: () => OniroError,
|
|
48
|
+
SIGNED_HAP_CHUNK_SIZE: () => SIGNED_HAP_CHUNK_SIZE,
|
|
48
49
|
SIGNING_ERRORS: () => SIGNING_ERRORS,
|
|
49
50
|
SdkNotInstalledError: () => SdkNotInstalledError,
|
|
50
51
|
TMP_DIR_HINT: () => TMP_DIR_HINT,
|
|
@@ -80,6 +81,7 @@ __export(index_exports, {
|
|
|
80
81
|
dedupEntries: () => dedupEntries,
|
|
81
82
|
defaultContext: () => defaultContext,
|
|
82
83
|
defaultPaths: () => defaultPaths,
|
|
84
|
+
defaultSignedHapPath: () => defaultSignedHapPath,
|
|
83
85
|
describeLayoutNode: () => describeLayoutNode,
|
|
84
86
|
detectAaStartFailure: () => detectAaStartFailure,
|
|
85
87
|
detectCmdToolsFlavour: () => detectCmdToolsFlavour,
|
|
@@ -146,6 +148,7 @@ __export(index_exports, {
|
|
|
146
148
|
getSupportedSdksForUi: () => getSupportedSdksForUi,
|
|
147
149
|
harmonyOsAutoSign: () => harmonyOsAutoSign,
|
|
148
150
|
harmonyOsSdkLabelForApi: () => harmonyOsSdkLabelForApi,
|
|
151
|
+
harmonyOsSignHap: () => harmonyOsSignHap,
|
|
149
152
|
hdcClientFailure: () => hdcClientFailure,
|
|
150
153
|
hdcExec: () => hdcExec,
|
|
151
154
|
hdcTargetArgs: () => hdcTargetArgs,
|
|
@@ -199,6 +202,7 @@ __export(index_exports, {
|
|
|
199
202
|
prepareSigning: () => prepareSigning,
|
|
200
203
|
pruneLayout: () => pruneLayout,
|
|
201
204
|
readHapBundleName: () => readHapBundleName,
|
|
205
|
+
readHapSigningInfo: () => readHapSigningInfo,
|
|
202
206
|
readJson5File: () => readJson5File,
|
|
203
207
|
readJsonFile: () => readJsonFile,
|
|
204
208
|
readProvisionProfile: () => readProvisionProfile,
|
|
@@ -226,6 +230,7 @@ __export(index_exports, {
|
|
|
226
230
|
setHilogLevel: () => setHilogLevel,
|
|
227
231
|
shell: () => shell,
|
|
228
232
|
shellChecked: () => shellChecked,
|
|
233
|
+
signOpenHarmonyHap: () => signOpenHarmonyHap,
|
|
229
234
|
spawnCompat: () => spawnCompat,
|
|
230
235
|
startEmulator: () => startEmulator,
|
|
231
236
|
staticConfig: () => staticConfig,
|
|
@@ -245,6 +250,7 @@ __export(index_exports, {
|
|
|
245
250
|
waitForTarget: () => waitForTarget,
|
|
246
251
|
watchLog: () => watchLog,
|
|
247
252
|
waypointsToRawEvents: () => waypointsToRawEvents,
|
|
253
|
+
withHapZip: () => withHapZip,
|
|
248
254
|
withoutWindow: () => withoutWindow,
|
|
249
255
|
writeJson5File: () => writeJson5File,
|
|
250
256
|
writeJsonFile: () => writeJsonFile
|
|
@@ -834,14 +840,14 @@ var pipelineAsync = (0, import_node_util.promisify)(import_node_stream.pipeline)
|
|
|
834
840
|
async function downloadFile(opts) {
|
|
835
841
|
const { url, dest, progress, abortSignal } = opts;
|
|
836
842
|
const proto = url.startsWith("https") ? https : http;
|
|
837
|
-
return new Promise((
|
|
843
|
+
return new Promise((resolve9, reject) => {
|
|
838
844
|
const s = Math.max(0, Math.min(100, opts.start ?? 0));
|
|
839
845
|
const r = Math.max(0, Math.min(100 - s, opts.range ?? 100));
|
|
840
846
|
let settled = false;
|
|
841
847
|
const done = (err) => {
|
|
842
848
|
if (settled) return;
|
|
843
849
|
settled = true;
|
|
844
|
-
err ? reject(err) :
|
|
850
|
+
err ? reject(err) : resolve9();
|
|
845
851
|
};
|
|
846
852
|
if (abortSignal?.aborted) {
|
|
847
853
|
done(new CancelledError("Download cancelled before start."));
|
|
@@ -1019,15 +1025,26 @@ async function extractZipWithProgress(opts) {
|
|
|
1019
1025
|
async function extractTarball(tarPath, dest, strip = 0, filter) {
|
|
1020
1026
|
await tar.x({ file: tarPath, cwd: dest, strip, ...filter ? { filter: (p) => filter(p) } : {} });
|
|
1021
1027
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1028
|
+
var SIGNED_HAP_CHUNK_SIZE = 128 * 1024;
|
|
1029
|
+
async function withHapZip(zipPath, use) {
|
|
1030
|
+
const zip = new import_node_stream_zip.default({ file: zipPath, chunkSize: SIGNED_HAP_CHUNK_SIZE, storeEntries: true });
|
|
1031
|
+
const close = () => new Promise((resolve9) => zip.close(() => resolve9()));
|
|
1024
1032
|
try {
|
|
1025
|
-
|
|
1026
|
-
|
|
1033
|
+
await new Promise((resolve9, reject) => {
|
|
1034
|
+
zip.once("ready", () => resolve9());
|
|
1035
|
+
zip.once("error", (err) => reject(err));
|
|
1036
|
+
});
|
|
1037
|
+
return await use({ entries: () => zip.entries(), entryData: (name) => zip.entryDataSync(name) });
|
|
1027
1038
|
} finally {
|
|
1028
|
-
await
|
|
1039
|
+
await close();
|
|
1029
1040
|
}
|
|
1030
1041
|
}
|
|
1042
|
+
function readZipEntry(zipPath, match) {
|
|
1043
|
+
return withHapZip(zipPath, (zip) => {
|
|
1044
|
+
const entry = Object.values(zip.entries()).find((e) => !e.isDirectory && match(e.name));
|
|
1045
|
+
return entry ? zip.entryData(entry.name) : void 0;
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1031
1048
|
|
|
1032
1049
|
// src/sdk/list.ts
|
|
1033
1050
|
var fs7 = __toESM(require("fs"), 1);
|
|
@@ -1678,9 +1695,16 @@ var SIGNING_KIND_CONFIG = {
|
|
|
1678
1695
|
certBasename: "OpenHarmonyApplication.cer"
|
|
1679
1696
|
}
|
|
1680
1697
|
};
|
|
1681
|
-
function
|
|
1682
|
-
|
|
1683
|
-
|
|
1698
|
+
function sdkSigningFiles(sdkPath) {
|
|
1699
|
+
return {
|
|
1700
|
+
signTool: path14.join(sdkPath, "toolchains/lib/hap-sign-tool.jar"),
|
|
1701
|
+
keystore: path14.join(sdkPath, "toolchains/lib/OpenHarmony.p12"),
|
|
1702
|
+
profileCert: path14.join(sdkPath, "toolchains/lib/OpenHarmonyProfileRelease.pem"),
|
|
1703
|
+
unsignedProfileTemplate: path14.join(sdkPath, "toolchains/lib/UnsgnedReleasedProfileTemplate.json")
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
function copySigningFiles(signaturesDir, paths, kind, logger, applicationCertPath) {
|
|
1707
|
+
logger.info(`[sign] Copying signing material into ${signaturesDir}...`);
|
|
1684
1708
|
fs13.mkdirSync(signaturesDir, { recursive: true });
|
|
1685
1709
|
fs13.copyFileSync(paths.keystore, path14.join(signaturesDir, "OpenHarmony.p12"));
|
|
1686
1710
|
fs13.copyFileSync(paths.profileCert, path14.join(signaturesDir, "OpenHarmonyProfileRelease.pem"));
|
|
@@ -1707,10 +1731,7 @@ function extractLeafCertificate(chainPath) {
|
|
|
1707
1731
|
return parts[2].trim() + "\n-----END CERTIFICATE-----\n";
|
|
1708
1732
|
}
|
|
1709
1733
|
function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}) {
|
|
1710
|
-
const kind = options.kind ?? pickSigningKind(apl);
|
|
1711
|
-
logger.info(`[sign] Modifying profile template (apl=${apl}, app-feature=${appFeature}, kind=${kind})...`);
|
|
1712
1734
|
const appJsonPath = path14.join(projectDir, "AppScope/app.json5");
|
|
1713
|
-
const profileTemplatePath = path14.join(projectDir, "signatures/UnsgnedReleasedProfileTemplate.json");
|
|
1714
1735
|
if (!fs13.existsSync(appJsonPath)) {
|
|
1715
1736
|
throw new OniroError(`${appJsonPath} does not exist.`);
|
|
1716
1737
|
}
|
|
@@ -1720,26 +1741,28 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
|
|
|
1720
1741
|
} catch (e) {
|
|
1721
1742
|
throw new OniroError(`Error parsing ${appJsonPath}: ${e.message}`, e);
|
|
1722
1743
|
}
|
|
1744
|
+
if (!appJson.app?.bundleName) {
|
|
1745
|
+
throw new OniroError("app.json5 does not contain app.bundleName.");
|
|
1746
|
+
}
|
|
1747
|
+
applyProfileTemplate(path14.join(projectDir, "signatures"), appJson.app.bundleName, apl, appFeature, logger, options);
|
|
1748
|
+
}
|
|
1749
|
+
function applyProfileTemplate(signaturesDir, bundleName, apl, appFeature, logger, options = {}) {
|
|
1750
|
+
const kind = options.kind ?? pickSigningKind(apl);
|
|
1751
|
+
logger.info(`[sign] Modifying profile template (apl=${apl}, app-feature=${appFeature}, kind=${kind})...`);
|
|
1752
|
+
const profileTemplatePath = path14.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json");
|
|
1723
1753
|
let profileTemplate;
|
|
1724
1754
|
try {
|
|
1725
1755
|
profileTemplate = JSON.parse(fs13.readFileSync(profileTemplatePath, "utf-8"));
|
|
1726
1756
|
} catch (e) {
|
|
1727
1757
|
throw new OniroError(`Error parsing ${profileTemplatePath}: ${e.message}`, e);
|
|
1728
1758
|
}
|
|
1729
|
-
if (!appJson.app?.bundleName) {
|
|
1730
|
-
throw new OniroError("app.json5 does not contain app.bundleName.");
|
|
1731
|
-
}
|
|
1732
1759
|
if (!profileTemplate["bundle-info"]) {
|
|
1733
1760
|
throw new OniroError("UnsgnedReleasedProfileTemplate.json is missing the bundle-info section.");
|
|
1734
1761
|
}
|
|
1735
|
-
profileTemplate["bundle-info"]["bundle-name"] =
|
|
1762
|
+
profileTemplate["bundle-info"]["bundle-name"] = bundleName;
|
|
1736
1763
|
profileTemplate["bundle-info"]["apl"] = apl;
|
|
1737
1764
|
profileTemplate["bundle-info"]["app-feature"] = appFeature;
|
|
1738
|
-
const distCertChainPath = path14.join(
|
|
1739
|
-
projectDir,
|
|
1740
|
-
"signatures",
|
|
1741
|
-
SIGNING_KIND_CONFIG[kind].certBasename
|
|
1742
|
-
);
|
|
1765
|
+
const distCertChainPath = path14.join(signaturesDir, SIGNING_KIND_CONFIG[kind].certBasename);
|
|
1743
1766
|
profileTemplate["bundle-info"]["distribution-certificate"] = extractLeafCertificate(distCertChainPath);
|
|
1744
1767
|
if (options.acls !== void 0) {
|
|
1745
1768
|
profileTemplate.acls = profileTemplate.acls ?? {};
|
|
@@ -1750,9 +1773,8 @@ function modifyProfileTemplate(projectDir, apl, appFeature, logger, options = {}
|
|
|
1750
1773
|
}
|
|
1751
1774
|
fs13.writeFileSync(profileTemplatePath, JSON.stringify(profileTemplate, null, 2));
|
|
1752
1775
|
}
|
|
1753
|
-
function generateP7bFile(
|
|
1776
|
+
function generateP7bFile(signaturesDir, paths, logger, passwords) {
|
|
1754
1777
|
logger.info("[sign] Generating P7b profile via hap-sign-tool...");
|
|
1755
|
-
const signaturesDir = path14.join(projectDir, "signatures");
|
|
1756
1778
|
const profileTemplatePath = path14.join(signaturesDir, "UnsgnedReleasedProfileTemplate.json");
|
|
1757
1779
|
const outputProfilePath = path14.join(signaturesDir, "app1-profile.p7b");
|
|
1758
1780
|
const args = [
|
|
@@ -1876,30 +1898,201 @@ function generateSigningConfigs(options) {
|
|
|
1876
1898
|
if (!fs13.existsSync(sdkPath)) {
|
|
1877
1899
|
throw new SdkNotInstalledError(String(sdkVersion), sdkPath, ALL_SDKS.find((s) => s.api === String(sdkVersion))?.version);
|
|
1878
1900
|
}
|
|
1879
|
-
const paths =
|
|
1880
|
-
signTool: path14.join(sdkPath, "toolchains/lib/hap-sign-tool.jar"),
|
|
1881
|
-
keystore: path14.join(sdkPath, "toolchains/lib/OpenHarmony.p12"),
|
|
1882
|
-
profileCert: path14.join(sdkPath, "toolchains/lib/OpenHarmonyProfileRelease.pem"),
|
|
1883
|
-
unsignedProfileTemplate: path14.join(sdkPath, "toolchains/lib/UnsgnedReleasedProfileTemplate.json")
|
|
1884
|
-
};
|
|
1901
|
+
const paths = sdkSigningFiles(sdkPath);
|
|
1885
1902
|
const kind = pickSigningKind(apl);
|
|
1886
1903
|
const passwords = options.passwords ?? DEFAULT_PASSWORDS;
|
|
1887
1904
|
logger.info("[sign] Starting signing configuration generation...");
|
|
1888
|
-
|
|
1905
|
+
const signaturesDir = path14.join(projectDir, "signatures");
|
|
1906
|
+
copySigningFiles(signaturesDir, paths, kind, logger, options.applicationCertPath);
|
|
1889
1907
|
modifyProfileTemplate(projectDir, apl, appFeature, logger, {
|
|
1890
1908
|
kind,
|
|
1891
1909
|
acls: options.acls,
|
|
1892
1910
|
appPrivilegeCapabilities: options.appPrivilegeCapabilities
|
|
1893
1911
|
});
|
|
1894
|
-
generateP7bFile(
|
|
1912
|
+
generateP7bFile(signaturesDir, paths, logger, passwords);
|
|
1895
1913
|
prepareMaterialDirectory(projectDir, logger);
|
|
1896
1914
|
updateBuildProfile(projectDir, kind, logger, passwords);
|
|
1897
1915
|
logger.info("[sign] Signing configuration generated successfully.");
|
|
1898
1916
|
}
|
|
1899
1917
|
|
|
1900
|
-
// src/
|
|
1918
|
+
// src/sign/hapInfo.ts
|
|
1919
|
+
var crypto3 = __toESM(require("crypto"), 1);
|
|
1901
1920
|
var fs14 = __toESM(require("fs"), 1);
|
|
1902
1921
|
var path15 = __toESM(require("path"), 1);
|
|
1922
|
+
function parseHapModuleJson(text, hapPath) {
|
|
1923
|
+
let parsed;
|
|
1924
|
+
try {
|
|
1925
|
+
parsed = JSON.parse(text.replace(/^\uFEFF/, ""));
|
|
1926
|
+
} catch (err) {
|
|
1927
|
+
throw new OniroError(`The module.json in ${hapPath} is not valid JSON: ${err.message}`, err);
|
|
1928
|
+
}
|
|
1929
|
+
const bundleName = parsed.app?.bundleName;
|
|
1930
|
+
if (typeof bundleName !== "string" || !bundleName) {
|
|
1931
|
+
throw new OniroError(`The module.json in ${hapPath} names no app.bundleName.`);
|
|
1932
|
+
}
|
|
1933
|
+
const requested = Array.isArray(parsed.module?.requestPermissions) ? parsed.module.requestPermissions : [];
|
|
1934
|
+
const { compileSdkType, targetAPIVersion } = parsed.app ?? {};
|
|
1935
|
+
return {
|
|
1936
|
+
bundleName,
|
|
1937
|
+
requestedPermissions: requested.map((p) => p?.name).filter((n) => typeof n === "string" && n.length > 0),
|
|
1938
|
+
compileSdkType: typeof compileSdkType === "string" && compileSdkType ? compileSdkType : void 0,
|
|
1939
|
+
targetApiVersion: typeof targetAPIVersion === "number" ? targetAPIVersion : void 0
|
|
1940
|
+
};
|
|
1941
|
+
}
|
|
1942
|
+
async function readHapSigningInfo(hapPath) {
|
|
1943
|
+
if (!fs14.existsSync(hapPath)) throw new OniroError(`${hapPath} does not exist.`);
|
|
1944
|
+
let moduleJson;
|
|
1945
|
+
try {
|
|
1946
|
+
moduleJson = await readZipEntry(hapPath, (n) => n === "module.json");
|
|
1947
|
+
if (!moduleJson && await readZipEntry(hapPath, (n) => n === "config.json")) {
|
|
1948
|
+
throw new OniroError(
|
|
1949
|
+
`${hapPath} is an FA-model HAP (config.json, no module.json). Only stage-model HAPs can be signed without their project.`
|
|
1950
|
+
);
|
|
1951
|
+
}
|
|
1952
|
+
} catch (err) {
|
|
1953
|
+
if (err instanceof OniroError) throw err;
|
|
1954
|
+
throw new OniroError(`Could not read ${hapPath} as a HAP: ${err.message}`, err);
|
|
1955
|
+
}
|
|
1956
|
+
if (!moduleJson) throw new OniroError(`${hapPath} holds no module.json, so it is not a HAP.`);
|
|
1957
|
+
return parseHapModuleJson(moduleJson.toString("utf8"), hapPath);
|
|
1958
|
+
}
|
|
1959
|
+
function defaultSignedHapPath(hapPath) {
|
|
1960
|
+
const dir = path15.dirname(hapPath);
|
|
1961
|
+
const name = path15.basename(hapPath);
|
|
1962
|
+
if (/-signed\.hap$/i.test(name)) return path15.join(dir, name.replace(/-signed\.hap$/i, "-resigned.hap"));
|
|
1963
|
+
return path15.join(dir, `${name.replace(/(-unsigned)?\.hap$/i, "")}-signed.hap`);
|
|
1964
|
+
}
|
|
1965
|
+
async function writeHapAtomically(outPath, sign) {
|
|
1966
|
+
const dir = path15.dirname(outPath);
|
|
1967
|
+
try {
|
|
1968
|
+
fs14.mkdirSync(dir, { recursive: true });
|
|
1969
|
+
} catch (err) {
|
|
1970
|
+
throw new OniroError(`Cannot create ${dir} for the signed HAP: ${err.message}`, err);
|
|
1971
|
+
}
|
|
1972
|
+
const tmpPath = path15.join(dir, `.${path15.basename(outPath)}.${crypto3.randomBytes(4).toString("hex")}.tmp`);
|
|
1973
|
+
try {
|
|
1974
|
+
await sign(tmpPath);
|
|
1975
|
+
fs14.renameSync(tmpPath, outPath);
|
|
1976
|
+
} finally {
|
|
1977
|
+
fs14.rmSync(tmpPath, { force: true });
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
// src/sign/signHap.ts
|
|
1982
|
+
var fs15 = __toESM(require("fs"), 1);
|
|
1983
|
+
var os8 = __toESM(require("os"), 1);
|
|
1984
|
+
var path16 = __toESM(require("path"), 1);
|
|
1985
|
+
var import_node_child_process4 = require("child_process");
|
|
1986
|
+
|
|
1987
|
+
// src/project/validators.ts
|
|
1988
|
+
function isValidProjectName(name) {
|
|
1989
|
+
if (!name) return false;
|
|
1990
|
+
if (name.includes("/") || name.includes("\\")) return false;
|
|
1991
|
+
return /^[A-Za-z0-9._-]+$/.test(name);
|
|
1992
|
+
}
|
|
1993
|
+
function isValidBundleName(bundleName) {
|
|
1994
|
+
return /^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)+$/.test(bundleName);
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
// src/sign/signHap.ts
|
|
1998
|
+
function pickSigningSdk(sdkHome, targetApiVersion) {
|
|
1999
|
+
let apis;
|
|
2000
|
+
try {
|
|
2001
|
+
apis = fs15.readdirSync(sdkHome).filter((api2) => /^\d+$/.test(api2));
|
|
2002
|
+
} catch {
|
|
2003
|
+
return null;
|
|
2004
|
+
}
|
|
2005
|
+
const usable = apis.filter((api2) => fs15.existsSync(sdkSigningFiles(path16.join(sdkHome, api2)).signTool)).sort((a, b) => Number(b) - Number(a));
|
|
2006
|
+
const api = usable.find((a) => targetApiVersion !== void 0 && Number(a) === targetApiVersion) ?? usable[0];
|
|
2007
|
+
return api ? { api, sdkPath: path16.join(sdkHome, api) } : null;
|
|
2008
|
+
}
|
|
2009
|
+
async function signOpenHarmonyHap(opts) {
|
|
2010
|
+
const logger = opts.logger ?? noopLogger;
|
|
2011
|
+
const hapPath = path16.resolve(opts.hapPath);
|
|
2012
|
+
const outPath = path16.resolve(opts.outPath ?? defaultSignedHapPath(hapPath));
|
|
2013
|
+
const apl = opts.apl ?? "normal";
|
|
2014
|
+
if (!APL_VALUES.includes(apl)) {
|
|
2015
|
+
throw new OniroError(`Invalid apl '${apl}'. Expected one of: ${APL_VALUES.join(", ")}.`);
|
|
2016
|
+
}
|
|
2017
|
+
const appFeature = resolveAppFeature(apl, opts.appFeature);
|
|
2018
|
+
if (!APP_FEATURE_VALUES.includes(appFeature)) {
|
|
2019
|
+
throw new OniroError(`Invalid appFeature '${appFeature}'. Expected one of: ${APP_FEATURE_VALUES.join(", ")}.`);
|
|
2020
|
+
}
|
|
2021
|
+
const info = await readHapSigningInfo(hapPath);
|
|
2022
|
+
if (info.compileSdkType === "HarmonyOS") {
|
|
2023
|
+
throw new OniroError(
|
|
2024
|
+
`${hapPath} was built for HarmonyOS, which needs a certificate from AppGallery Connect: run \`oniro-app auth login\` once, then \`oniro-app sign --harmonyos --hap\`.`
|
|
2025
|
+
);
|
|
2026
|
+
}
|
|
2027
|
+
if (!isValidBundleName(info.bundleName)) {
|
|
2028
|
+
throw new OniroError(`${hapPath} names an invalid bundle name '${info.bundleName}'.`);
|
|
2029
|
+
}
|
|
2030
|
+
const sdk = pickSigningSdk(opts.sdkHome, info.targetApiVersion);
|
|
2031
|
+
if (!sdk) {
|
|
2032
|
+
throw new OniroError(
|
|
2033
|
+
`No OpenHarmony SDK with hap-sign-tool.jar under ${opts.sdkHome}; install one with \`oniro-app sdk install\`.`
|
|
2034
|
+
);
|
|
2035
|
+
}
|
|
2036
|
+
const files = sdkSigningFiles(sdk.sdkPath);
|
|
2037
|
+
const kind = pickSigningKind(apl);
|
|
2038
|
+
const passwords = opts.passwords ?? DEFAULT_PASSWORDS;
|
|
2039
|
+
logger.info(`[sign] Signing ${path16.basename(hapPath)} as ${info.bundleName} with the API ${sdk.api} SDK's material...`);
|
|
2040
|
+
const signaturesDir = fs15.mkdtempSync(path16.join(os8.tmpdir(), "oniro-sign-hap-"));
|
|
2041
|
+
try {
|
|
2042
|
+
copySigningFiles(signaturesDir, files, kind, logger, opts.applicationCertPath);
|
|
2043
|
+
applyProfileTemplate(signaturesDir, info.bundleName, apl, appFeature, logger, {
|
|
2044
|
+
kind,
|
|
2045
|
+
acls: opts.acls,
|
|
2046
|
+
appPrivilegeCapabilities: opts.appPrivilegeCapabilities
|
|
2047
|
+
});
|
|
2048
|
+
generateP7bFile(signaturesDir, files, logger, passwords);
|
|
2049
|
+
logger.info("[sign] Signing the HAP via hap-sign-tool...");
|
|
2050
|
+
const { hapKeyAlias, certBasename } = SIGNING_KIND_CONFIG[kind];
|
|
2051
|
+
await writeHapAtomically(outPath, (tmpPath) => {
|
|
2052
|
+
const args = [
|
|
2053
|
+
"-jar",
|
|
2054
|
+
files.signTool,
|
|
2055
|
+
"sign-app",
|
|
2056
|
+
"-mode",
|
|
2057
|
+
"localSign",
|
|
2058
|
+
"-keyAlias",
|
|
2059
|
+
hapKeyAlias,
|
|
2060
|
+
"-signAlg",
|
|
2061
|
+
"SHA256withECDSA",
|
|
2062
|
+
"-appCertFile",
|
|
2063
|
+
path16.join(signaturesDir, certBasename),
|
|
2064
|
+
"-profileFile",
|
|
2065
|
+
path16.join(signaturesDir, "app1-profile.p7b"),
|
|
2066
|
+
"-inFile",
|
|
2067
|
+
hapPath,
|
|
2068
|
+
"-outFile",
|
|
2069
|
+
tmpPath,
|
|
2070
|
+
"-keystoreFile",
|
|
2071
|
+
path16.join(signaturesDir, "OpenHarmony.p12"),
|
|
2072
|
+
"-keyPwd",
|
|
2073
|
+
passwords.key,
|
|
2074
|
+
"-keystorePwd",
|
|
2075
|
+
passwords.store
|
|
2076
|
+
];
|
|
2077
|
+
try {
|
|
2078
|
+
(0, import_node_child_process4.execFileSync)("java", args, { stdio: "inherit" });
|
|
2079
|
+
} catch (e) {
|
|
2080
|
+
throw new OniroError(
|
|
2081
|
+
`hap-sign-tool failed to sign ${hapPath}. Ensure a JDK (with java) is on PATH. Underlying error: ${e.message}`,
|
|
2082
|
+
e
|
|
2083
|
+
);
|
|
2084
|
+
}
|
|
2085
|
+
});
|
|
2086
|
+
} finally {
|
|
2087
|
+
fs15.rmSync(signaturesDir, { recursive: true, force: true });
|
|
2088
|
+
}
|
|
2089
|
+
logger.info(`[sign] Wrote ${outPath}.`);
|
|
2090
|
+
return { bundleName: info.bundleName, outPath, sdkApi: sdk.api, kind };
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
// src/emulator/install.ts
|
|
2094
|
+
var fs16 = __toESM(require("fs"), 1);
|
|
2095
|
+
var path17 = __toESM(require("path"), 1);
|
|
1903
2096
|
async function installEmulator(opts) {
|
|
1904
2097
|
const { config, progress, abortSignal } = opts;
|
|
1905
2098
|
const logger = opts.logger ?? noopLogger;
|
|
@@ -1909,20 +2102,20 @@ async function installEmulator(opts) {
|
|
|
1909
2102
|
const { dir: tmpDir, root: tmpRoot } = createInstallTempDir({
|
|
1910
2103
|
config,
|
|
1911
2104
|
override: opts.tmpDir,
|
|
1912
|
-
installRoot:
|
|
2105
|
+
installRoot: path17.dirname(emulatorDir),
|
|
1913
2106
|
prefix: "oniro-emulator-",
|
|
1914
2107
|
logger
|
|
1915
2108
|
});
|
|
1916
|
-
const tmpZip =
|
|
2109
|
+
const tmpZip = path17.join(tmpDir, "oniro_emulator.zip");
|
|
1917
2110
|
try {
|
|
1918
|
-
|
|
2111
|
+
fs16.mkdirSync(emulatorDir, { recursive: true });
|
|
1919
2112
|
progress?.report({ message: "Downloading emulator...", increment: 0 });
|
|
1920
2113
|
await downloadFile({ url, dest: tmpZip, progress, abortSignal, start: 0, range: 50, what, tmpRoot });
|
|
1921
2114
|
progress?.report({ message: "Extracting emulator...", increment: 0 });
|
|
1922
2115
|
await extractZipWithProgress({ zipPath: tmpZip, dest: emulatorDir, progress, start: 50, range: 45, logger });
|
|
1923
|
-
const runSh =
|
|
1924
|
-
if (
|
|
1925
|
-
|
|
2116
|
+
const runSh = path17.join(emulatorDir, "images", "run.sh");
|
|
2117
|
+
if (fs16.existsSync(runSh)) {
|
|
2118
|
+
fs16.chmodSync(runSh, 493);
|
|
1926
2119
|
}
|
|
1927
2120
|
progress?.report({ message: "Finalizing installation...", increment: 5 });
|
|
1928
2121
|
} catch (err) {
|
|
@@ -1932,24 +2125,24 @@ async function installEmulator(opts) {
|
|
|
1932
2125
|
}
|
|
1933
2126
|
}
|
|
1934
2127
|
function isEmulatorInstalled(config) {
|
|
1935
|
-
const imagesDir =
|
|
1936
|
-
return
|
|
2128
|
+
const imagesDir = path17.join(getEmulatorDir(config), "images");
|
|
2129
|
+
return fs16.existsSync(path17.join(imagesDir, "run.sh")) || fs16.existsSync(path17.join(imagesDir, "run.bat"));
|
|
1937
2130
|
}
|
|
1938
2131
|
function removeEmulator(config) {
|
|
1939
2132
|
const emulatorDir = getEmulatorDir(config);
|
|
1940
|
-
if (
|
|
1941
|
-
|
|
2133
|
+
if (fs16.existsSync(emulatorDir)) {
|
|
2134
|
+
fs16.rmSync(emulatorDir, { recursive: true, force: true });
|
|
1942
2135
|
}
|
|
1943
2136
|
}
|
|
1944
2137
|
|
|
1945
2138
|
// src/emulator/lifecycle.ts
|
|
1946
|
-
var
|
|
1947
|
-
var
|
|
1948
|
-
var
|
|
1949
|
-
var
|
|
2139
|
+
var fs18 = __toESM(require("fs"), 1);
|
|
2140
|
+
var os9 = __toESM(require("os"), 1);
|
|
2141
|
+
var path18 = __toESM(require("path"), 1);
|
|
2142
|
+
var import_node_child_process5 = require("child_process");
|
|
1950
2143
|
|
|
1951
2144
|
// src/hdc/exec.ts
|
|
1952
|
-
var
|
|
2145
|
+
var fs17 = __toESM(require("fs"), 1);
|
|
1953
2146
|
var import_node_string_decoder = require("string_decoder");
|
|
1954
2147
|
function errorMessage(err) {
|
|
1955
2148
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -1958,12 +2151,12 @@ function runProcess(opts) {
|
|
|
1958
2151
|
const { command, args, cwd, env, onOutput } = opts;
|
|
1959
2152
|
const timeoutMs = opts.timeoutMs ?? 6e4;
|
|
1960
2153
|
const { abortSignal } = opts;
|
|
1961
|
-
return new Promise((
|
|
2154
|
+
return new Promise((resolve9, reject) => {
|
|
1962
2155
|
if (abortSignal?.aborted) {
|
|
1963
2156
|
reject(new CancelledError(`Command aborted before start: ${command}`));
|
|
1964
2157
|
return;
|
|
1965
2158
|
}
|
|
1966
|
-
if (needsCmdWrapper(command) && !
|
|
2159
|
+
if (needsCmdWrapper(command) && !fs17.existsSync(command)) {
|
|
1967
2160
|
reject(new OniroError(`Failed to spawn ${command}: ENOENT (no such file)`));
|
|
1968
2161
|
return;
|
|
1969
2162
|
}
|
|
@@ -2031,7 +2224,7 @@ ${stderr.trim()}` : "")
|
|
|
2031
2224
|
);
|
|
2032
2225
|
return;
|
|
2033
2226
|
}
|
|
2034
|
-
|
|
2227
|
+
resolve9({ code: code ?? -1, stdout, stderr });
|
|
2035
2228
|
});
|
|
2036
2229
|
});
|
|
2037
2230
|
}
|
|
@@ -2104,7 +2297,7 @@ function ensureRemoteOk(result, command) {
|
|
|
2104
2297
|
}
|
|
2105
2298
|
|
|
2106
2299
|
// src/emulator/lifecycle.ts
|
|
2107
|
-
var PID_FILE =
|
|
2300
|
+
var PID_FILE = path18.join(os9.tmpdir(), "oniro_emulator.pid");
|
|
2108
2301
|
async function attemptHdcConnection(config, address = "127.0.0.1:55555", logger = noopLogger) {
|
|
2109
2302
|
try {
|
|
2110
2303
|
await hdcExec({ config, args: ["start", "-r"], logger });
|
|
@@ -2117,24 +2310,24 @@ async function attemptHdcConnection(config, address = "127.0.0.1:55555", logger
|
|
|
2117
2310
|
}
|
|
2118
2311
|
}
|
|
2119
2312
|
function resolveLauncher(imagesPath, headless, connect) {
|
|
2120
|
-
const runSh =
|
|
2121
|
-
const runBat =
|
|
2313
|
+
const runSh = path18.join(imagesPath, "run.sh");
|
|
2314
|
+
const runBat = path18.join(imagesPath, "run.bat");
|
|
2122
2315
|
const extra = [];
|
|
2123
2316
|
if (headless) extra.push("--headless");
|
|
2124
2317
|
if (connect) extra.push("--connect", connect);
|
|
2125
|
-
if (
|
|
2126
|
-
if (
|
|
2318
|
+
if (os9.platform() === "win32") {
|
|
2319
|
+
if (fs18.existsSync(runBat)) {
|
|
2127
2320
|
return { command: "cmd.exe", args: ["/c", runBat, ...extra], cwd: imagesPath };
|
|
2128
2321
|
}
|
|
2129
|
-
if (
|
|
2322
|
+
if (fs18.existsSync(runSh)) {
|
|
2130
2323
|
return { command: "bash", args: [runSh, ...extra], cwd: imagesPath };
|
|
2131
2324
|
}
|
|
2132
2325
|
throw new OniroError(`No emulator launcher (run.bat or run.sh) found in ${imagesPath}.`);
|
|
2133
2326
|
}
|
|
2134
|
-
if (
|
|
2327
|
+
if (fs18.existsSync(runSh)) {
|
|
2135
2328
|
return { command: "bash", args: [runSh, ...extra], cwd: imagesPath };
|
|
2136
2329
|
}
|
|
2137
|
-
if (
|
|
2330
|
+
if (fs18.existsSync(runBat)) {
|
|
2138
2331
|
return { command: "bash", args: [runBat, ...extra], cwd: imagesPath };
|
|
2139
2332
|
}
|
|
2140
2333
|
throw new OniroError(`No emulator launcher (run.sh or run.bat) found in ${imagesPath}.`);
|
|
@@ -2142,9 +2335,9 @@ function resolveLauncher(imagesPath, headless, connect) {
|
|
|
2142
2335
|
async function startEmulator(opts) {
|
|
2143
2336
|
const { config } = opts;
|
|
2144
2337
|
const logger = opts.logger ?? noopLogger;
|
|
2145
|
-
if (
|
|
2338
|
+
if (os9.platform() !== "win32" && fs18.existsSync(PID_FILE)) {
|
|
2146
2339
|
try {
|
|
2147
|
-
const pid = Number(
|
|
2340
|
+
const pid = Number(fs18.readFileSync(PID_FILE, "utf8").trim());
|
|
2148
2341
|
if (Number.isFinite(pid) && pid > 0) {
|
|
2149
2342
|
try {
|
|
2150
2343
|
process.kill(pid, 0);
|
|
@@ -2160,35 +2353,35 @@ async function startEmulator(opts) {
|
|
|
2160
2353
|
logger.warn(`Could not read PID file: ${err.message}`);
|
|
2161
2354
|
}
|
|
2162
2355
|
}
|
|
2163
|
-
const imagesPath =
|
|
2164
|
-
if (!
|
|
2356
|
+
const imagesPath = path18.join(getEmulatorDir(config), "images");
|
|
2357
|
+
if (!fs18.existsSync(imagesPath)) {
|
|
2165
2358
|
throw new OniroError(`Emulator images directory not found at ${imagesPath}. Run \`oniro-app emulator install\` first.`);
|
|
2166
2359
|
}
|
|
2167
2360
|
const launcher = resolveLauncher(imagesPath, opts.headless === true, opts.connect);
|
|
2168
|
-
const logPath = opts.logFile ?? (
|
|
2169
|
-
const logFd =
|
|
2361
|
+
const logPath = opts.logFile ?? (os9.platform() === "win32" ? "NUL" : "/dev/null");
|
|
2362
|
+
const logFd = fs18.openSync(logPath, "a");
|
|
2170
2363
|
let child;
|
|
2171
2364
|
try {
|
|
2172
|
-
child = (0,
|
|
2365
|
+
child = (0, import_node_child_process5.spawn)(launcher.command, [...launcher.args], {
|
|
2173
2366
|
cwd: launcher.cwd,
|
|
2174
2367
|
detached: true,
|
|
2175
2368
|
stdio: ["ignore", logFd, logFd],
|
|
2176
2369
|
windowsHide: true
|
|
2177
2370
|
});
|
|
2178
2371
|
} finally {
|
|
2179
|
-
|
|
2372
|
+
fs18.closeSync(logFd);
|
|
2180
2373
|
}
|
|
2181
2374
|
if (!child.pid) {
|
|
2182
2375
|
throw new OniroError(`Failed to spawn launcher (${launcher.command} ${launcher.args.join(" ")}).`);
|
|
2183
2376
|
}
|
|
2184
|
-
|
|
2377
|
+
fs18.writeFileSync(PID_FILE, String(child.pid));
|
|
2185
2378
|
child.unref();
|
|
2186
2379
|
logger.info(`Emulator launched (PID ${child.pid}). Logs: ${logPath}`);
|
|
2187
|
-
const earlyExit = new Promise((
|
|
2188
|
-
child.once("exit", (code) =>
|
|
2189
|
-
child.once("error", () =>
|
|
2380
|
+
const earlyExit = new Promise((resolve9) => {
|
|
2381
|
+
child.once("exit", (code) => resolve9(code));
|
|
2382
|
+
child.once("error", () => resolve9(-1));
|
|
2190
2383
|
});
|
|
2191
|
-
const liveness = new Promise((
|
|
2384
|
+
const liveness = new Promise((resolve9) => setTimeout(() => resolve9("alive"), 2e3));
|
|
2192
2385
|
const outcome = await Promise.race([earlyExit, liveness]);
|
|
2193
2386
|
if (outcome !== "alive") {
|
|
2194
2387
|
const tail = readTail(logPath, 4e3);
|
|
@@ -2228,24 +2421,24 @@ ${tail}` : ""}`);
|
|
|
2228
2421
|
}
|
|
2229
2422
|
function readTail(filePath, bytes) {
|
|
2230
2423
|
try {
|
|
2231
|
-
const stat =
|
|
2424
|
+
const stat = fs18.statSync(filePath);
|
|
2232
2425
|
const start = Math.max(0, stat.size - bytes);
|
|
2233
|
-
const fd =
|
|
2426
|
+
const fd = fs18.openSync(filePath, "r");
|
|
2234
2427
|
try {
|
|
2235
2428
|
const buf = Buffer.alloc(stat.size - start);
|
|
2236
|
-
|
|
2429
|
+
fs18.readSync(fd, buf, 0, buf.length, start);
|
|
2237
2430
|
return buf.toString("utf8");
|
|
2238
2431
|
} finally {
|
|
2239
|
-
|
|
2432
|
+
fs18.closeSync(fd);
|
|
2240
2433
|
}
|
|
2241
2434
|
} catch {
|
|
2242
2435
|
return "";
|
|
2243
2436
|
}
|
|
2244
2437
|
}
|
|
2245
2438
|
async function stopEmulator(logger = noopLogger) {
|
|
2246
|
-
if (
|
|
2439
|
+
if (fs18.existsSync(PID_FILE)) {
|
|
2247
2440
|
try {
|
|
2248
|
-
const pid = Number(
|
|
2441
|
+
const pid = Number(fs18.readFileSync(PID_FILE, "utf8").trim());
|
|
2249
2442
|
if (Number.isFinite(pid) && pid > 0) {
|
|
2250
2443
|
try {
|
|
2251
2444
|
process.kill(pid, "SIGTERM");
|
|
@@ -2258,20 +2451,20 @@ async function stopEmulator(logger = noopLogger) {
|
|
|
2258
2451
|
logger.warn(`Could not read PID file: ${err.message}`);
|
|
2259
2452
|
}
|
|
2260
2453
|
}
|
|
2261
|
-
const [killCmd, ...killArgs] =
|
|
2454
|
+
const [killCmd, ...killArgs] = os9.platform() === "win32" ? ["taskkill", "/IM", "qemu-system-x86_64.exe", "/F"] : ["pkill", "-f", "qemu-system-x86_64"];
|
|
2262
2455
|
try {
|
|
2263
2456
|
await runProcess({ command: killCmd, args: killArgs, logger });
|
|
2264
2457
|
} catch (err) {
|
|
2265
2458
|
logger.warn(`[emulator] could not run ${killCmd}: ${err.message}`);
|
|
2266
2459
|
}
|
|
2267
|
-
|
|
2460
|
+
fs18.rm(PID_FILE, { force: true }, (err) => {
|
|
2268
2461
|
if (err) logger.warn(`Could not remove PID file: ${err.message}`);
|
|
2269
2462
|
});
|
|
2270
2463
|
}
|
|
2271
2464
|
async function isQemuRunning(logger) {
|
|
2272
|
-
if (
|
|
2465
|
+
if (os9.platform() !== "win32") {
|
|
2273
2466
|
try {
|
|
2274
|
-
const pid = Number(
|
|
2467
|
+
const pid = Number(fs18.readFileSync(PID_FILE, "utf8").trim());
|
|
2275
2468
|
if (Number.isFinite(pid) && pid > 0) {
|
|
2276
2469
|
process.kill(pid, 0);
|
|
2277
2470
|
return true;
|
|
@@ -2279,10 +2472,10 @@ async function isQemuRunning(logger) {
|
|
|
2279
2472
|
} catch {
|
|
2280
2473
|
}
|
|
2281
2474
|
}
|
|
2282
|
-
const [cmd, ...args] =
|
|
2475
|
+
const [cmd, ...args] = os9.platform() === "win32" ? ["tasklist", "/FI", "IMAGENAME eq qemu-system-x86_64.exe", "/NH"] : ["pgrep", "-f", "qemu-system-x86_64"];
|
|
2283
2476
|
try {
|
|
2284
2477
|
const res = await runProcess({ command: cmd, args, timeoutMs: 1e4, logger });
|
|
2285
|
-
return
|
|
2478
|
+
return os9.platform() === "win32" ? /qemu-system-x86_64/i.test(res.stdout) : res.code === 0;
|
|
2286
2479
|
} catch {
|
|
2287
2480
|
return false;
|
|
2288
2481
|
}
|
|
@@ -2407,11 +2600,11 @@ async function paramSet(config, key, value, opts = {}) {
|
|
|
2407
2600
|
}
|
|
2408
2601
|
|
|
2409
2602
|
// src/hdc/files.ts
|
|
2410
|
-
var
|
|
2603
|
+
var path19 = __toESM(require("path"), 1);
|
|
2411
2604
|
function normaliseLocalPath(local) {
|
|
2412
|
-
const abs =
|
|
2605
|
+
const abs = path19.resolve(local);
|
|
2413
2606
|
const long = toLongPath(abs);
|
|
2414
|
-
return long !== abs ? long :
|
|
2607
|
+
return long !== abs ? long : path19.join(toLongPath(path19.dirname(abs)), path19.basename(abs));
|
|
2415
2608
|
}
|
|
2416
2609
|
function assertDevicePath(remote) {
|
|
2417
2610
|
if (/^[A-Za-z]:[\\/]/.test(remote)) {
|
|
@@ -2430,13 +2623,13 @@ async function sendFile(opts) {
|
|
|
2430
2623
|
assertDevicePath(opts.remote);
|
|
2431
2624
|
const local = normaliseLocalPath(opts.local);
|
|
2432
2625
|
const sandbox = opts.bundle ? appSandboxDir(opts.bundle) : void 0;
|
|
2433
|
-
const remote = sandbox && !opts.remote.startsWith("/") ?
|
|
2626
|
+
const remote = sandbox && !opts.remote.startsWith("/") ? path19.posix.join(sandbox, opts.remote) : opts.remote;
|
|
2434
2627
|
if (sandbox && !remote.startsWith(`${sandbox}/`)) {
|
|
2435
2628
|
throw new OniroError(`${remote} is outside the sandbox of ${opts.bundle} (${sandbox}).`);
|
|
2436
2629
|
}
|
|
2437
2630
|
const device = { config: opts.config, deviceSerial: opts.deviceSerial, logger: opts.logger };
|
|
2438
2631
|
if (sandbox) {
|
|
2439
|
-
const mkdir = `mkdir -p ${shQuote(
|
|
2632
|
+
const mkdir = `mkdir -p ${shQuote(path19.posix.dirname(remote))}`;
|
|
2440
2633
|
ensureRemoteOk(await shellChecked({ ...device, command: mkdir }), `hdc shell ${mkdir}`);
|
|
2441
2634
|
}
|
|
2442
2635
|
const res = await hdcExec({
|
|
@@ -2448,7 +2641,7 @@ async function sendFile(opts) {
|
|
|
2448
2641
|
});
|
|
2449
2642
|
ensureOk(res, `hdc file send ${local} ${remote}`);
|
|
2450
2643
|
if (sandbox) {
|
|
2451
|
-
const top =
|
|
2644
|
+
const top = path19.posix.join(sandbox, path19.posix.relative(sandbox, remote).split("/")[0]);
|
|
2452
2645
|
const chown = `chown -R "$(stat -c %u:%g ${shQuote(sandbox)})" ${shQuote(top)}`;
|
|
2453
2646
|
ensureRemoteOk(await shellChecked({ ...device, command: chown }), `hdc shell ${chown}`);
|
|
2454
2647
|
}
|
|
@@ -2486,7 +2679,7 @@ async function getDisplaySize(config, opts = {}) {
|
|
|
2486
2679
|
|
|
2487
2680
|
// src/hdc/wait.ts
|
|
2488
2681
|
function delay(ms, signal) {
|
|
2489
|
-
return new Promise((
|
|
2682
|
+
return new Promise((resolve9, reject) => {
|
|
2490
2683
|
if (signal?.aborted) {
|
|
2491
2684
|
reject(new CancelledError("Wait cancelled."));
|
|
2492
2685
|
return;
|
|
@@ -2501,7 +2694,7 @@ function delay(ms, signal) {
|
|
|
2501
2694
|
};
|
|
2502
2695
|
const timer = setTimeout(() => {
|
|
2503
2696
|
cleanup();
|
|
2504
|
-
|
|
2697
|
+
resolve9();
|
|
2505
2698
|
}, ms);
|
|
2506
2699
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2507
2700
|
});
|
|
@@ -2530,18 +2723,18 @@ async function waitForCondition(opts) {
|
|
|
2530
2723
|
}
|
|
2531
2724
|
|
|
2532
2725
|
// src/hdc/app.ts
|
|
2533
|
-
var
|
|
2534
|
-
var
|
|
2726
|
+
var fs21 = __toESM(require("fs"), 1);
|
|
2727
|
+
var path22 = __toESM(require("path"), 1);
|
|
2535
2728
|
|
|
2536
2729
|
// src/build/discoverHaps.ts
|
|
2537
|
-
var
|
|
2538
|
-
var
|
|
2730
|
+
var fs19 = __toESM(require("fs"), 1);
|
|
2731
|
+
var path20 = __toESM(require("path"), 1);
|
|
2539
2732
|
function moduleOfHap(hapFileName) {
|
|
2540
2733
|
const dash = hapFileName.indexOf("-");
|
|
2541
2734
|
return dash > 0 ? hapFileName.slice(0, dash) : hapFileName.replace(/\.hap$/i, "");
|
|
2542
2735
|
}
|
|
2543
2736
|
function isAppProjectRoot(dir) {
|
|
2544
|
-
return
|
|
2737
|
+
return fs19.existsSync(path20.join(dir, "AppScope", "app.json5"));
|
|
2545
2738
|
}
|
|
2546
2739
|
async function discoverHaps(opts) {
|
|
2547
2740
|
const { projectDir } = opts;
|
|
@@ -2550,9 +2743,9 @@ async function discoverHaps(opts) {
|
|
|
2550
2743
|
const result = {};
|
|
2551
2744
|
const walk = async (dir, depth) => {
|
|
2552
2745
|
if (depth > maxDepth) return;
|
|
2553
|
-
const entries = await
|
|
2746
|
+
const entries = await fs19.promises.readdir(dir, { withFileTypes: true }).catch(() => []);
|
|
2554
2747
|
for (const e of entries) {
|
|
2555
|
-
const full =
|
|
2748
|
+
const full = path20.join(dir, e.name);
|
|
2556
2749
|
if (e.isDirectory()) {
|
|
2557
2750
|
if (e.name === "node_modules" || e.name === "oh_modules" || e.name === ".git") continue;
|
|
2558
2751
|
if (skipNestedProjects && isAppProjectRoot(full)) continue;
|
|
@@ -2566,7 +2759,7 @@ async function discoverHaps(opts) {
|
|
|
2566
2759
|
}
|
|
2567
2760
|
};
|
|
2568
2761
|
await walk(projectDir, 0);
|
|
2569
|
-
const mtime = (p) =>
|
|
2762
|
+
const mtime = (p) => fs19.statSync(p).mtimeMs;
|
|
2570
2763
|
for (const bucket of Object.values(result)) {
|
|
2571
2764
|
bucket.signed.sort((a, b) => mtime(b) - mtime(a));
|
|
2572
2765
|
bucket.unsigned.sort((a, b) => mtime(b) - mtime(a));
|
|
@@ -2592,16 +2785,16 @@ function pickHap(haps, module2) {
|
|
|
2592
2785
|
}
|
|
2593
2786
|
|
|
2594
2787
|
// src/hdc/project.ts
|
|
2595
|
-
var
|
|
2596
|
-
var
|
|
2788
|
+
var fs20 = __toESM(require("fs"), 1);
|
|
2789
|
+
var path21 = __toESM(require("path"), 1);
|
|
2597
2790
|
var import_json53 = __toESM(require("json5"), 1);
|
|
2598
2791
|
function readJson5(filePath) {
|
|
2599
|
-
const content =
|
|
2792
|
+
const content = fs20.readFileSync(filePath, "utf-8");
|
|
2600
2793
|
return import_json53.default.parse(content);
|
|
2601
2794
|
}
|
|
2602
2795
|
function getBundleName(projectDir) {
|
|
2603
|
-
const appJsonPath =
|
|
2604
|
-
if (!
|
|
2796
|
+
const appJsonPath = path21.join(projectDir, "AppScope", "app.json5");
|
|
2797
|
+
if (!fs20.existsSync(appJsonPath)) {
|
|
2605
2798
|
throw new OniroError(`Could not find app.json5 at ${appJsonPath}`);
|
|
2606
2799
|
}
|
|
2607
2800
|
const appJson = readJson5(appJsonPath);
|
|
@@ -2611,8 +2804,8 @@ function getBundleName(projectDir) {
|
|
|
2611
2804
|
return appJson.app.bundleName;
|
|
2612
2805
|
}
|
|
2613
2806
|
function getMainAbility(projectDir, moduleName = "entry", abilityName) {
|
|
2614
|
-
const moduleJsonPath =
|
|
2615
|
-
if (!
|
|
2807
|
+
const moduleJsonPath = path21.join(projectDir, moduleName, "src", "main", "module.json5");
|
|
2808
|
+
if (!fs20.existsSync(moduleJsonPath)) {
|
|
2616
2809
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
2617
2810
|
}
|
|
2618
2811
|
const moduleJson = readJson5(moduleJsonPath);
|
|
@@ -2636,7 +2829,7 @@ function detectInstallFailure(output) {
|
|
|
2636
2829
|
return /\[Fail\]|msg:\s*error|error:\s*failed to install|code:\s*95\d{5}/i.test(output) ? output.trim() : null;
|
|
2637
2830
|
}
|
|
2638
2831
|
function isUnsignedHap(hapPath) {
|
|
2639
|
-
return
|
|
2832
|
+
return path22.basename(hapPath).includes("unsigned");
|
|
2640
2833
|
}
|
|
2641
2834
|
function installFailureReason(output) {
|
|
2642
2835
|
const code = /code:\s*(\d+)/i.exec(output);
|
|
@@ -2645,7 +2838,7 @@ function installFailureReason(output) {
|
|
|
2645
2838
|
return message ? `code ${code[1]}: ${message}` : `code ${code[1]}`;
|
|
2646
2839
|
}
|
|
2647
2840
|
function unsignedHapRejection(output, hap) {
|
|
2648
|
-
const name =
|
|
2841
|
+
const name = path22.basename(hap.path);
|
|
2649
2842
|
const reason = installFailureReason(output);
|
|
2650
2843
|
const what = hap.fallback ? `No signed HAP was found, so the unsigned ${name} was tried, and the target rejected it (${reason}).` : `The target rejected the unsigned ${name} (${reason}).`;
|
|
2651
2844
|
if (!/9568320|signature|pkcs7/i.test(reason)) return what;
|
|
@@ -2663,24 +2856,24 @@ ${result.stderr}`;
|
|
|
2663
2856
|
return result;
|
|
2664
2857
|
}
|
|
2665
2858
|
function existingHapOrUnsigned(hapPath) {
|
|
2666
|
-
if (
|
|
2859
|
+
if (fs21.existsSync(hapPath)) return { path: hapPath };
|
|
2667
2860
|
const sibling = hapPath.replace(/-signed\.hap$/i, "-unsigned.hap");
|
|
2668
|
-
return sibling !== hapPath &&
|
|
2861
|
+
return sibling !== hapPath && fs21.existsSync(sibling) ? { path: sibling, fallback: true } : void 0;
|
|
2669
2862
|
}
|
|
2670
2863
|
async function resolveInstallHap(opts, logger) {
|
|
2671
2864
|
const warnIfFallback = (hap) => {
|
|
2672
|
-
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${
|
|
2865
|
+
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path22.basename(hap.path)}.`);
|
|
2673
2866
|
return hap;
|
|
2674
2867
|
};
|
|
2675
2868
|
const configured = opts.hapPath ?? opts.config.get("hapPath", "");
|
|
2676
2869
|
const relative3 = configured || defaultPaths.hapPath;
|
|
2677
|
-
const hapPath =
|
|
2870
|
+
const hapPath = path22.isAbsolute(relative3) ? relative3 : path22.join(opts.projectDir, relative3);
|
|
2678
2871
|
if (configured) {
|
|
2679
2872
|
const hap = existingHapOrUnsigned(hapPath);
|
|
2680
2873
|
if (!hap) throw new OniroError(`HAP file not found at: ${hapPath}. Build the app first.`);
|
|
2681
2874
|
return warnIfFallback(hap);
|
|
2682
2875
|
}
|
|
2683
|
-
if (
|
|
2876
|
+
if (fs21.existsSync(hapPath)) return { path: hapPath };
|
|
2684
2877
|
const haps = await discoverHaps({ projectDir: opts.projectDir });
|
|
2685
2878
|
const anySigned = Object.values(haps).some((m) => m.signed.length > 0);
|
|
2686
2879
|
const entryUnsigned = anySigned ? void 0 : existingHapOrUnsigned(hapPath);
|
|
@@ -2791,7 +2984,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2791
2984
|
const logger = options.logger ?? noopLogger;
|
|
2792
2985
|
const timeoutMs = options.timeoutMs ?? 1e3;
|
|
2793
2986
|
const hdc = getHdcPath(config);
|
|
2794
|
-
return new Promise((
|
|
2987
|
+
return new Promise((resolve9, reject) => {
|
|
2795
2988
|
let proc;
|
|
2796
2989
|
try {
|
|
2797
2990
|
proc = spawnCompat(hdc, [...hdcTargetArgs(options.deviceSerial), "track-jpid"]);
|
|
@@ -2811,7 +3004,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2811
3004
|
if (options.targetProcessName && name === options.targetProcessName && !resolved) {
|
|
2812
3005
|
resolved = true;
|
|
2813
3006
|
killProcessTree(proc);
|
|
2814
|
-
|
|
3007
|
+
resolve9(pid);
|
|
2815
3008
|
return;
|
|
2816
3009
|
}
|
|
2817
3010
|
}
|
|
@@ -2832,7 +3025,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2832
3025
|
if (options.targetProcessName) {
|
|
2833
3026
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
2834
3027
|
} else {
|
|
2835
|
-
|
|
3028
|
+
resolve9(processes);
|
|
2836
3029
|
}
|
|
2837
3030
|
}, timeoutMs);
|
|
2838
3031
|
proc.on("close", () => {
|
|
@@ -2842,7 +3035,7 @@ function listRunningProcesses(config, options = {}) {
|
|
|
2842
3035
|
if (options.targetProcessName) {
|
|
2843
3036
|
reject(new OniroError(`Could not find process for bundle: ${options.targetProcessName}`));
|
|
2844
3037
|
} else {
|
|
2845
|
-
|
|
3038
|
+
resolve9(processes);
|
|
2846
3039
|
}
|
|
2847
3040
|
});
|
|
2848
3041
|
});
|
|
@@ -3011,12 +3204,12 @@ async function reboot(opts) {
|
|
|
3011
3204
|
}
|
|
3012
3205
|
|
|
3013
3206
|
// src/hdc/screen.ts
|
|
3014
|
-
var
|
|
3015
|
-
var
|
|
3016
|
-
var
|
|
3207
|
+
var fs22 = __toESM(require("fs"), 1);
|
|
3208
|
+
var os10 = __toESM(require("os"), 1);
|
|
3209
|
+
var path23 = __toESM(require("path"), 1);
|
|
3017
3210
|
var import_node_crypto = require("crypto");
|
|
3018
3211
|
function tmpName(ext) {
|
|
3019
|
-
return
|
|
3212
|
+
return path23.join(os10.tmpdir(), `oniro_screen_${(0, import_node_crypto.randomBytes)(6).toString("hex")}.${ext}`);
|
|
3020
3213
|
}
|
|
3021
3214
|
async function takeScreenshot(opts) {
|
|
3022
3215
|
const remote = "/data/local/tmp/oniro_screenshot.jpeg";
|
|
@@ -3026,11 +3219,11 @@ async function takeScreenshot(opts) {
|
|
|
3026
3219
|
const local = tmpName("jpeg");
|
|
3027
3220
|
try {
|
|
3028
3221
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
3029
|
-
const pixels = await
|
|
3222
|
+
const pixels = await fs22.promises.readFile(local);
|
|
3030
3223
|
const size = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial }) ?? { width: 0, height: 0 };
|
|
3031
3224
|
return { pixels, width: size.width, height: size.height };
|
|
3032
3225
|
} finally {
|
|
3033
|
-
|
|
3226
|
+
fs22.promises.unlink(local).catch(() => {
|
|
3034
3227
|
});
|
|
3035
3228
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
3036
3229
|
});
|
|
@@ -3049,9 +3242,9 @@ async function captureBurst(opts) {
|
|
|
3049
3242
|
const local = tmpName(`burst_${i}.jpeg`);
|
|
3050
3243
|
try {
|
|
3051
3244
|
await recvFile({ config: opts.config, remote: `${remoteDir}/f${i}.jpeg`, local, deviceSerial: opts.deviceSerial });
|
|
3052
|
-
frames.push(await
|
|
3245
|
+
frames.push(await fs22.promises.readFile(local));
|
|
3053
3246
|
} finally {
|
|
3054
|
-
|
|
3247
|
+
fs22.promises.unlink(local).catch(() => {
|
|
3055
3248
|
});
|
|
3056
3249
|
}
|
|
3057
3250
|
}
|
|
@@ -3226,9 +3419,9 @@ async function sendRawTouch(opts) {
|
|
|
3226
3419
|
}
|
|
3227
3420
|
|
|
3228
3421
|
// src/hdc/dump.ts
|
|
3229
|
-
var
|
|
3230
|
-
var
|
|
3231
|
-
var
|
|
3422
|
+
var fs23 = __toESM(require("fs"), 1);
|
|
3423
|
+
var os11 = __toESM(require("os"), 1);
|
|
3424
|
+
var path24 = __toESM(require("path"), 1);
|
|
3232
3425
|
var import_node_crypto2 = require("crypto");
|
|
3233
3426
|
|
|
3234
3427
|
// src/hdc/ime.ts
|
|
@@ -3491,10 +3684,10 @@ async function dumpLayout(opts) {
|
|
|
3491
3684
|
if (!m) throw new OniroError(`Could not parse dumpLayout output:
|
|
3492
3685
|
${dump.stdout}`);
|
|
3493
3686
|
const remote = m[1];
|
|
3494
|
-
const local =
|
|
3687
|
+
const local = path24.join(os11.tmpdir(), `oniro_layout_${(0, import_node_crypto2.randomBytes)(6).toString("hex")}.json`);
|
|
3495
3688
|
try {
|
|
3496
3689
|
await recvFile({ config: opts.config, remote, local, deviceSerial: opts.deviceSerial, timeoutMs });
|
|
3497
|
-
const parsed = JSON.parse(await
|
|
3690
|
+
const parsed = JSON.parse(await fs23.promises.readFile(local, "utf8"));
|
|
3498
3691
|
const display = await getDisplaySize(opts.config, { deviceSerial: opts.deviceSerial });
|
|
3499
3692
|
if (opts.prune === false) {
|
|
3500
3693
|
return { display, tree: parsed };
|
|
@@ -3507,7 +3700,7 @@ ${dump.stdout}`);
|
|
|
3507
3700
|
const keyboard = kb ? { shown: true, bundle: kb.bundle, ...kb.b ? { b: kb.b } : {} } : { shown: false };
|
|
3508
3701
|
return { display, tree, keyboard };
|
|
3509
3702
|
} finally {
|
|
3510
|
-
|
|
3703
|
+
fs23.promises.unlink(local).catch(() => {
|
|
3511
3704
|
});
|
|
3512
3705
|
void shell({ config: opts.config, command: `rm -f ${remote}`, deviceSerial: opts.deviceSerial }).catch(() => {
|
|
3513
3706
|
});
|
|
@@ -3517,7 +3710,7 @@ ${dump.stdout}`);
|
|
|
3517
3710
|
// src/hdc/uiActions.ts
|
|
3518
3711
|
var FOCUS_SETTLE_MS = 400;
|
|
3519
3712
|
var KEYBOARD_SETTLE_MS = 400;
|
|
3520
|
-
var sleep = (ms) => new Promise((
|
|
3713
|
+
var sleep = (ms) => new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
3521
3714
|
function targetTree(layout) {
|
|
3522
3715
|
const kb = layout.keyboard;
|
|
3523
3716
|
return kb?.shown && kb.bundle ? withoutWindow(layout.tree, kb.bundle) : layout.tree;
|
|
@@ -3670,11 +3863,11 @@ async function waitForTarget(opts) {
|
|
|
3670
3863
|
}
|
|
3671
3864
|
|
|
3672
3865
|
// src/hdc/hilog.ts
|
|
3673
|
-
var
|
|
3866
|
+
var fs24 = __toESM(require("fs"), 1);
|
|
3674
3867
|
function setHilogLevel(opts) {
|
|
3675
3868
|
const logger = opts.logger ?? noopLogger;
|
|
3676
3869
|
const hdc = getHdcPath(opts.config);
|
|
3677
|
-
return new Promise((
|
|
3870
|
+
return new Promise((resolve9, reject) => {
|
|
3678
3871
|
let child;
|
|
3679
3872
|
try {
|
|
3680
3873
|
child = spawnCompat(hdc, [...hdcTargetArgs(opts.deviceSerial), "shell", "hilog", "-b", opts.level]);
|
|
@@ -3694,7 +3887,7 @@ function setHilogLevel(opts) {
|
|
|
3694
3887
|
});
|
|
3695
3888
|
child.once("close", (code) => {
|
|
3696
3889
|
if (code === 0) {
|
|
3697
|
-
|
|
3890
|
+
resolve9();
|
|
3698
3891
|
} else {
|
|
3699
3892
|
const msg = stderr.trim() || `hdc shell hilog -b ${opts.level} exited with code ${code}`;
|
|
3700
3893
|
logger.error(`[hilog] ${msg}`);
|
|
@@ -3796,7 +3989,7 @@ async function recentEntryFilter(opts) {
|
|
|
3796
3989
|
};
|
|
3797
3990
|
}
|
|
3798
3991
|
function waitForLog(opts) {
|
|
3799
|
-
return new Promise((
|
|
3992
|
+
return new Promise((resolve9, reject) => {
|
|
3800
3993
|
const deadline = Date.now() + opts.timeoutMs;
|
|
3801
3994
|
let settled = false;
|
|
3802
3995
|
let child = null;
|
|
@@ -3817,7 +4010,7 @@ function waitForLog(opts) {
|
|
|
3817
4010
|
if (settled) return;
|
|
3818
4011
|
settled = true;
|
|
3819
4012
|
cleanup();
|
|
3820
|
-
|
|
4013
|
+
resolve9(entry);
|
|
3821
4014
|
};
|
|
3822
4015
|
const fail = (err) => {
|
|
3823
4016
|
if (settled) return;
|
|
@@ -3872,7 +4065,7 @@ function waitForLog(opts) {
|
|
|
3872
4065
|
});
|
|
3873
4066
|
}
|
|
3874
4067
|
function watchLog(opts) {
|
|
3875
|
-
return new Promise((
|
|
4068
|
+
return new Promise((resolve9, reject) => {
|
|
3876
4069
|
const matches = [];
|
|
3877
4070
|
let settled = false;
|
|
3878
4071
|
let child = null;
|
|
@@ -3891,7 +4084,7 @@ function watchLog(opts) {
|
|
|
3891
4084
|
if (settled) return;
|
|
3892
4085
|
settled = true;
|
|
3893
4086
|
cleanup();
|
|
3894
|
-
|
|
4087
|
+
resolve9(opts.dedup === false ? matches : dedupEntries(matches));
|
|
3895
4088
|
};
|
|
3896
4089
|
const onAbort = () => {
|
|
3897
4090
|
if (settled) return;
|
|
@@ -3936,11 +4129,11 @@ async function captureLog(opts) {
|
|
|
3936
4129
|
const res = await shell({ config: opts.config, command: "hilog -r", deviceSerial: opts.deviceSerial, timeoutMs: 1e4, logger });
|
|
3937
4130
|
ensureOk(res, "hdc shell hilog -r");
|
|
3938
4131
|
}
|
|
3939
|
-
const fd =
|
|
4132
|
+
const fd = fs24.openSync(opts.file, "a");
|
|
3940
4133
|
let lines = 0;
|
|
3941
4134
|
let reconnects = 0;
|
|
3942
4135
|
try {
|
|
3943
|
-
await new Promise((
|
|
4136
|
+
await new Promise((resolve9, reject) => {
|
|
3944
4137
|
const deadline = opts.durationMs !== void 0 ? Date.now() + opts.durationMs : Infinity;
|
|
3945
4138
|
let settled = false;
|
|
3946
4139
|
let child = null;
|
|
@@ -3949,7 +4142,7 @@ async function captureLog(opts) {
|
|
|
3949
4142
|
let open = true;
|
|
3950
4143
|
const write = (line) => {
|
|
3951
4144
|
if (!open || opts.pattern && !opts.pattern.test(line)) return;
|
|
3952
|
-
|
|
4145
|
+
fs24.writeSync(fd, `${line}
|
|
3953
4146
|
`);
|
|
3954
4147
|
lines++;
|
|
3955
4148
|
};
|
|
@@ -3970,7 +4163,7 @@ async function captureLog(opts) {
|
|
|
3970
4163
|
if (settled) return;
|
|
3971
4164
|
settled = true;
|
|
3972
4165
|
cleanup();
|
|
3973
|
-
|
|
4166
|
+
resolve9();
|
|
3974
4167
|
}
|
|
3975
4168
|
const fail = (err) => {
|
|
3976
4169
|
if (settled) return;
|
|
@@ -4014,7 +4207,7 @@ async function captureLog(opts) {
|
|
|
4014
4207
|
spawnStream();
|
|
4015
4208
|
});
|
|
4016
4209
|
} finally {
|
|
4017
|
-
|
|
4210
|
+
fs24.closeSync(fd);
|
|
4018
4211
|
}
|
|
4019
4212
|
return { file: opts.file, lines, reconnects };
|
|
4020
4213
|
}
|
|
@@ -4042,17 +4235,17 @@ async function dumpLog(opts) {
|
|
|
4042
4235
|
}
|
|
4043
4236
|
|
|
4044
4237
|
// src/build/runHvigorw.ts
|
|
4045
|
-
var
|
|
4046
|
-
var
|
|
4238
|
+
var fs26 = __toESM(require("fs"), 1);
|
|
4239
|
+
var path26 = __toESM(require("path"), 1);
|
|
4047
4240
|
|
|
4048
4241
|
// src/harmonyos/target.ts
|
|
4049
|
-
var
|
|
4050
|
-
var
|
|
4242
|
+
var fs25 = __toESM(require("fs"), 1);
|
|
4243
|
+
var path25 = __toESM(require("path"), 1);
|
|
4051
4244
|
var import_json54 = __toESM(require("json5"), 1);
|
|
4052
4245
|
function detectRuntimeOs(projectDir, productName) {
|
|
4053
4246
|
let products = [];
|
|
4054
4247
|
try {
|
|
4055
|
-
const parsed = import_json54.default.parse(
|
|
4248
|
+
const parsed = import_json54.default.parse(fs25.readFileSync(path25.join(projectDir, "build-profile.json5"), "utf-8"));
|
|
4056
4249
|
if (Array.isArray(parsed.app?.products)) products = parsed.app.products;
|
|
4057
4250
|
} catch {
|
|
4058
4251
|
return "OpenHarmony";
|
|
@@ -4093,7 +4286,7 @@ function runHvigorw(opts) {
|
|
|
4093
4286
|
const { config } = opts;
|
|
4094
4287
|
const projectDir = toLongPath(opts.projectDir);
|
|
4095
4288
|
const logger = opts.logger ?? noopLogger;
|
|
4096
|
-
if (!
|
|
4289
|
+
if (!fs26.existsSync(path26.join(projectDir, "build-profile.json5"))) {
|
|
4097
4290
|
throw new OniroError(`Not an OpenHarmony project: ${projectDir} (build-profile.json5 not found).`);
|
|
4098
4291
|
}
|
|
4099
4292
|
let hvigorw;
|
|
@@ -4105,24 +4298,24 @@ function runHvigorw(opts) {
|
|
|
4105
4298
|
hvigorw = resolved.startsWith(projectDir) ? resolved : findHarmonyOsTool(sdk, "hvigorw") ?? resolved;
|
|
4106
4299
|
logger.info(`[build] Building for HarmonyOS against the SDK at ${sdk.sdkPath}.`);
|
|
4107
4300
|
} else {
|
|
4108
|
-
if (!
|
|
4301
|
+
if (!fs26.existsSync(getCmdToolsPath(config))) {
|
|
4109
4302
|
throw new CmdToolsNotInstalledError(getCmdToolsPath(config));
|
|
4110
4303
|
}
|
|
4111
4304
|
sdkEnv = { OHOS_BASE_SDK_HOME: getOhosBaseSdkHome(config) };
|
|
4112
4305
|
hvigorw = getHvigorwPath(config, projectDir);
|
|
4113
4306
|
}
|
|
4114
|
-
if (!
|
|
4307
|
+
if (!fs26.existsSync(hvigorw)) {
|
|
4115
4308
|
throw new OniroError(`hvigorw wrapper not found at ${hvigorw}.`);
|
|
4116
4309
|
}
|
|
4117
4310
|
const args = buildHvigorwArgs(opts);
|
|
4118
4311
|
if (process.platform !== "win32") {
|
|
4119
4312
|
try {
|
|
4120
|
-
|
|
4313
|
+
fs26.chmodSync(hvigorw, 493);
|
|
4121
4314
|
} catch {
|
|
4122
4315
|
}
|
|
4123
4316
|
}
|
|
4124
4317
|
const env = { ...process.env, ...sdkEnv };
|
|
4125
|
-
return new Promise((
|
|
4318
|
+
return new Promise((resolve9, reject) => {
|
|
4126
4319
|
if (opts.abortSignal?.aborted) {
|
|
4127
4320
|
reject(new CancelledError("hvigorw build cancelled."));
|
|
4128
4321
|
return;
|
|
@@ -4166,15 +4359,15 @@ function runHvigorw(opts) {
|
|
|
4166
4359
|
settled = true;
|
|
4167
4360
|
cleanup();
|
|
4168
4361
|
const exitCode = code ?? 1;
|
|
4169
|
-
if (exitCode === 0)
|
|
4362
|
+
if (exitCode === 0) resolve9({ exitCode });
|
|
4170
4363
|
else reject(new OniroError(`hvigorw exited with code ${exitCode}`));
|
|
4171
4364
|
});
|
|
4172
4365
|
});
|
|
4173
4366
|
}
|
|
4174
4367
|
|
|
4175
4368
|
// src/build/ohpm.ts
|
|
4176
|
-
var
|
|
4177
|
-
var
|
|
4369
|
+
var fs27 = __toESM(require("fs"), 1);
|
|
4370
|
+
var path27 = __toESM(require("path"), 1);
|
|
4178
4371
|
function runOhpm(opts) {
|
|
4179
4372
|
return runProcess({
|
|
4180
4373
|
command: opts.ohpmPath ?? getOhpmPath(opts.config),
|
|
@@ -4187,7 +4380,7 @@ function runOhpm(opts) {
|
|
|
4187
4380
|
});
|
|
4188
4381
|
}
|
|
4189
4382
|
async function ensureOhModules(opts) {
|
|
4190
|
-
if (
|
|
4383
|
+
if (fs27.existsSync(path27.join(opts.projectDir, "oh_modules"))) {
|
|
4191
4384
|
return { installed: false };
|
|
4192
4385
|
}
|
|
4193
4386
|
const res = await runOhpm({
|
|
@@ -4204,8 +4397,8 @@ async function ensureOhModules(opts) {
|
|
|
4204
4397
|
}
|
|
4205
4398
|
|
|
4206
4399
|
// src/build/codelinter.ts
|
|
4207
|
-
var
|
|
4208
|
-
var
|
|
4400
|
+
var fs28 = __toESM(require("fs"), 1);
|
|
4401
|
+
var path28 = __toESM(require("path"), 1);
|
|
4209
4402
|
var FINDING_RE = /^(.*?):(\d+):(?:(\d+):)?\s*(error|warning|warn|suggestion|info)\b[:\s-]*(.*)$/i;
|
|
4210
4403
|
var TRAILING_CODE_RE = /[([]([\w@/.\-]+)[)\]]\s*$/;
|
|
4211
4404
|
var FILE_HEADER_RE = /^(.+\.\w+)\((\d+)\)$/;
|
|
@@ -4295,10 +4488,10 @@ function parseCodelinterFindings(output) {
|
|
|
4295
4488
|
var PROJECT_ROOT_FILES = [
|
|
4296
4489
|
["build-profile.json5"],
|
|
4297
4490
|
["hvigorfile.ts", "hvigorfile.js"],
|
|
4298
|
-
[
|
|
4491
|
+
[path28.join("hvigor", "hvigor-config.json5")]
|
|
4299
4492
|
];
|
|
4300
4493
|
function missingProjectRootFiles(projectDir) {
|
|
4301
|
-
return PROJECT_ROOT_FILES.filter((names) => !names.some((f) =>
|
|
4494
|
+
return PROJECT_ROOT_FILES.filter((names) => !names.some((f) => fs28.existsSync(path28.join(projectDir, f)))).map(
|
|
4302
4495
|
(names) => names[0]
|
|
4303
4496
|
);
|
|
4304
4497
|
}
|
|
@@ -4380,32 +4573,22 @@ ${hint}`, err);
|
|
|
4380
4573
|
return { exitCode, durationMs: Date.now() - start, discoveredHaps, warnings };
|
|
4381
4574
|
}
|
|
4382
4575
|
|
|
4383
|
-
// src/project/validators.ts
|
|
4384
|
-
function isValidProjectName(name) {
|
|
4385
|
-
if (!name) return false;
|
|
4386
|
-
if (name.includes("/") || name.includes("\\")) return false;
|
|
4387
|
-
return /^[A-Za-z0-9._-]+$/.test(name);
|
|
4388
|
-
}
|
|
4389
|
-
function isValidBundleName(bundleName) {
|
|
4390
|
-
return /^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)+$/.test(bundleName);
|
|
4391
|
-
}
|
|
4392
|
-
|
|
4393
4576
|
// src/project/templates.ts
|
|
4394
|
-
var
|
|
4395
|
-
var
|
|
4577
|
+
var fs29 = __toESM(require("fs"), 1);
|
|
4578
|
+
var path29 = __toESM(require("path"), 1);
|
|
4396
4579
|
function toHumanTemplateName(folderName) {
|
|
4397
4580
|
return folderName.replace(/([a-z])([A-Z])/g, "$1 $2");
|
|
4398
4581
|
}
|
|
4399
4582
|
function listTemplates(templateRoot) {
|
|
4400
|
-
if (!
|
|
4401
|
-
const entries =
|
|
4583
|
+
if (!fs29.existsSync(templateRoot)) return [];
|
|
4584
|
+
const entries = fs29.readdirSync(templateRoot, { withFileTypes: true });
|
|
4402
4585
|
return entries.filter((e) => e.isDirectory()).map((e) => {
|
|
4403
|
-
const dir =
|
|
4404
|
-
const metaPath =
|
|
4586
|
+
const dir = path29.join(templateRoot, e.name);
|
|
4587
|
+
const metaPath = path29.join(dir, "template.json");
|
|
4405
4588
|
let meta = {};
|
|
4406
|
-
if (
|
|
4589
|
+
if (fs29.existsSync(metaPath)) {
|
|
4407
4590
|
try {
|
|
4408
|
-
meta = JSON.parse(
|
|
4591
|
+
meta = JSON.parse(fs29.readFileSync(metaPath, "utf8"));
|
|
4409
4592
|
} catch {
|
|
4410
4593
|
}
|
|
4411
4594
|
}
|
|
@@ -4420,57 +4603,57 @@ function listTemplates(templateRoot) {
|
|
|
4420
4603
|
function validateTemplateLayout(templateDir, defaultModuleName) {
|
|
4421
4604
|
const required = [
|
|
4422
4605
|
"build-profile.json5",
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4606
|
+
path29.join("AppScope", "app.json5"),
|
|
4607
|
+
path29.join(defaultModuleName, "src", "main", "module.json5"),
|
|
4608
|
+
path29.join(defaultModuleName, "oh-package.json5"),
|
|
4426
4609
|
"hvigorfile.ts"
|
|
4427
4610
|
];
|
|
4428
|
-
return required.filter((rel) => !
|
|
4611
|
+
return required.filter((rel) => !fs29.existsSync(path29.join(templateDir, rel)));
|
|
4429
4612
|
}
|
|
4430
4613
|
|
|
4431
4614
|
// src/project/createScaffold.ts
|
|
4432
|
-
var
|
|
4433
|
-
var
|
|
4615
|
+
var fs31 = __toESM(require("fs"), 1);
|
|
4616
|
+
var path30 = __toESM(require("path"), 1);
|
|
4434
4617
|
|
|
4435
4618
|
// src/project/jsonHelpers.ts
|
|
4436
|
-
var
|
|
4619
|
+
var fs30 = __toESM(require("fs"), 1);
|
|
4437
4620
|
var import_json55 = __toESM(require("json5"), 1);
|
|
4438
4621
|
function readJson5File(filePath) {
|
|
4439
|
-
return import_json55.default.parse(
|
|
4622
|
+
return import_json55.default.parse(fs30.readFileSync(filePath, "utf8"));
|
|
4440
4623
|
}
|
|
4441
4624
|
function writeJson5File(filePath, value) {
|
|
4442
|
-
|
|
4625
|
+
fs30.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
4443
4626
|
}
|
|
4444
4627
|
function readJsonFile(filePath) {
|
|
4445
|
-
return JSON.parse(
|
|
4628
|
+
return JSON.parse(fs30.readFileSync(filePath, "utf8"));
|
|
4446
4629
|
}
|
|
4447
4630
|
function writeJsonFile(filePath, value) {
|
|
4448
|
-
|
|
4631
|
+
fs30.writeFileSync(filePath, JSON.stringify(value, null, 2) + "\n", "utf8");
|
|
4449
4632
|
}
|
|
4450
4633
|
|
|
4451
4634
|
// src/project/createScaffold.ts
|
|
4452
4635
|
var IGNORED_DIRS = /* @__PURE__ */ new Set(["oh_modules", "node_modules", "build", ".hvigor"]);
|
|
4453
4636
|
async function pathExists(p) {
|
|
4454
4637
|
try {
|
|
4455
|
-
await
|
|
4638
|
+
await fs31.promises.access(p);
|
|
4456
4639
|
return true;
|
|
4457
4640
|
} catch {
|
|
4458
4641
|
return false;
|
|
4459
4642
|
}
|
|
4460
4643
|
}
|
|
4461
4644
|
async function copyDirRecursive(srcDir, destDir) {
|
|
4462
|
-
await
|
|
4463
|
-
const entries = await
|
|
4645
|
+
await fs31.promises.mkdir(destDir, { recursive: true });
|
|
4646
|
+
const entries = await fs31.promises.readdir(srcDir, { withFileTypes: true });
|
|
4464
4647
|
for (const entry of entries) {
|
|
4465
|
-
const src =
|
|
4466
|
-
const dest =
|
|
4648
|
+
const src = path30.join(srcDir, entry.name);
|
|
4649
|
+
const dest = path30.join(destDir, entry.name);
|
|
4467
4650
|
if (entry.isDirectory()) {
|
|
4468
4651
|
await copyDirRecursive(src, dest);
|
|
4469
4652
|
} else if (entry.isSymbolicLink()) {
|
|
4470
4653
|
continue;
|
|
4471
4654
|
} else if (entry.isFile()) {
|
|
4472
4655
|
if (entry.name === "template.json") continue;
|
|
4473
|
-
await
|
|
4656
|
+
await fs31.promises.copyFile(src, dest);
|
|
4474
4657
|
}
|
|
4475
4658
|
}
|
|
4476
4659
|
}
|
|
@@ -4478,9 +4661,9 @@ async function normalizeJson5ToJson(projectDir, logger) {
|
|
|
4478
4661
|
const stack = [projectDir];
|
|
4479
4662
|
while (stack.length > 0) {
|
|
4480
4663
|
const currentDir = stack.pop();
|
|
4481
|
-
const entries = await
|
|
4664
|
+
const entries = await fs31.promises.readdir(currentDir, { withFileTypes: true });
|
|
4482
4665
|
for (const entry of entries) {
|
|
4483
|
-
const fullPath =
|
|
4666
|
+
const fullPath = path30.join(currentDir, entry.name);
|
|
4484
4667
|
if (entry.isDirectory()) {
|
|
4485
4668
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
4486
4669
|
stack.push(fullPath);
|
|
@@ -4502,23 +4685,23 @@ function toJavaPropertiesPath(p) {
|
|
|
4502
4685
|
function createOrUpdateLocalProperties(projectDir, sdkDir) {
|
|
4503
4686
|
const content = `sdk.dir=${toJavaPropertiesPath(sdkDir)}
|
|
4504
4687
|
`;
|
|
4505
|
-
|
|
4688
|
+
fs31.writeFileSync(path30.join(projectDir, "local.properties"), content, "utf8");
|
|
4506
4689
|
}
|
|
4507
4690
|
function renameIfExists(fromPath, toPath) {
|
|
4508
|
-
if (
|
|
4509
|
-
|
|
4691
|
+
if (fs31.existsSync(fromPath) && fromPath !== toPath) {
|
|
4692
|
+
fs31.renameSync(fromPath, toPath);
|
|
4510
4693
|
}
|
|
4511
4694
|
}
|
|
4512
4695
|
function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
4513
|
-
const appJsonPath =
|
|
4514
|
-
if (
|
|
4696
|
+
const appJsonPath = path30.join(projectDir, "AppScope", "app.json5");
|
|
4697
|
+
if (fs31.existsSync(appJsonPath)) {
|
|
4515
4698
|
const appJson = readJson5File(appJsonPath);
|
|
4516
4699
|
appJson.app = appJson.app ?? {};
|
|
4517
4700
|
appJson.app.bundleName = args.bundleName;
|
|
4518
4701
|
writeJson5File(appJsonPath, appJson);
|
|
4519
4702
|
}
|
|
4520
|
-
const stringsPath =
|
|
4521
|
-
if (
|
|
4703
|
+
const stringsPath = path30.join(projectDir, "AppScope", "resources", "base", "element", "string.json");
|
|
4704
|
+
if (fs31.existsSync(stringsPath)) {
|
|
4522
4705
|
const strings = readJsonFile(stringsPath);
|
|
4523
4706
|
if (Array.isArray(strings.string)) {
|
|
4524
4707
|
const appName = strings.string.find((s) => s.name === "app_name");
|
|
@@ -4526,8 +4709,8 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
4526
4709
|
}
|
|
4527
4710
|
writeJsonFile(stringsPath, strings);
|
|
4528
4711
|
}
|
|
4529
|
-
const buildProfilePath =
|
|
4530
|
-
if (
|
|
4712
|
+
const buildProfilePath = path30.join(projectDir, "build-profile.json5");
|
|
4713
|
+
if (fs31.existsSync(buildProfilePath)) {
|
|
4531
4714
|
const buildProfile = readJson5File(buildProfilePath);
|
|
4532
4715
|
buildProfile.app = buildProfile.app ?? {};
|
|
4533
4716
|
if (Array.isArray(buildProfile.app.products) && buildProfile.app.products.length > 0) {
|
|
@@ -4540,23 +4723,23 @@ function updateTemplateConfigs(projectDir, args, sdkBaseDir) {
|
|
|
4540
4723
|
}
|
|
4541
4724
|
writeJson5File(buildProfilePath, buildProfile);
|
|
4542
4725
|
}
|
|
4543
|
-
const moduleJsonPath =
|
|
4544
|
-
if (
|
|
4726
|
+
const moduleJsonPath = path30.join(projectDir, args.moduleName, "src", "main", "module.json5");
|
|
4727
|
+
if (fs31.existsSync(moduleJsonPath)) {
|
|
4545
4728
|
const moduleJson = readJson5File(moduleJsonPath);
|
|
4546
4729
|
moduleJson.module = moduleJson.module ?? {};
|
|
4547
4730
|
moduleJson.module.name = args.moduleName;
|
|
4548
4731
|
writeJson5File(moduleJsonPath, moduleJson);
|
|
4549
4732
|
}
|
|
4550
|
-
const moduleOhPackagePath =
|
|
4551
|
-
if (
|
|
4733
|
+
const moduleOhPackagePath = path30.join(projectDir, args.moduleName, "oh-package.json5");
|
|
4734
|
+
if (fs31.existsSync(moduleOhPackagePath)) {
|
|
4552
4735
|
const pkg = readJson5File(moduleOhPackagePath);
|
|
4553
4736
|
pkg.name = args.moduleName;
|
|
4554
4737
|
writeJson5File(moduleOhPackagePath, pkg);
|
|
4555
4738
|
}
|
|
4556
|
-
const vscodeDir =
|
|
4557
|
-
|
|
4739
|
+
const vscodeDir = path30.join(projectDir, ".vscode");
|
|
4740
|
+
fs31.mkdirSync(vscodeDir, { recursive: true });
|
|
4558
4741
|
const hapPath = `${args.moduleName}/build/default/outputs/default/${args.moduleName}-default-signed.hap`;
|
|
4559
|
-
writeJsonFile(
|
|
4742
|
+
writeJsonFile(path30.join(vscodeDir, "settings.json"), {
|
|
4560
4743
|
"oniro.hapPath": hapPath,
|
|
4561
4744
|
"files.associations": { "*.json5": "jsonc" }
|
|
4562
4745
|
});
|
|
@@ -4573,7 +4756,7 @@ async function createScaffold(opts) {
|
|
|
4573
4756
|
if (!opts.location || !await pathExists(opts.location)) {
|
|
4574
4757
|
throw new OniroError(`Location does not exist: ${opts.location}`);
|
|
4575
4758
|
}
|
|
4576
|
-
const templateDir =
|
|
4759
|
+
const templateDir = path30.join(opts.templateRoot, opts.templateId);
|
|
4577
4760
|
if (!await pathExists(templateDir)) {
|
|
4578
4761
|
throw new OniroError(`Template not found: ${templateDir}`);
|
|
4579
4762
|
}
|
|
@@ -4608,17 +4791,17 @@ async function createScaffold(opts) {
|
|
|
4608
4791
|
}
|
|
4609
4792
|
}
|
|
4610
4793
|
}
|
|
4611
|
-
const projectDir =
|
|
4794
|
+
const projectDir = path30.join(opts.location, opts.projectName);
|
|
4612
4795
|
if (await pathExists(projectDir)) {
|
|
4613
4796
|
if (!opts.overwrite) {
|
|
4614
4797
|
throw new OniroError(`Destination already exists: ${projectDir}. Pass overwrite: true to replace it.`);
|
|
4615
4798
|
}
|
|
4616
|
-
await
|
|
4799
|
+
await fs31.promises.rm(projectDir, { recursive: true, force: true });
|
|
4617
4800
|
}
|
|
4618
4801
|
logger.info(`[create] Scaffolding ${opts.templateId} at ${projectDir}`);
|
|
4619
4802
|
await copyDirRecursive(templateDir, projectDir);
|
|
4620
4803
|
if (moduleName !== defaultModuleName) {
|
|
4621
|
-
renameIfExists(
|
|
4804
|
+
renameIfExists(path30.join(projectDir, defaultModuleName), path30.join(projectDir, moduleName));
|
|
4622
4805
|
}
|
|
4623
4806
|
updateTemplateConfigs(
|
|
4624
4807
|
projectDir,
|
|
@@ -4635,11 +4818,11 @@ async function createScaffold(opts) {
|
|
|
4635
4818
|
}
|
|
4636
4819
|
|
|
4637
4820
|
// src/project/listModules.ts
|
|
4638
|
-
var
|
|
4639
|
-
var
|
|
4821
|
+
var fs32 = __toESM(require("fs"), 1);
|
|
4822
|
+
var path31 = __toESM(require("path"), 1);
|
|
4640
4823
|
function listModules(opts) {
|
|
4641
|
-
const buildProfile =
|
|
4642
|
-
if (!
|
|
4824
|
+
const buildProfile = path31.join(opts.projectDir, "build-profile.json5");
|
|
4825
|
+
if (!fs32.existsSync(buildProfile)) {
|
|
4643
4826
|
throw new OniroError(`build-profile.json5 not found at ${buildProfile}`);
|
|
4644
4827
|
}
|
|
4645
4828
|
const parsed = readJson5File(buildProfile);
|
|
@@ -4651,12 +4834,12 @@ function listModules(opts) {
|
|
|
4651
4834
|
}
|
|
4652
4835
|
|
|
4653
4836
|
// src/project/abilities.ts
|
|
4654
|
-
var
|
|
4655
|
-
var
|
|
4837
|
+
var fs33 = __toESM(require("fs"), 1);
|
|
4838
|
+
var path32 = __toESM(require("path"), 1);
|
|
4656
4839
|
function listAbilities(opts) {
|
|
4657
4840
|
const moduleName = opts.moduleName ?? "entry";
|
|
4658
|
-
const moduleJsonPath =
|
|
4659
|
-
if (!
|
|
4841
|
+
const moduleJsonPath = path32.join(opts.projectDir, moduleName, "src", "main", "module.json5");
|
|
4842
|
+
if (!fs33.existsSync(moduleJsonPath)) {
|
|
4660
4843
|
throw new OniroError(`Could not find module.json5 at ${moduleJsonPath}`);
|
|
4661
4844
|
}
|
|
4662
4845
|
const parsed = readJson5File(moduleJsonPath);
|
|
@@ -4664,12 +4847,12 @@ function listAbilities(opts) {
|
|
|
4664
4847
|
}
|
|
4665
4848
|
|
|
4666
4849
|
// src/project/prepareSigning.ts
|
|
4667
|
-
var
|
|
4668
|
-
var
|
|
4850
|
+
var fs34 = __toESM(require("fs"), 1);
|
|
4851
|
+
var path33 = __toESM(require("path"), 1);
|
|
4669
4852
|
function hasSigningArtifacts(dir) {
|
|
4670
|
-
if (!
|
|
4671
|
-
const buildProfile =
|
|
4672
|
-
if (!
|
|
4853
|
+
if (!fs34.existsSync(path33.join(dir, "signatures"))) return false;
|
|
4854
|
+
const buildProfile = path33.join(dir, "build-profile.json5");
|
|
4855
|
+
if (!fs34.existsSync(buildProfile)) return false;
|
|
4673
4856
|
try {
|
|
4674
4857
|
const parsed = readJson5File(buildProfile);
|
|
4675
4858
|
return Array.isArray(parsed.app?.signingConfigs) && parsed.app.signingConfigs.length > 0;
|
|
@@ -4748,7 +4931,6 @@ async function getDeviceInfo(opts) {
|
|
|
4748
4931
|
}
|
|
4749
4932
|
|
|
4750
4933
|
// src/install/diffHapAssets.ts
|
|
4751
|
-
var import_node_stream_zip2 = __toESM(require("node-stream-zip"), 1);
|
|
4752
4934
|
function diffEntryNames(installed, next) {
|
|
4753
4935
|
const installedSet = new Set(installed);
|
|
4754
4936
|
const nextSet = new Set(next);
|
|
@@ -4757,14 +4939,11 @@ function diffEntryNames(installed, next) {
|
|
|
4757
4939
|
removedAssetPaths: [...installedSet].filter((n) => !nextSet.has(n)).sort()
|
|
4758
4940
|
};
|
|
4759
4941
|
}
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
} finally {
|
|
4766
|
-
await zip.close();
|
|
4767
|
-
}
|
|
4942
|
+
function listFileEntries(hapPath) {
|
|
4943
|
+
return withHapZip(
|
|
4944
|
+
hapPath,
|
|
4945
|
+
(zip) => Object.values(zip.entries()).filter((e) => !e.isDirectory).map((e) => e.name)
|
|
4946
|
+
);
|
|
4768
4947
|
}
|
|
4769
4948
|
async function diffHapAssets(opts) {
|
|
4770
4949
|
const [installed, next] = await Promise.all([listFileEntries(opts.installedHap), listFileEntries(opts.newHap)]);
|
|
@@ -4772,8 +4951,8 @@ async function diffHapAssets(opts) {
|
|
|
4772
4951
|
}
|
|
4773
4952
|
|
|
4774
4953
|
// src/install/apply.ts
|
|
4775
|
-
var
|
|
4776
|
-
var
|
|
4954
|
+
var fs35 = __toESM(require("fs"), 1);
|
|
4955
|
+
var path34 = __toESM(require("path"), 1);
|
|
4777
4956
|
|
|
4778
4957
|
// src/install/hapBundleName.ts
|
|
4779
4958
|
function bundleNameFromHapConfig(text) {
|
|
@@ -4811,7 +4990,7 @@ async function pidOf(config, bundle, deviceSerial) {
|
|
|
4811
4990
|
async function resolveHap(opts, logger) {
|
|
4812
4991
|
let hap;
|
|
4813
4992
|
if (opts.hapPath) {
|
|
4814
|
-
const hapPath = !
|
|
4993
|
+
const hapPath = !path34.isAbsolute(opts.hapPath) && opts.projectDir ? path34.join(opts.projectDir, opts.hapPath) : opts.hapPath;
|
|
4815
4994
|
hap = existingHapOrUnsigned(hapPath);
|
|
4816
4995
|
if (!hap) throw new OniroError(`HAP not found at ${hapPath}.`);
|
|
4817
4996
|
} else {
|
|
@@ -4820,7 +4999,7 @@ async function resolveHap(opts, logger) {
|
|
|
4820
4999
|
if (!picked) throw new OniroError(`No HAP found${opts.module ? ` for module ${opts.module}` : ""}. Build first.`);
|
|
4821
5000
|
hap = { path: picked.path, fallback: !picked.signed };
|
|
4822
5001
|
}
|
|
4823
|
-
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${
|
|
5002
|
+
if (hap.fallback) logger.warn(`No signed HAP found; installing the unsigned ${path34.basename(hap.path)}.`);
|
|
4824
5003
|
return hap;
|
|
4825
5004
|
}
|
|
4826
5005
|
async function applyChanges(opts) {
|
|
@@ -4836,12 +5015,12 @@ async function applyChanges(opts) {
|
|
|
4836
5015
|
});
|
|
4837
5016
|
if (hapBundle && hapBundle !== bundle) {
|
|
4838
5017
|
throw new OniroError(
|
|
4839
|
-
`${
|
|
5018
|
+
`${path34.basename(hapPath)} (${hapPath}) is bundle ${hapBundle}, not ${bundle}, so installing it would not update ${bundle}. Choose the HAP explicitly, or name ${hapBundle} as the bundle if it is the app to update.`
|
|
4840
5019
|
);
|
|
4841
5020
|
}
|
|
4842
5021
|
logger.info(`installing ${hapPath}`);
|
|
4843
5022
|
let assetsChanged = false;
|
|
4844
|
-
if (opts.installedHapPath &&
|
|
5023
|
+
if (opts.installedHapPath && fs35.existsSync(opts.installedHapPath)) {
|
|
4845
5024
|
try {
|
|
4846
5025
|
const diff = await diffHapAssets({ installedHap: opts.installedHapPath, newHap: hapPath });
|
|
4847
5026
|
assetsChanged = diff.addedAssetPaths.length > 0 || diff.removedAssetPaths.length > 0;
|
|
@@ -4874,7 +5053,7 @@ async function applyChanges(opts) {
|
|
|
4874
5053
|
}
|
|
4875
5054
|
if (!await isBundleInstalled({ config, bundle, deviceSerial })) {
|
|
4876
5055
|
throw new OniroError(
|
|
4877
|
-
`hdc reported ${
|
|
5056
|
+
`hdc reported ${path34.basename(hapPath)} as installed, but bm dump does not list ${bundle}. Check that the HAP was built from this project (its bundleName must match).`
|
|
4878
5057
|
);
|
|
4879
5058
|
}
|
|
4880
5059
|
let postInstallPid = await pidOf(config, bundle, deviceSerial);
|
|
@@ -4951,10 +5130,10 @@ var AUTH_PATHS = {
|
|
|
4951
5130
|
};
|
|
4952
5131
|
|
|
4953
5132
|
// src/harmonyos/auth/tokenStore.ts
|
|
4954
|
-
var
|
|
4955
|
-
var
|
|
4956
|
-
var
|
|
4957
|
-
var
|
|
5133
|
+
var fs36 = __toESM(require("fs"), 1);
|
|
5134
|
+
var os12 = __toESM(require("os"), 1);
|
|
5135
|
+
var path35 = __toESM(require("path"), 1);
|
|
5136
|
+
var crypto4 = __toESM(require("crypto"), 1);
|
|
4958
5137
|
var ALGORITHM = "aes-256-gcm";
|
|
4959
5138
|
var KEY_LENGTH = 32;
|
|
4960
5139
|
var IV_LENGTH = 12;
|
|
@@ -4963,8 +5142,8 @@ var KEY_FILE = "kek.bin";
|
|
|
4963
5142
|
var DIR_MODE = 448;
|
|
4964
5143
|
var FILE_MODE = 384;
|
|
4965
5144
|
function encrypt2(key, plaintext) {
|
|
4966
|
-
const iv =
|
|
4967
|
-
const cipher =
|
|
5145
|
+
const iv = crypto4.randomBytes(IV_LENGTH);
|
|
5146
|
+
const cipher = crypto4.createCipheriv(ALGORITHM, key, iv);
|
|
4968
5147
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
4969
5148
|
return {
|
|
4970
5149
|
version: 1,
|
|
@@ -4975,7 +5154,7 @@ function encrypt2(key, plaintext) {
|
|
|
4975
5154
|
};
|
|
4976
5155
|
}
|
|
4977
5156
|
function decrypt2(key, blob) {
|
|
4978
|
-
const decipher =
|
|
5157
|
+
const decipher = crypto4.createDecipheriv(ALGORITHM, key, Buffer.from(blob.iv, "base64"));
|
|
4979
5158
|
decipher.setAuthTag(Buffer.from(blob.authTag, "base64"));
|
|
4980
5159
|
return Buffer.concat([decipher.update(Buffer.from(blob.ciphertext, "base64")), decipher.final()]);
|
|
4981
5160
|
}
|
|
@@ -4989,7 +5168,7 @@ function permissionHint(dir) {
|
|
|
4989
5168
|
}
|
|
4990
5169
|
function ensureDir(dir) {
|
|
4991
5170
|
try {
|
|
4992
|
-
|
|
5171
|
+
fs36.mkdirSync(dir, { recursive: true, mode: DIR_MODE });
|
|
4993
5172
|
} catch (err) {
|
|
4994
5173
|
if (err.code === "EACCES") {
|
|
4995
5174
|
throw new OniroError(permissionHint(dir), err);
|
|
@@ -5000,17 +5179,17 @@ function ensureDir(dir) {
|
|
|
5000
5179
|
function createTokenStore(opts) {
|
|
5001
5180
|
const logger = opts.logger ?? noopLogger;
|
|
5002
5181
|
const authDir = opts.config.get("harmonyosAuthDir", defaultPaths.harmonyosAuthDir());
|
|
5003
|
-
const tokenPath =
|
|
5004
|
-
const keyPath =
|
|
5182
|
+
const tokenPath = path35.join(authDir, TOKEN_FILE);
|
|
5183
|
+
const keyPath = path35.join(os12.homedir(), ".local", "share", "oniro-app", "keys", KEY_FILE);
|
|
5005
5184
|
function loadOrCreateKey() {
|
|
5006
|
-
if (
|
|
5007
|
-
const existing =
|
|
5185
|
+
if (fs36.existsSync(keyPath)) {
|
|
5186
|
+
const existing = fs36.readFileSync(keyPath);
|
|
5008
5187
|
if (existing.length === KEY_LENGTH) return existing;
|
|
5009
5188
|
logger.warn("[harmonyos] The token key file was malformed; regenerating (you will need to log in again).");
|
|
5010
5189
|
}
|
|
5011
|
-
ensureDir(
|
|
5012
|
-
const key =
|
|
5013
|
-
|
|
5190
|
+
ensureDir(path35.dirname(keyPath));
|
|
5191
|
+
const key = crypto4.randomBytes(KEY_LENGTH);
|
|
5192
|
+
fs36.writeFileSync(keyPath, key, { mode: FILE_MODE });
|
|
5014
5193
|
return key;
|
|
5015
5194
|
}
|
|
5016
5195
|
return {
|
|
@@ -5020,12 +5199,12 @@ function createTokenStore(opts) {
|
|
|
5020
5199
|
const payload = Buffer.from(JSON.stringify(session), "utf8");
|
|
5021
5200
|
const blob = encrypt2(loadOrCreateKey(), payload);
|
|
5022
5201
|
ensureDir(authDir);
|
|
5023
|
-
|
|
5202
|
+
fs36.writeFileSync(tokenPath, JSON.stringify(blob, null, 2), { mode: FILE_MODE });
|
|
5024
5203
|
},
|
|
5025
5204
|
load() {
|
|
5026
|
-
if (!
|
|
5205
|
+
if (!fs36.existsSync(tokenPath)) return null;
|
|
5027
5206
|
try {
|
|
5028
|
-
const blob = JSON.parse(
|
|
5207
|
+
const blob = JSON.parse(fs36.readFileSync(tokenPath, "utf8"));
|
|
5029
5208
|
if (!isEncryptedBlob(blob)) return null;
|
|
5030
5209
|
const { jwtToken, siteId } = JSON.parse(decrypt2(loadOrCreateKey(), blob).toString("utf8"));
|
|
5031
5210
|
return typeof jwtToken === "string" && jwtToken && typeof siteId === "string" ? { jwtToken, siteId } : null;
|
|
@@ -5037,7 +5216,7 @@ function createTokenStore(opts) {
|
|
|
5037
5216
|
}
|
|
5038
5217
|
logger.debug(`[harmonyos] Discarding unreadable token at ${tokenPath}.`);
|
|
5039
5218
|
try {
|
|
5040
|
-
|
|
5219
|
+
fs36.rmSync(tokenPath, { force: true });
|
|
5041
5220
|
} catch {
|
|
5042
5221
|
}
|
|
5043
5222
|
return null;
|
|
@@ -5045,7 +5224,7 @@ function createTokenStore(opts) {
|
|
|
5045
5224
|
},
|
|
5046
5225
|
clear() {
|
|
5047
5226
|
try {
|
|
5048
|
-
|
|
5227
|
+
fs36.rmSync(tokenPath, { force: true });
|
|
5049
5228
|
} catch (err) {
|
|
5050
5229
|
throw new OniroError(`Failed to remove ${tokenPath}.`, err);
|
|
5051
5230
|
}
|
|
@@ -5054,7 +5233,7 @@ function createTokenStore(opts) {
|
|
|
5054
5233
|
}
|
|
5055
5234
|
|
|
5056
5235
|
// src/harmonyos/auth/session.ts
|
|
5057
|
-
var
|
|
5236
|
+
var crypto6 = __toESM(require("crypto"), 1);
|
|
5058
5237
|
|
|
5059
5238
|
// src/harmonyos/http.ts
|
|
5060
5239
|
var import_undici = require("undici");
|
|
@@ -5145,13 +5324,13 @@ function createHttpClient(opts = {}) {
|
|
|
5145
5324
|
|
|
5146
5325
|
// src/harmonyos/auth/callbackServer.ts
|
|
5147
5326
|
var http2 = __toESM(require("http"), 1);
|
|
5148
|
-
var
|
|
5327
|
+
var crypto5 = __toESM(require("crypto"), 1);
|
|
5149
5328
|
var CALLBACK_PATH = "/callback";
|
|
5150
5329
|
var MAX_BODY_BYTES = 65536;
|
|
5151
5330
|
function codeMatches(code, secret) {
|
|
5152
5331
|
const a = Buffer.from(code ?? "", "utf8");
|
|
5153
5332
|
const b = Buffer.from(secret, "utf8");
|
|
5154
|
-
return a.length === b.length &&
|
|
5333
|
+
return a.length === b.length && crypto5.timingSafeEqual(a, b);
|
|
5155
5334
|
}
|
|
5156
5335
|
function isQuit(quit) {
|
|
5157
5336
|
return quit === "true" || quit === "access_denied" || quit === "quit";
|
|
@@ -5159,8 +5338,8 @@ function isQuit(quit) {
|
|
|
5159
5338
|
async function startCallbackServer(opts) {
|
|
5160
5339
|
let resolveCallback;
|
|
5161
5340
|
let rejectCallback;
|
|
5162
|
-
const callback = new Promise((
|
|
5163
|
-
resolveCallback =
|
|
5341
|
+
const callback = new Promise((resolve9, reject) => {
|
|
5342
|
+
resolveCallback = resolve9;
|
|
5164
5343
|
rejectCallback = reject;
|
|
5165
5344
|
});
|
|
5166
5345
|
callback.catch(() => {
|
|
@@ -5219,9 +5398,9 @@ async function startCallbackServer(opts) {
|
|
|
5219
5398
|
}
|
|
5220
5399
|
});
|
|
5221
5400
|
server.keepAliveTimeout = 1;
|
|
5222
|
-
await new Promise((
|
|
5401
|
+
await new Promise((resolve9, reject) => {
|
|
5223
5402
|
server.once("error", (err) => reject(new OniroError("Failed to start the local login callback server.", err)));
|
|
5224
|
-
server.listen(0, "127.0.0.1",
|
|
5403
|
+
server.listen(0, "127.0.0.1", resolve9);
|
|
5225
5404
|
});
|
|
5226
5405
|
const port = server.address().port;
|
|
5227
5406
|
return {
|
|
@@ -5237,12 +5416,12 @@ async function startCallbackServer(opts) {
|
|
|
5237
5416
|
return Promise.race([callback, timeout]).finally(() => clearTimeout(timer));
|
|
5238
5417
|
},
|
|
5239
5418
|
stop() {
|
|
5240
|
-
return new Promise((
|
|
5419
|
+
return new Promise((resolve9) => {
|
|
5241
5420
|
server.closeAllConnections?.();
|
|
5242
|
-
const timer = setTimeout(
|
|
5421
|
+
const timer = setTimeout(resolve9, 100);
|
|
5243
5422
|
server.close(() => {
|
|
5244
5423
|
clearTimeout(timer);
|
|
5245
|
-
|
|
5424
|
+
resolve9();
|
|
5246
5425
|
});
|
|
5247
5426
|
});
|
|
5248
5427
|
}
|
|
@@ -5250,7 +5429,7 @@ async function startCallbackServer(opts) {
|
|
|
5250
5429
|
}
|
|
5251
5430
|
|
|
5252
5431
|
// src/harmonyos/auth/browser.ts
|
|
5253
|
-
var
|
|
5432
|
+
var import_node_child_process6 = require("child_process");
|
|
5254
5433
|
function isSafeUrl(url) {
|
|
5255
5434
|
try {
|
|
5256
5435
|
const parsed = new URL(url);
|
|
@@ -5267,18 +5446,18 @@ function openBrowser(url) {
|
|
|
5267
5446
|
return Promise.reject(new OniroError(`Refusing to open unsafe URL: ${JSON.stringify(url)}`));
|
|
5268
5447
|
}
|
|
5269
5448
|
const [command, args] = process.platform === "win32" ? ["cmd", ["/c", "start", '""', escapeForCmd(url)]] : process.platform === "darwin" ? ["open", [url]] : ["xdg-open", [url]];
|
|
5270
|
-
const child = (0,
|
|
5449
|
+
const child = (0, import_node_child_process6.spawn)(command, args, {
|
|
5271
5450
|
stdio: "ignore",
|
|
5272
5451
|
shell: false,
|
|
5273
5452
|
detached: true,
|
|
5274
5453
|
windowsHide: true
|
|
5275
5454
|
});
|
|
5276
5455
|
child.unref();
|
|
5277
|
-
return new Promise((
|
|
5456
|
+
return new Promise((resolve9, reject) => {
|
|
5278
5457
|
child.on("error", (err) => reject(new OniroError(`Failed to open a browser (${command}).`, err)));
|
|
5279
5458
|
child.on(
|
|
5280
5459
|
"exit",
|
|
5281
|
-
(code) => code === 0 ?
|
|
5460
|
+
(code) => code === 0 ? resolve9() : reject(new OniroError(`Browser launcher '${command}' exited with code ${code}.`))
|
|
5282
5461
|
);
|
|
5283
5462
|
});
|
|
5284
5463
|
}
|
|
@@ -5360,7 +5539,7 @@ function createHarmonyOsSession(opts) {
|
|
|
5360
5539
|
getDeveloperAgreement,
|
|
5361
5540
|
async login(o = {}) {
|
|
5362
5541
|
const start = HUAWEI_SITES.CN.loginUrl;
|
|
5363
|
-
const clientSecret =
|
|
5542
|
+
const clientSecret = crypto6.randomUUID().replace(/-/g, "");
|
|
5364
5543
|
const server = await startCallbackServer({
|
|
5365
5544
|
clientSecret,
|
|
5366
5545
|
baseUrl: start,
|
|
@@ -5526,7 +5705,7 @@ function mapAgcError(operation, statusCode, reasonPhrase, body) {
|
|
|
5526
5705
|
}
|
|
5527
5706
|
|
|
5528
5707
|
// src/harmonyos/signing/profile.ts
|
|
5529
|
-
var
|
|
5708
|
+
var fs37 = __toESM(require("fs"), 1);
|
|
5530
5709
|
var import_node_crypto3 = require("crypto");
|
|
5531
5710
|
var import_node_forge = __toESM(require("node-forge"), 1);
|
|
5532
5711
|
function extractProfileJson(buffer) {
|
|
@@ -5558,7 +5737,7 @@ function extractProfileJson(buffer) {
|
|
|
5558
5737
|
function readProvisionProfile(profilePath) {
|
|
5559
5738
|
let raw;
|
|
5560
5739
|
try {
|
|
5561
|
-
const json = extractProfileJson(
|
|
5740
|
+
const json = extractProfileJson(fs37.readFileSync(profilePath));
|
|
5562
5741
|
if (!json) return null;
|
|
5563
5742
|
raw = JSON.parse(json);
|
|
5564
5743
|
} catch {
|
|
@@ -5587,7 +5766,7 @@ function parseCertificate(pem) {
|
|
|
5587
5766
|
}
|
|
5588
5767
|
function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
|
|
5589
5768
|
try {
|
|
5590
|
-
const der = import_node_forge.default.util.createBuffer(
|
|
5769
|
+
const der = import_node_forge.default.util.createBuffer(fs37.readFileSync(p12Path).toString("binary"));
|
|
5591
5770
|
const p12 = import_node_forge.default.pkcs12.pkcs12FromAsn1(import_node_forge.default.asn1.fromDer(der), keyPwd);
|
|
5592
5771
|
const certBag = import_node_forge.default.pki.oids.certBag ?? "1.2.840.113549.1.12.10.1.3";
|
|
5593
5772
|
const wanted = certificate.publicKey.export({ type: "spki", format: "der" });
|
|
@@ -5603,7 +5782,7 @@ function keystoreHoldsKey(p12Path, keyAlias, keyPwd, certificate) {
|
|
|
5603
5782
|
}
|
|
5604
5783
|
}
|
|
5605
5784
|
function verifySigningMaterial(opts) {
|
|
5606
|
-
const pems =
|
|
5785
|
+
const pems = fs37.readFileSync(opts.cerPath, "utf8").match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g);
|
|
5607
5786
|
const chain = (pems ?? []).map(parseCertificate);
|
|
5608
5787
|
const leaf = chain.find((c) => !c.ca) ?? chain.at(-1);
|
|
5609
5788
|
if (!leaf) throw new AgcError(SIGNING_ERRORS.CERT_INVALID);
|
|
@@ -5621,15 +5800,15 @@ function verifySigningMaterial(opts) {
|
|
|
5621
5800
|
}
|
|
5622
5801
|
|
|
5623
5802
|
// src/harmonyos/signing/autoSign.ts
|
|
5624
|
-
var
|
|
5625
|
-
var
|
|
5626
|
-
var
|
|
5803
|
+
var crypto10 = __toESM(require("crypto"), 1);
|
|
5804
|
+
var fs42 = __toESM(require("fs"), 1);
|
|
5805
|
+
var path41 = __toESM(require("path"), 1);
|
|
5627
5806
|
var import_json57 = __toESM(require("json5"), 1);
|
|
5628
5807
|
|
|
5629
5808
|
// src/harmonyos/signing/agc.ts
|
|
5630
|
-
var
|
|
5631
|
-
var
|
|
5632
|
-
var
|
|
5809
|
+
var crypto7 = __toESM(require("crypto"), 1);
|
|
5810
|
+
var fs38 = __toESM(require("fs"), 1);
|
|
5811
|
+
var path36 = __toESM(require("path"), 1);
|
|
5633
5812
|
var ENDPOINTS = {
|
|
5634
5813
|
CERT_LIST: "/api/cps/harmony-cert-manage/v1/cert/list",
|
|
5635
5814
|
CERT_ADD: "/api/cps/harmony-cert-manage/v1/cert/add",
|
|
@@ -5677,7 +5856,7 @@ function createAgcClient(http3, auth) {
|
|
|
5677
5856
|
}
|
|
5678
5857
|
},
|
|
5679
5858
|
async addDevice(udid, deviceKind) {
|
|
5680
|
-
const deviceName = `oniro_app_device_${
|
|
5859
|
+
const deviceName = `oniro_app_device_${crypto7.randomBytes(4).toString("hex")}`;
|
|
5681
5860
|
await call("device", "post", ENDPOINTS.DEVICE_ADD, {
|
|
5682
5861
|
body: { deviceName, udid, deviceType: String(DEVICE_TYPE_CODES[deviceKind] ?? DEVICE_TYPE_CODES.phone) }
|
|
5683
5862
|
});
|
|
@@ -5711,12 +5890,12 @@ function createAgcClient(http3, auth) {
|
|
|
5711
5890
|
const target = urlsInfo?.[0];
|
|
5712
5891
|
if (!target) throw mapAgcError(operation, 200, "", "");
|
|
5713
5892
|
const buffer = await http3.getBinary(target.newUrl, { timeoutMs: 6e4 });
|
|
5714
|
-
const actual =
|
|
5893
|
+
const actual = crypto7.createHash("sha256").update(buffer).digest("hex");
|
|
5715
5894
|
if (target.sha256 && actual !== target.sha256.toLowerCase()) {
|
|
5716
5895
|
throw new ChecksumMismatchError(target.sha256, actual);
|
|
5717
5896
|
}
|
|
5718
|
-
|
|
5719
|
-
|
|
5897
|
+
fs38.mkdirSync(path36.dirname(dest), { recursive: true, mode: 448 });
|
|
5898
|
+
fs38.writeFileSync(dest, buffer, { mode: 384 });
|
|
5720
5899
|
}
|
|
5721
5900
|
};
|
|
5722
5901
|
}
|
|
@@ -5771,23 +5950,23 @@ async function registerDevices(agc, connected, logger) {
|
|
|
5771
5950
|
}
|
|
5772
5951
|
|
|
5773
5952
|
// src/harmonyos/signing/keystore.ts
|
|
5774
|
-
var
|
|
5775
|
-
var
|
|
5776
|
-
var
|
|
5953
|
+
var crypto8 = __toESM(require("crypto"), 1);
|
|
5954
|
+
var fs40 = __toESM(require("fs"), 1);
|
|
5955
|
+
var path38 = __toESM(require("path"), 1);
|
|
5777
5956
|
|
|
5778
5957
|
// src/harmonyos/java.ts
|
|
5779
|
-
var
|
|
5780
|
-
var
|
|
5958
|
+
var fs39 = __toESM(require("fs"), 1);
|
|
5959
|
+
var path37 = __toESM(require("path"), 1);
|
|
5781
5960
|
var JAVA_BIN = process.platform === "win32" ? "java.exe" : "java";
|
|
5782
5961
|
function findJava(sdk, env = process.env) {
|
|
5783
5962
|
const candidates = [
|
|
5784
|
-
env.JAVA_HOME &&
|
|
5785
|
-
sdk &&
|
|
5963
|
+
env.JAVA_HOME && path37.join(env.JAVA_HOME, "bin", JAVA_BIN),
|
|
5964
|
+
sdk && path37.join(sdk.installRoot, "jbr", "bin", JAVA_BIN),
|
|
5786
5965
|
// macOS: the JBR is itself a bundle inside Studio's Contents.
|
|
5787
|
-
sdk &&
|
|
5788
|
-
...(env.PATH ?? "").split(
|
|
5966
|
+
sdk && path37.join(sdk.installRoot, "jbr", "Contents", "Home", "bin", JAVA_BIN),
|
|
5967
|
+
...(env.PATH ?? "").split(path37.delimiter).map((dir) => dir && path37.join(dir, JAVA_BIN))
|
|
5789
5968
|
];
|
|
5790
|
-
const found = candidates.find((c) => !!c &&
|
|
5969
|
+
const found = candidates.find((c) => !!c && fs39.existsSync(c));
|
|
5791
5970
|
if (found) return found;
|
|
5792
5971
|
throw new OniroError(
|
|
5793
5972
|
"No Java runtime found. HarmonyOS signing runs the SDK's hap-sign-tool.jar, which needs one: install a JDK and set JAVA_HOME, or install DevEco Studio, whose bundled runtime is used automatically."
|
|
@@ -5800,49 +5979,77 @@ var SIGN_ALG = "SHA256withECDSA";
|
|
|
5800
5979
|
function redactArgs(args) {
|
|
5801
5980
|
return args.map((arg, i) => args[i - 1] === "-keyPwd" || args[i - 1] === "-keystorePwd" ? "******" : arg);
|
|
5802
5981
|
}
|
|
5803
|
-
|
|
5804
|
-
const jar =
|
|
5805
|
-
if (!
|
|
5982
|
+
function hapSignToolJar(sdk) {
|
|
5983
|
+
const jar = path38.join(sdk.sdkPath, "default", "openharmony", "toolchains", "lib", "hap-sign-tool.jar");
|
|
5984
|
+
if (!fs40.existsSync(jar)) {
|
|
5806
5985
|
throw new OniroError(`hap-sign-tool.jar not found at ${jar}; the HarmonyOS SDK looks incomplete.`);
|
|
5807
5986
|
}
|
|
5987
|
+
return jar;
|
|
5988
|
+
}
|
|
5989
|
+
async function runHapSignTool(opts) {
|
|
5990
|
+
const jar = hapSignToolJar(opts.sdk);
|
|
5808
5991
|
const java = findJava(opts.sdk);
|
|
5809
|
-
const
|
|
5810
|
-
|
|
5811
|
-
const
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
if (result.code !== 0) {
|
|
5816
|
-
const detail = (result.stderr || result.stdout || "").trim();
|
|
5817
|
-
throw new OniroError(`hap-sign-tool failed to ${what} (exit ${result.code}).${detail ? `
|
|
5992
|
+
const argv = ["-jar", jar, ...opts.args, "-keyAlias", KEY_ALIAS, "-keystoreFile", opts.p12Path, "-keystorePwd", opts.keyPwd, "-keyPwd", opts.keyPwd];
|
|
5993
|
+
opts.logger.debug(`[harmonyos] ${java} ${redactArgs(argv).join(" ")}`);
|
|
5994
|
+
const result = await runProcess({ command: java, args: argv, timeoutMs: 12e4, logger: opts.logger });
|
|
5995
|
+
if (result.code !== 0) {
|
|
5996
|
+
const detail = (result.stderr || result.stdout || "").trim();
|
|
5997
|
+
throw new OniroError(`hap-sign-tool failed to ${opts.what} (exit ${result.code}).${detail ? `
|
|
5818
5998
|
${detail}` : ""}`);
|
|
5819
|
-
|
|
5820
|
-
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
6001
|
+
async function generateKeystoreAndCsr(opts) {
|
|
6002
|
+
hapSignToolJar(opts.sdk);
|
|
6003
|
+
findJava(opts.sdk);
|
|
6004
|
+
const keyPwd = crypto8.randomBytes(12).toString("base64url").replaceAll(/[-_]/g, "");
|
|
6005
|
+
fs40.mkdirSync(path38.dirname(opts.p12Path), { recursive: true, mode: 448 });
|
|
6006
|
+
const run = (what, args) => runHapSignTool({ ...opts, what, args, keyPwd });
|
|
5821
6007
|
opts.logger.info("[harmonyos] Generating the local keystore and certificate signing request...");
|
|
5822
6008
|
await run("generate the key pair", ["generate-keypair", "-keyAlg", "ECC", "-keySize", "NIST-P-256"]);
|
|
5823
6009
|
await run("generate the CSR", ["generate-csr", "-subject", "CN=DebugKey", "-signAlg", SIGN_ALG, "-outFile", opts.csrPath]);
|
|
5824
|
-
return { keyPwd, csr:
|
|
6010
|
+
return { keyPwd, csr: fs40.readFileSync(opts.csrPath, "utf8") };
|
|
6011
|
+
}
|
|
6012
|
+
async function signHapFile(opts) {
|
|
6013
|
+
await runHapSignTool({
|
|
6014
|
+
...opts,
|
|
6015
|
+
what: `sign ${opts.inFile}`,
|
|
6016
|
+
args: [
|
|
6017
|
+
"sign-app",
|
|
6018
|
+
"-mode",
|
|
6019
|
+
"localSign",
|
|
6020
|
+
"-signAlg",
|
|
6021
|
+
SIGN_ALG,
|
|
6022
|
+
"-appCertFile",
|
|
6023
|
+
opts.cerPath,
|
|
6024
|
+
"-profileFile",
|
|
6025
|
+
opts.profilePath,
|
|
6026
|
+
"-inFile",
|
|
6027
|
+
opts.inFile,
|
|
6028
|
+
"-outFile",
|
|
6029
|
+
opts.outFile
|
|
6030
|
+
]
|
|
6031
|
+
});
|
|
5825
6032
|
}
|
|
5826
6033
|
|
|
5827
6034
|
// src/harmonyos/signing/paths.ts
|
|
5828
|
-
var
|
|
5829
|
-
var
|
|
6035
|
+
var crypto9 = __toESM(require("crypto"), 1);
|
|
6036
|
+
var path39 = __toESM(require("path"), 1);
|
|
5830
6037
|
function sanitizeNamePart(raw) {
|
|
5831
6038
|
const safe = (raw?.trim() ?? "").replace(/[\\/:*?"<>|=.-]+/g, "_");
|
|
5832
6039
|
return safe.slice(0, 64) || "default";
|
|
5833
6040
|
}
|
|
5834
6041
|
function resolveSigningMaterialPaths(config, productName, projectRoot) {
|
|
5835
|
-
const hash =
|
|
5836
|
-
const base =
|
|
6042
|
+
const hash = crypto9.createHash("sha256").update(projectRoot, "utf8").digest("base64url").replaceAll(/[-_]/g, "");
|
|
6043
|
+
const base = path39.join(
|
|
5837
6044
|
config.get("harmonyosSigningDir", defaultPaths.harmonyosSigningDir()),
|
|
5838
|
-
`${sanitizeNamePart(productName)}_${
|
|
6045
|
+
`${sanitizeNamePart(productName)}_${path39.basename(projectRoot)}_${hash}=`
|
|
5839
6046
|
);
|
|
5840
6047
|
return { p12Path: `${base}.p12`, csrPath: `${base}.csr`, cerPath: `${base}.cer`, profilePath: `${base}.p7b` };
|
|
5841
6048
|
}
|
|
5842
6049
|
|
|
5843
6050
|
// src/harmonyos/signing/project.ts
|
|
5844
|
-
var
|
|
5845
|
-
var
|
|
6051
|
+
var fs41 = __toESM(require("fs"), 1);
|
|
6052
|
+
var path40 = __toESM(require("path"), 1);
|
|
5846
6053
|
var import_json56 = __toESM(require("json5"), 1);
|
|
5847
6054
|
|
|
5848
6055
|
// src/harmonyos/signing/aclPermissionList.ts
|
|
@@ -5910,9 +6117,9 @@ var ACL_PERMISSIONS = /* @__PURE__ */ new Set([
|
|
|
5910
6117
|
|
|
5911
6118
|
// src/harmonyos/signing/project.ts
|
|
5912
6119
|
function readRequestedPermissions(moduleConfigPath) {
|
|
5913
|
-
if (!
|
|
6120
|
+
if (!fs41.existsSync(moduleConfigPath)) return [];
|
|
5914
6121
|
try {
|
|
5915
|
-
const parsed = import_json56.default.parse(
|
|
6122
|
+
const parsed = import_json56.default.parse(fs41.readFileSync(moduleConfigPath, "utf-8"));
|
|
5916
6123
|
return (parsed.module?.requestPermissions ?? []).map((p) => p?.name).filter((n) => typeof n === "string" && n.length > 0);
|
|
5917
6124
|
} catch {
|
|
5918
6125
|
return [];
|
|
@@ -5921,32 +6128,38 @@ function readRequestedPermissions(moduleConfigPath) {
|
|
|
5921
6128
|
function collectAclPermissions(projectDir, logger = noopLogger) {
|
|
5922
6129
|
const requested = /* @__PURE__ */ new Set();
|
|
5923
6130
|
for (const module2 of listModules({ projectDir })) {
|
|
5924
|
-
const moduleRoot =
|
|
6131
|
+
const moduleRoot = path40.resolve(projectDir, module2.srcPath);
|
|
5925
6132
|
for (const sourceSet of ["main", "ohosTest"]) {
|
|
5926
6133
|
for (const name of readRequestedPermissions(
|
|
5927
|
-
|
|
6134
|
+
path40.join(moduleRoot, "src", sourceSet, "module.json5")
|
|
5928
6135
|
)) {
|
|
5929
6136
|
requested.add(name);
|
|
5930
6137
|
}
|
|
5931
6138
|
}
|
|
5932
6139
|
}
|
|
5933
|
-
const acls =
|
|
6140
|
+
const acls = aclPermissionsAmong(requested);
|
|
5934
6141
|
if (acls.length > 0) {
|
|
5935
6142
|
logger.info(`[harmonyos] Project requests ${acls.length} ACL permission(s): ${acls.join(", ")}`);
|
|
5936
6143
|
}
|
|
5937
6144
|
return acls;
|
|
5938
6145
|
}
|
|
6146
|
+
function aclPermissionsAmong(names) {
|
|
6147
|
+
return [...new Set(names)].filter((p) => ACL_PERMISSIONS.has(p)).sort();
|
|
6148
|
+
}
|
|
5939
6149
|
|
|
5940
6150
|
// src/harmonyos/signing/autoSign.ts
|
|
5941
6151
|
function shouldRegenerate(input) {
|
|
5942
6152
|
if (input.force) return "--force was passed";
|
|
5943
|
-
const missing = Object.values(input.paths).find((file) => !
|
|
6153
|
+
const missing = Object.values(input.paths).find((file) => !fs42.existsSync(file));
|
|
5944
6154
|
if (missing) return `${missing} is missing`;
|
|
5945
6155
|
const config = input.buildProfile.app?.signingConfigs?.find((c) => c.name === input.productName);
|
|
5946
6156
|
if (config?.type !== "HarmonyOS" || config.material?.profile !== input.paths.profilePath) {
|
|
5947
6157
|
return "build-profile.json5 has no signingConfig for this material";
|
|
5948
6158
|
}
|
|
5949
|
-
|
|
6159
|
+
return profileProblem({ ...input, profilePath: input.paths.profilePath });
|
|
6160
|
+
}
|
|
6161
|
+
function profileProblem(input) {
|
|
6162
|
+
const profile = readProvisionProfile(input.profilePath);
|
|
5950
6163
|
if (!profile) return "the provisioning profile could not be read";
|
|
5951
6164
|
if (profile.bundleName !== input.bundleName) return `the profile is for bundle '${profile.bundleName}'`;
|
|
5952
6165
|
if (profile.developerId && profile.developerId !== input.teamId) {
|
|
@@ -5979,25 +6192,23 @@ function writeSigningConfig(opts) {
|
|
|
5979
6192
|
for (const product of app.products ?? []) {
|
|
5980
6193
|
if (product.name === opts.productName) product.signingConfig = opts.productName;
|
|
5981
6194
|
}
|
|
5982
|
-
|
|
6195
|
+
fs42.writeFileSync(opts.buildProfilePath, JSON.stringify(opts.buildProfile, null, 2));
|
|
5983
6196
|
}
|
|
5984
6197
|
async function harmonyOsAutoSign(opts) {
|
|
5985
6198
|
const logger = opts.logger ?? noopLogger;
|
|
5986
6199
|
const productName = opts.productName ?? "default";
|
|
5987
|
-
const projectDir =
|
|
5988
|
-
const buildProfilePath =
|
|
6200
|
+
const projectDir = path41.resolve(opts.projectDir);
|
|
6201
|
+
const buildProfilePath = path41.join(projectDir, "build-profile.json5");
|
|
5989
6202
|
let buildProfile;
|
|
5990
6203
|
try {
|
|
5991
|
-
buildProfile = import_json57.default.parse(
|
|
6204
|
+
buildProfile = import_json57.default.parse(fs42.readFileSync(buildProfilePath, "utf-8"));
|
|
5992
6205
|
} catch (err) {
|
|
5993
6206
|
throw new OniroError(`Could not read ${buildProfilePath}: ${err.message}`, err);
|
|
5994
6207
|
}
|
|
5995
6208
|
const product = buildProfile.app?.products?.find((p) => p.name === productName);
|
|
5996
6209
|
if (!product) throw new OniroError(`${buildProfilePath} declares no product named '${productName}'.`);
|
|
5997
6210
|
const bundleName = product.bundleName || getBundleName(projectDir);
|
|
5998
|
-
|
|
5999
|
-
throw new AgcError(SIGNING_ERRORS.BUNDLE_NAME_INVALID);
|
|
6000
|
-
}
|
|
6211
|
+
assertAgcBundleName(bundleName);
|
|
6001
6212
|
const sdk = requireHarmonyOsSdk({ config: opts.config, logger });
|
|
6002
6213
|
const auth = await opts.session.resolveAgcAuth({ teamId: opts.teamId });
|
|
6003
6214
|
const aclPermissions = collectAclPermissions(projectDir, logger);
|
|
@@ -6026,14 +6237,47 @@ async function harmonyOsAutoSign(opts) {
|
|
|
6026
6237
|
return result(false);
|
|
6027
6238
|
}
|
|
6028
6239
|
logger.info(`[harmonyos] Regenerating signing material: ${reason}.`);
|
|
6029
|
-
const
|
|
6240
|
+
const keyPwd = await issueSigningMaterial({
|
|
6241
|
+
agc: createAgcClient(opts.http ?? createHttpClient({ logger }), auth),
|
|
6242
|
+
local,
|
|
6243
|
+
sdk,
|
|
6244
|
+
paths,
|
|
6245
|
+
bundleName,
|
|
6246
|
+
aclPermissions,
|
|
6247
|
+
teamId: auth.teamId,
|
|
6248
|
+
logger
|
|
6249
|
+
});
|
|
6250
|
+
const encryptedPassword = encryptPwd(keyPwd, sharedMaterialDir(paths));
|
|
6251
|
+
writeSigningConfig({ buildProfilePath, buildProfile, productName, paths, encryptedPassword });
|
|
6252
|
+
logger.info(`[harmonyos] Wrote signingConfigs['${productName}'] to ${buildProfilePath}.`);
|
|
6253
|
+
return result(true);
|
|
6254
|
+
}
|
|
6255
|
+
function assertAgcBundleName(bundleName) {
|
|
6256
|
+
if (!isValidBundleName(bundleName) || bundleName.split(".").length < 3 || bundleName.length < 7 || bundleName.length > 128) {
|
|
6257
|
+
throw new AgcError(SIGNING_ERRORS.BUNDLE_NAME_INVALID);
|
|
6258
|
+
}
|
|
6259
|
+
}
|
|
6260
|
+
function materialDirFor(paths) {
|
|
6261
|
+
return path41.join(path41.dirname(paths.p12Path), "material");
|
|
6262
|
+
}
|
|
6263
|
+
function sharedMaterialDir(paths) {
|
|
6264
|
+
const materialDir = materialDirFor(paths);
|
|
6265
|
+
try {
|
|
6266
|
+
getKey(materialDir);
|
|
6267
|
+
} catch {
|
|
6268
|
+
createMaterial(materialDir);
|
|
6269
|
+
}
|
|
6270
|
+
return materialDir;
|
|
6271
|
+
}
|
|
6272
|
+
async function issueSigningMaterial(opts) {
|
|
6273
|
+
const { agc, local, sdk, paths, logger } = opts;
|
|
6030
6274
|
const deviceIds = await registerDevices(agc, local.devices, logger);
|
|
6031
6275
|
if (local.devices.length === 0) {
|
|
6032
6276
|
const cause = local.skipped.length > 0 ? "No connected device could be registered" : "No device is connected";
|
|
6033
6277
|
logger.warn(`[harmonyos] ${cause}; the profile will name the ${deviceIds.length} device(s) already registered to this team.`);
|
|
6034
6278
|
}
|
|
6035
|
-
for (const file of Object.values(paths))
|
|
6036
|
-
const certName = `oniro_debug_${
|
|
6279
|
+
for (const file of Object.values(paths)) fs42.rmSync(file, { force: true });
|
|
6280
|
+
const certName = `oniro_debug_${opts.teamId.replace(/[\\/.:]/g, "")}.cer`;
|
|
6037
6281
|
const stale = (await agc.listCertificates()).find((c) => c.certName === certName);
|
|
6038
6282
|
if (stale) {
|
|
6039
6283
|
logger.info(`[harmonyos] Replacing the previous '${certName}' certificate in AppGallery Connect...`);
|
|
@@ -6047,11 +6291,11 @@ async function harmonyOsAutoSign(opts) {
|
|
|
6047
6291
|
await agc.download("cert", cert.certObjectId, paths.cerPath);
|
|
6048
6292
|
logger.info("[harmonyos] Issuing the debug provisioning profile...");
|
|
6049
6293
|
const profile = await agc.addDebugProfile({
|
|
6050
|
-
provisionName: `oniro_${
|
|
6051
|
-
bundleName,
|
|
6294
|
+
provisionName: `oniro_${crypto10.randomBytes(6).toString("hex")}`,
|
|
6295
|
+
bundleName: opts.bundleName,
|
|
6052
6296
|
certId: cert.id,
|
|
6053
6297
|
deviceIds,
|
|
6054
|
-
aclPermissions
|
|
6298
|
+
aclPermissions: opts.aclPermissions
|
|
6055
6299
|
});
|
|
6056
6300
|
try {
|
|
6057
6301
|
await agc.download("profile", profile.provisionFileUrl, paths.profilePath);
|
|
@@ -6063,22 +6307,86 @@ async function harmonyOsAutoSign(opts) {
|
|
|
6063
6307
|
try {
|
|
6064
6308
|
verifySigningMaterial({ ...paths, keyAlias: KEY_ALIAS, keyPwd });
|
|
6065
6309
|
} catch (err) {
|
|
6066
|
-
|
|
6310
|
+
fs42.rmSync(paths.profilePath, { force: true });
|
|
6067
6311
|
throw err;
|
|
6068
6312
|
}
|
|
6069
|
-
|
|
6313
|
+
return keyPwd;
|
|
6314
|
+
}
|
|
6315
|
+
|
|
6316
|
+
// src/harmonyos/signing/signHap.ts
|
|
6317
|
+
var fs43 = __toESM(require("fs"), 1);
|
|
6318
|
+
var path42 = __toESM(require("path"), 1);
|
|
6319
|
+
function resolveHapSigningMaterialPaths(config, bundleName) {
|
|
6320
|
+
const paths = resolveSigningMaterialPaths(config, "hap", bundleName);
|
|
6321
|
+
return { ...paths, pwdPath: paths.p12Path.replace(/\.p12$/, ".pwd") };
|
|
6322
|
+
}
|
|
6323
|
+
function readStoredPassword(paths) {
|
|
6070
6324
|
try {
|
|
6071
|
-
|
|
6325
|
+
return decryptPwd(fs43.readFileSync(paths.pwdPath, "utf8").trim(), materialDirFor(paths));
|
|
6072
6326
|
} catch {
|
|
6073
|
-
|
|
6327
|
+
return null;
|
|
6074
6328
|
}
|
|
6075
|
-
|
|
6076
|
-
|
|
6077
|
-
|
|
6329
|
+
}
|
|
6330
|
+
async function harmonyOsSignHap(opts) {
|
|
6331
|
+
const logger = opts.logger ?? noopLogger;
|
|
6332
|
+
const hapPath = path42.resolve(opts.hapPath);
|
|
6333
|
+
const outPath = path42.resolve(opts.outPath ?? defaultSignedHapPath(hapPath));
|
|
6334
|
+
const info = await readHapSigningInfo(hapPath);
|
|
6335
|
+
const { bundleName } = info;
|
|
6336
|
+
if (info.compileSdkType === "OpenHarmony") {
|
|
6337
|
+
throw new OniroError(
|
|
6338
|
+
`${hapPath} was built for OpenHarmony, so a HarmonyOS device would not run it; sign it without --harmonyos.`
|
|
6339
|
+
);
|
|
6340
|
+
}
|
|
6341
|
+
assertAgcBundleName(bundleName);
|
|
6342
|
+
const aclPermissions = aclPermissionsAmong(info.requestedPermissions);
|
|
6343
|
+
if (aclPermissions.length > 0) {
|
|
6344
|
+
logger.info(`[harmonyos] HAP requests ${aclPermissions.length} ACL permission(s): ${aclPermissions.join(", ")}`);
|
|
6345
|
+
}
|
|
6346
|
+
const sdk = requireHarmonyOsSdk({ config: opts.config, logger });
|
|
6347
|
+
const auth = await opts.session.resolveAgcAuth({ teamId: opts.teamId });
|
|
6348
|
+
const paths = resolveHapSigningMaterialPaths(opts.config, bundleName);
|
|
6349
|
+
const { pwdPath, ...material } = paths;
|
|
6350
|
+
logger.info(`[harmonyos] Signing ${path42.basename(hapPath)} as ${bundleName} (team ${auth.teamId}).`);
|
|
6351
|
+
const local = await collectLocalDevices(opts.config, logger);
|
|
6352
|
+
let keyPwd = opts.force ? null : readStoredPassword(paths);
|
|
6353
|
+
const missing = Object.values(material).find((file) => !fs43.existsSync(file));
|
|
6354
|
+
const reason = opts.force ? "--force was passed" : missing ? `${missing} is missing` : keyPwd === null ? "the stored keystore password could not be read" : profileProblem({
|
|
6355
|
+
profilePath: material.profilePath,
|
|
6356
|
+
bundleName,
|
|
6357
|
+
teamId: auth.teamId,
|
|
6358
|
+
connectedUdids: local.devices.map((d) => d.udid),
|
|
6359
|
+
aclPermissions
|
|
6360
|
+
});
|
|
6361
|
+
if (!reason && keyPwd !== null) {
|
|
6362
|
+
logger.info("[harmonyos] Reusing the existing signing material, which is still valid.");
|
|
6363
|
+
} else {
|
|
6364
|
+
logger.info(`[harmonyos] Regenerating signing material: ${reason}.`);
|
|
6365
|
+
fs43.rmSync(pwdPath, { force: true });
|
|
6366
|
+
keyPwd = await issueSigningMaterial({
|
|
6367
|
+
agc: createAgcClient(opts.http ?? createHttpClient({ logger }), auth),
|
|
6368
|
+
local,
|
|
6369
|
+
sdk,
|
|
6370
|
+
paths: material,
|
|
6371
|
+
bundleName,
|
|
6372
|
+
aclPermissions,
|
|
6373
|
+
teamId: auth.teamId,
|
|
6374
|
+
logger
|
|
6375
|
+
});
|
|
6376
|
+
fs43.writeFileSync(pwdPath, encryptPwd(keyPwd, sharedMaterialDir(material)), { mode: 384 });
|
|
6377
|
+
}
|
|
6378
|
+
const password = keyPwd;
|
|
6379
|
+
await writeHapAtomically(
|
|
6380
|
+
outPath,
|
|
6381
|
+
(tmpPath) => signHapFile({ sdk, inFile: hapPath, outFile: tmpPath, ...material, keyPwd: password, logger })
|
|
6382
|
+
);
|
|
6383
|
+
const deviceIds = readProvisionProfile(material.profilePath)?.deviceIds ?? [];
|
|
6384
|
+
logger.info(`[harmonyos] Wrote ${outPath}.`);
|
|
6385
|
+
return { bundleName, teamId: auth.teamId, paths: material, regenerated: !!reason, deviceIds, outPath };
|
|
6078
6386
|
}
|
|
6079
6387
|
|
|
6080
6388
|
// src/index.ts
|
|
6081
|
-
var VERSION = "0.
|
|
6389
|
+
var VERSION = "0.16.0";
|
|
6082
6390
|
// Annotate the CommonJS export names for ESM import in node:
|
|
6083
6391
|
0 && (module.exports = {
|
|
6084
6392
|
ALL_SDKS,
|
|
@@ -6096,6 +6404,7 @@ var VERSION = "0.15.1";
|
|
|
6096
6404
|
OHOS_DAILY_BUILDS_URL,
|
|
6097
6405
|
OHOS_URL_BASE,
|
|
6098
6406
|
OniroError,
|
|
6407
|
+
SIGNED_HAP_CHUNK_SIZE,
|
|
6099
6408
|
SIGNING_ERRORS,
|
|
6100
6409
|
SdkNotInstalledError,
|
|
6101
6410
|
TMP_DIR_HINT,
|
|
@@ -6131,6 +6440,7 @@ var VERSION = "0.15.1";
|
|
|
6131
6440
|
dedupEntries,
|
|
6132
6441
|
defaultContext,
|
|
6133
6442
|
defaultPaths,
|
|
6443
|
+
defaultSignedHapPath,
|
|
6134
6444
|
describeLayoutNode,
|
|
6135
6445
|
detectAaStartFailure,
|
|
6136
6446
|
detectCmdToolsFlavour,
|
|
@@ -6197,6 +6507,7 @@ var VERSION = "0.15.1";
|
|
|
6197
6507
|
getSupportedSdksForUi,
|
|
6198
6508
|
harmonyOsAutoSign,
|
|
6199
6509
|
harmonyOsSdkLabelForApi,
|
|
6510
|
+
harmonyOsSignHap,
|
|
6200
6511
|
hdcClientFailure,
|
|
6201
6512
|
hdcExec,
|
|
6202
6513
|
hdcTargetArgs,
|
|
@@ -6250,6 +6561,7 @@ var VERSION = "0.15.1";
|
|
|
6250
6561
|
prepareSigning,
|
|
6251
6562
|
pruneLayout,
|
|
6252
6563
|
readHapBundleName,
|
|
6564
|
+
readHapSigningInfo,
|
|
6253
6565
|
readJson5File,
|
|
6254
6566
|
readJsonFile,
|
|
6255
6567
|
readProvisionProfile,
|
|
@@ -6277,6 +6589,7 @@ var VERSION = "0.15.1";
|
|
|
6277
6589
|
setHilogLevel,
|
|
6278
6590
|
shell,
|
|
6279
6591
|
shellChecked,
|
|
6592
|
+
signOpenHarmonyHap,
|
|
6280
6593
|
spawnCompat,
|
|
6281
6594
|
startEmulator,
|
|
6282
6595
|
staticConfig,
|
|
@@ -6296,6 +6609,7 @@ var VERSION = "0.15.1";
|
|
|
6296
6609
|
waitForTarget,
|
|
6297
6610
|
watchLog,
|
|
6298
6611
|
waypointsToRawEvents,
|
|
6612
|
+
withHapZip,
|
|
6299
6613
|
withoutWindow,
|
|
6300
6614
|
writeJson5File,
|
|
6301
6615
|
writeJsonFile
|