@harmonyos-arkts/droid2hmos 0.0.8 → 0.0.10
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/cli.js +213 -34
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import path36 from "path";
|
|
5
|
-
import { existsSync as existsSync9, readFileSync as
|
|
5
|
+
import { existsSync as existsSync9, readFileSync as readFileSync8, realpathSync, readdirSync as readdirSync5 } from "fs";
|
|
6
6
|
import { pathToFileURL } from "url";
|
|
7
7
|
|
|
8
8
|
// src/commands/lib/spawn-command.ts
|
|
@@ -2395,6 +2395,14 @@ import { existsSync as existsSync3, readdirSync, statSync } from "fs";
|
|
|
2395
2395
|
import path13 from "path";
|
|
2396
2396
|
var DEVECO_CLI_PACKAGE = "@deveco/deveco-cli@latest";
|
|
2397
2397
|
var DEVECO_CLI_INSTALL_COMMAND = `npm install -g ${DEVECO_CLI_PACKAGE}`;
|
|
2398
|
+
var NODE_INSPECTOR_OPTION = /(?:^|\s)--inspect(?:-brk|-port|-wait)?(?:=(?:"[^"]*"|'[^']*'|\S+))?(?=\s|$)/gu;
|
|
2399
|
+
function devEcoCliEnvironment(environment = process.env) {
|
|
2400
|
+
const result = { ...environment, DEVECO_CLI_SKIP_VERSION_CHECK: "1" };
|
|
2401
|
+
const nodeOptions = String(environment.NODE_OPTIONS ?? "").replace(NODE_INSPECTOR_OPTION, "").trim();
|
|
2402
|
+
if (nodeOptions) result.NODE_OPTIONS = nodeOptions;
|
|
2403
|
+
else delete result.NODE_OPTIONS;
|
|
2404
|
+
return result;
|
|
2405
|
+
}
|
|
2398
2406
|
function executableName() {
|
|
2399
2407
|
return process.env.DEVECO_CLI_BINARY || "devecocli";
|
|
2400
2408
|
}
|
|
@@ -2402,14 +2410,14 @@ function devEcoCliSpawn(executable, args) {
|
|
|
2402
2410
|
const scriptWrapper = /\.m?js$/i.test(executable);
|
|
2403
2411
|
return scriptWrapper ? [process.execPath, executable, ...args] : [executable, ...args];
|
|
2404
2412
|
}
|
|
2405
|
-
function runDevEcoCli(args, { executable = executableName(), runner = spawnCommandSync, timeoutMs = 15e3 } = {}, cwd) {
|
|
2413
|
+
function runDevEcoCli(args, { executable = executableName(), runner = spawnCommandSync, timeoutMs = 15e3, environment = process.env } = {}, cwd) {
|
|
2406
2414
|
const [command2, ...commandArgs] = devEcoCliSpawn(executable, args);
|
|
2407
2415
|
const result = runner(command2, commandArgs, {
|
|
2408
2416
|
cwd,
|
|
2409
2417
|
encoding: "utf8",
|
|
2410
2418
|
timeout: timeoutMs,
|
|
2411
2419
|
windowsHide: true,
|
|
2412
|
-
env:
|
|
2420
|
+
env: devEcoCliEnvironment(environment)
|
|
2413
2421
|
});
|
|
2414
2422
|
return {
|
|
2415
2423
|
executable,
|
|
@@ -2421,13 +2429,13 @@ function runDevEcoCli(args, { executable = executableName(), runner = spawnComma
|
|
|
2421
2429
|
errorCode: result.error && "code" in result.error ? result.error.code : null
|
|
2422
2430
|
};
|
|
2423
2431
|
}
|
|
2424
|
-
async function runDevEcoCliAsync(args, { executable = executableName(), timeoutMs = 15e3 } = {}, cwd) {
|
|
2432
|
+
async function runDevEcoCliAsync(args, { executable = executableName(), timeoutMs = 15e3, environment = process.env } = {}, cwd) {
|
|
2425
2433
|
const [command2, ...commandArgs] = devEcoCliSpawn(executable, args);
|
|
2426
2434
|
const child = spawnCommand(command2, commandArgs, {
|
|
2427
2435
|
cwd,
|
|
2428
2436
|
windowsHide: true,
|
|
2429
2437
|
detached: process.platform !== "win32",
|
|
2430
|
-
env:
|
|
2438
|
+
env: devEcoCliEnvironment(environment),
|
|
2431
2439
|
stdio: ["ignore", "pipe", "pipe"]
|
|
2432
2440
|
});
|
|
2433
2441
|
let stdout = "";
|
|
@@ -2508,7 +2516,7 @@ function checkDevEcoCliAuth(cli = {}) {
|
|
|
2508
2516
|
const result = runDevEcoCli(["auth", "status"], cli);
|
|
2509
2517
|
const output = [result.stdout, result.stderr].map((value) => value.trim()).filter(Boolean).join("\n");
|
|
2510
2518
|
const loggedOut = /(?:^|\n)Not logged in(?:\n|$)/i.test(output);
|
|
2511
|
-
const currentUser = output.match(/
|
|
2519
|
+
const currentUser = output.match(/Current user:\s*([^\r\n]+)/i)?.[1]?.trim();
|
|
2512
2520
|
if (result.status !== "passed" || loggedOut || !currentUser) {
|
|
2513
2521
|
return {
|
|
2514
2522
|
status: "failed",
|
|
@@ -3124,7 +3132,7 @@ function runHarmonyTest({ projectRoot, harmonyProject, timeoutMs, testClass = nu
|
|
|
3124
3132
|
}
|
|
3125
3133
|
|
|
3126
3134
|
// src/commands/python-hypium.ts
|
|
3127
|
-
import { existsSync as existsSync5, statSync as statSync3 } from "fs";
|
|
3135
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
|
|
3128
3136
|
import path16 from "path";
|
|
3129
3137
|
var safeTestName = /^[A-Za-z0-9_./-]+$/;
|
|
3130
3138
|
function executableWithArgs(executable, args) {
|
|
@@ -3214,8 +3222,51 @@ function runHarmonyPythonHypiumTest({
|
|
|
3214
3222
|
projectRoot,
|
|
3215
3223
|
timeoutMs
|
|
3216
3224
|
});
|
|
3225
|
+
if (execute.status !== "passed") {
|
|
3226
|
+
return {
|
|
3227
|
+
status: execute.status,
|
|
3228
|
+
key: "harmonyPythonTest",
|
|
3229
|
+
runner: "python",
|
|
3230
|
+
stage: "execute",
|
|
3231
|
+
target,
|
|
3232
|
+
appArtifact: appBuild.artifact,
|
|
3233
|
+
hypiumProject: testProjectRoot,
|
|
3234
|
+
testLists,
|
|
3235
|
+
reportPath: reports,
|
|
3236
|
+
signature,
|
|
3237
|
+
installApp,
|
|
3238
|
+
execute,
|
|
3239
|
+
summary: `Python Hypium \u6267\u884C\u5931\u8D25\uFF0C\u8BF7\u786E\u8BA4\u5DF2\u4E3A ${python} \u5B89\u88C5 hypium\uFF08python -m pip install hypium -U\uFF09`
|
|
3240
|
+
};
|
|
3241
|
+
}
|
|
3242
|
+
const stdoutText = (() => {
|
|
3243
|
+
try {
|
|
3244
|
+
return existsSync5(execute.stdout) ? readFileSync4(execute.stdout, "utf8") : "";
|
|
3245
|
+
} catch {
|
|
3246
|
+
return "";
|
|
3247
|
+
}
|
|
3248
|
+
})();
|
|
3249
|
+
const structuredHypiumResult = pythonHypiumResult({ stdoutText, reportsDir: reports });
|
|
3250
|
+
if (!structuredHypiumResult.valid) {
|
|
3251
|
+
return {
|
|
3252
|
+
status: "failed",
|
|
3253
|
+
key: "harmonyPythonTest",
|
|
3254
|
+
runner: "python",
|
|
3255
|
+
stage: "parse-summary",
|
|
3256
|
+
target,
|
|
3257
|
+
appArtifact: appBuild.artifact,
|
|
3258
|
+
hypiumProject: testProjectRoot,
|
|
3259
|
+
testLists,
|
|
3260
|
+
reportPath: reports,
|
|
3261
|
+
signature,
|
|
3262
|
+
installApp,
|
|
3263
|
+
execute,
|
|
3264
|
+
structuredHypiumResult,
|
|
3265
|
+
summary: `Hypium \u7ED3\u6784\u5316\u7ED3\u679C\u4E0D\u901A\u8FC7: ${structuredHypiumResult.summary}`
|
|
3266
|
+
};
|
|
3267
|
+
}
|
|
3217
3268
|
return {
|
|
3218
|
-
status:
|
|
3269
|
+
status: "passed",
|
|
3219
3270
|
key: "harmonyPythonTest",
|
|
3220
3271
|
runner: "python",
|
|
3221
3272
|
stage: "execute",
|
|
@@ -3227,9 +3278,123 @@ function runHarmonyPythonHypiumTest({
|
|
|
3227
3278
|
signature,
|
|
3228
3279
|
installApp,
|
|
3229
3280
|
execute,
|
|
3230
|
-
|
|
3281
|
+
structuredHypiumResult,
|
|
3282
|
+
tests: structuredHypiumResult,
|
|
3283
|
+
summary: `HarmonyOS \u5E94\u7528\u6784\u5EFA\u3001\u5B89\u88C5\u548C Python Hypium \u6D4B\u8BD5\u6267\u884C\u6210\u529F\uFF08${structuredHypiumResult.passed}/${structuredHypiumResult.total}\uFF09`
|
|
3231
3284
|
};
|
|
3232
3285
|
}
|
|
3286
|
+
function junitAttribute(tag, name) {
|
|
3287
|
+
const match = new RegExp(`\\b${name}="(-?\\d+)"`).exec(tag);
|
|
3288
|
+
return match ? Number(match[1]) : 0;
|
|
3289
|
+
}
|
|
3290
|
+
function aggregateJunitXmlResults(xmlTexts) {
|
|
3291
|
+
const suiteTags = [];
|
|
3292
|
+
let wrapperTag = "";
|
|
3293
|
+
const executedCases = [];
|
|
3294
|
+
for (const xml of xmlTexts) {
|
|
3295
|
+
const text = String(xml ?? "");
|
|
3296
|
+
wrapperTag = wrapperTag || (/<testsuites\b[^>]*>/.exec(text)?.[0] ?? "");
|
|
3297
|
+
for (const match of text.matchAll(/<testsuite\b[^>]*>/g)) suiteTags.push(match[0]);
|
|
3298
|
+
for (const match of text.matchAll(/<testcase\b[^>]*>/g)) {
|
|
3299
|
+
const classname = /\bclassname="([^"]*)"/.exec(match[0])?.[1];
|
|
3300
|
+
const name = /\bname="([^"]*)"/.exec(match[0])?.[1];
|
|
3301
|
+
if (name) executedCases.push(`${classname ?? "suite"}#${name}`);
|
|
3302
|
+
}
|
|
3303
|
+
}
|
|
3304
|
+
if (!wrapperTag && !suiteTags.length) return null;
|
|
3305
|
+
const sources = wrapperTag ? [wrapperTag] : suiteTags;
|
|
3306
|
+
const sum = (attribute) => sources.reduce((total2, tag) => total2 + junitAttribute(tag, attribute), 0);
|
|
3307
|
+
const total = sum("tests");
|
|
3308
|
+
const failed = sum("failures");
|
|
3309
|
+
const errors = sum("errors");
|
|
3310
|
+
const ignored = sum("ignored") + sum("skipped");
|
|
3311
|
+
const disabled = sum("disabled");
|
|
3312
|
+
const unavailable = sum("unavailable");
|
|
3313
|
+
const passed = Math.max(total - failed - errors - ignored - disabled - unavailable, 0);
|
|
3314
|
+
const problems = [];
|
|
3315
|
+
if (total <= 0) problems.push("zero tests");
|
|
3316
|
+
if (failed) problems.push(`failed ${failed}`);
|
|
3317
|
+
if (errors) problems.push(`errors ${errors}`);
|
|
3318
|
+
if (ignored) problems.push(`ignored ${ignored}`);
|
|
3319
|
+
if (disabled) problems.push(`disabled ${disabled}`);
|
|
3320
|
+
if (unavailable) problems.push(`unavailable ${unavailable}`);
|
|
3321
|
+
return {
|
|
3322
|
+
valid: problems.length === 0,
|
|
3323
|
+
total,
|
|
3324
|
+
passed,
|
|
3325
|
+
failed,
|
|
3326
|
+
errors,
|
|
3327
|
+
ignored,
|
|
3328
|
+
disabled,
|
|
3329
|
+
summary: problems.length ? `Hypium rejected: ${problems.join(", ")}` : `Hypium ${passed}/${total} passed`,
|
|
3330
|
+
executedCases
|
|
3331
|
+
};
|
|
3332
|
+
}
|
|
3333
|
+
function pythonHypiumResult({ stdoutText, reportsDir }) {
|
|
3334
|
+
const empty2 = (summary) => ({
|
|
3335
|
+
valid: false,
|
|
3336
|
+
total: 0,
|
|
3337
|
+
passed: 0,
|
|
3338
|
+
failed: 0,
|
|
3339
|
+
errors: 0,
|
|
3340
|
+
ignored: 0,
|
|
3341
|
+
disabled: 0,
|
|
3342
|
+
executedCases: [],
|
|
3343
|
+
summary
|
|
3344
|
+
});
|
|
3345
|
+
const stdoutMatch = /Tests run:\s*(\d+)\s*,\s*Failure:\s*(\d+)\s*,\s*Error:\s*(\d+)\s*,\s*(?:Pass(?:ed)?:\s*(\d+)\s*,\s*)?Ignore:\s*(\d+)/.exec(String(stdoutText ?? ""));
|
|
3346
|
+
if (stdoutMatch) {
|
|
3347
|
+
const total = Number(stdoutMatch[1]);
|
|
3348
|
+
const failed = Number(stdoutMatch[2]);
|
|
3349
|
+
const errors = Number(stdoutMatch[3]);
|
|
3350
|
+
const reportedPass = stdoutMatch[4] !== void 0 ? Number(stdoutMatch[4]) : null;
|
|
3351
|
+
const ignored = Number(stdoutMatch[5]);
|
|
3352
|
+
const passed = reportedPass ?? Math.max(total - failed - errors - ignored, 0);
|
|
3353
|
+
const problems = [];
|
|
3354
|
+
if (total <= 0) problems.push("zero tests");
|
|
3355
|
+
if (failed) problems.push(`failed ${failed}`);
|
|
3356
|
+
if (errors) problems.push(`errors ${errors}`);
|
|
3357
|
+
if (ignored) problems.push(`ignored ${ignored}`);
|
|
3358
|
+
return {
|
|
3359
|
+
valid: problems.length === 0,
|
|
3360
|
+
total,
|
|
3361
|
+
passed,
|
|
3362
|
+
failed,
|
|
3363
|
+
errors,
|
|
3364
|
+
ignored,
|
|
3365
|
+
disabled: 0,
|
|
3366
|
+
executedCases: [],
|
|
3367
|
+
summary: problems.length ? `Hypium rejected: ${problems.join(", ")}` : `Hypium ${passed}/${total} passed`
|
|
3368
|
+
};
|
|
3369
|
+
}
|
|
3370
|
+
const xmlTexts = [];
|
|
3371
|
+
const aggregatePath = path16.join(reportsDir, "summary_report.xml");
|
|
3372
|
+
if (existsSync5(aggregatePath)) {
|
|
3373
|
+
try {
|
|
3374
|
+
xmlTexts.push(readFileSync4(aggregatePath, "utf8"));
|
|
3375
|
+
} catch {
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3378
|
+
if (existsSync5(reportsDir)) {
|
|
3379
|
+
try {
|
|
3380
|
+
const stamped = readdirSync3(reportsDir).filter((entry) => /^\d+$/.test(entry)).sort().reverse();
|
|
3381
|
+
for (const stamp of stamped) {
|
|
3382
|
+
const summaryPath = path16.join(reportsDir, stamp, "result", "summary.xml");
|
|
3383
|
+
if (existsSync5(summaryPath)) {
|
|
3384
|
+
try {
|
|
3385
|
+
xmlTexts.push(readFileSync4(summaryPath, "utf8"));
|
|
3386
|
+
} catch {
|
|
3387
|
+
}
|
|
3388
|
+
break;
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
} catch {
|
|
3392
|
+
}
|
|
3393
|
+
}
|
|
3394
|
+
const aggregated = aggregateJunitXmlResults(xmlTexts);
|
|
3395
|
+
if (aggregated) return aggregated;
|
|
3396
|
+
return empty2(`Hypium did not produce a machine-readable test summary (stdout or ${reportsDir})`);
|
|
3397
|
+
}
|
|
3233
3398
|
|
|
3234
3399
|
// src/commands/detect-harmony-sdk.ts
|
|
3235
3400
|
import fs14 from "fs";
|
|
@@ -3348,12 +3513,12 @@ function parseProperties(text) {
|
|
|
3348
3513
|
}
|
|
3349
3514
|
|
|
3350
3515
|
// src/commands/upgrade.ts
|
|
3351
|
-
import { readFileSync as
|
|
3516
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
3352
3517
|
import path18 from "path";
|
|
3353
3518
|
function readPackageMetadata(packageRoot) {
|
|
3354
3519
|
if (!packageRoot) throw new Error("Cannot locate droid2hmos package metadata");
|
|
3355
3520
|
const packagePath = path18.join(packageRoot, "package.json");
|
|
3356
|
-
const metadata = JSON.parse(
|
|
3521
|
+
const metadata = JSON.parse(readFileSync5(packagePath, "utf8"));
|
|
3357
3522
|
if (!metadata.name || !metadata.version) throw new Error(`Invalid package metadata: ${packagePath}`);
|
|
3358
3523
|
return metadata;
|
|
3359
3524
|
}
|
|
@@ -4074,8 +4239,8 @@ async function runPreflight(options) {
|
|
|
4074
4239
|
}
|
|
4075
4240
|
|
|
4076
4241
|
// src/commands/deveco-auth-login.ts
|
|
4077
|
-
import {
|
|
4078
|
-
import { closeSync as closeSync3, existsSync as existsSync6, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as
|
|
4242
|
+
import { spawnSync as spawnSync6 } from "child_process";
|
|
4243
|
+
import { closeSync as closeSync3, existsSync as existsSync6, mkdirSync as mkdirSync3, openSync as openSync3, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
4079
4244
|
import path24 from "path";
|
|
4080
4245
|
import { setTimeout as delay2 } from "timers/promises";
|
|
4081
4246
|
var MANAGED_LOGIN_SERVICE_NAME = "devecocli-auth";
|
|
@@ -4107,7 +4272,7 @@ function isAlive2(pid) {
|
|
|
4107
4272
|
}
|
|
4108
4273
|
function readPidFile(pidFile) {
|
|
4109
4274
|
try {
|
|
4110
|
-
const pid = Number.parseInt(
|
|
4275
|
+
const pid = Number.parseInt(readFileSync6(pidFile, "utf8").trim(), 10);
|
|
4111
4276
|
return Number.isInteger(pid) ? pid : null;
|
|
4112
4277
|
} catch {
|
|
4113
4278
|
return null;
|
|
@@ -4115,7 +4280,7 @@ function readPidFile(pidFile) {
|
|
|
4115
4280
|
}
|
|
4116
4281
|
function tailFile(file, maxChars) {
|
|
4117
4282
|
try {
|
|
4118
|
-
const content =
|
|
4283
|
+
const content = readFileSync6(file, "utf8").trim();
|
|
4119
4284
|
return content.length > maxChars ? `\u2026${content.slice(-maxChars)}` : content;
|
|
4120
4285
|
} catch {
|
|
4121
4286
|
return "";
|
|
@@ -4206,13 +4371,13 @@ async function killOrphanDevEcoCliLogins(options) {
|
|
|
4206
4371
|
return { killedPids, managedPid: managedPid ?? null };
|
|
4207
4372
|
}
|
|
4208
4373
|
function runDetachedDevEcoAuthHost(requestPath) {
|
|
4209
|
-
const request = JSON.parse(
|
|
4374
|
+
const request = JSON.parse(readFileSync6(requestPath, "utf8"));
|
|
4210
4375
|
mkdirSync3(path24.dirname(request.stdout), { recursive: true });
|
|
4211
4376
|
mkdirSync3(path24.dirname(request.stderr), { recursive: true });
|
|
4212
4377
|
const stdout = openSync3(request.stdout, "a");
|
|
4213
4378
|
const stderr = openSync3(request.stderr, "a");
|
|
4214
4379
|
try {
|
|
4215
|
-
const child =
|
|
4380
|
+
const child = spawnCommand(request.command[0], request.command.slice(1), {
|
|
4216
4381
|
cwd: request.cwd,
|
|
4217
4382
|
detached: true,
|
|
4218
4383
|
env: { ...process.env, ...request.env ?? {} },
|
|
@@ -4220,6 +4385,13 @@ function runDetachedDevEcoAuthHost(requestPath) {
|
|
|
4220
4385
|
windowsHide: true
|
|
4221
4386
|
});
|
|
4222
4387
|
const stdin = child.stdin;
|
|
4388
|
+
if (!stdin) {
|
|
4389
|
+
try {
|
|
4390
|
+
child.kill();
|
|
4391
|
+
} catch {
|
|
4392
|
+
}
|
|
4393
|
+
throw new Error("DevEco CLI \u767B\u5F55\u8FDB\u7A0B\u7684 stdin \u4E0D\u53EF\u7528");
|
|
4394
|
+
}
|
|
4223
4395
|
stdin.on("error", () => {
|
|
4224
4396
|
});
|
|
4225
4397
|
stdin.write("\n");
|
|
@@ -4257,7 +4429,7 @@ function runDetachedDevEcoAuthHost(requestPath) {
|
|
|
4257
4429
|
function findLoginUrl(state) {
|
|
4258
4430
|
for (const file of [state.stdoutLog, state.stderrLog]) {
|
|
4259
4431
|
try {
|
|
4260
|
-
const match =
|
|
4432
|
+
const match = readFileSync6(file, "utf8").match(LOGIN_URL_PATTERN);
|
|
4261
4433
|
if (match) return match[0];
|
|
4262
4434
|
} catch {
|
|
4263
4435
|
}
|
|
@@ -4310,7 +4482,7 @@ async function managedDevEcoCliLogin(options) {
|
|
|
4310
4482
|
stdout: state.stdoutLog,
|
|
4311
4483
|
stderr: state.stderrLog,
|
|
4312
4484
|
command: devEcoCliSpawn(executable, ["auth", "login"]),
|
|
4313
|
-
env:
|
|
4485
|
+
env: devEcoCliEnvironment()
|
|
4314
4486
|
}, null, 2), "utf8");
|
|
4315
4487
|
launchHostOutsideRunner(requestPath, options.hostCommand);
|
|
4316
4488
|
progress(`\u5DF2\u6301\u4E45\u62C9\u8D77\u767B\u5F55\u8FDB\u7A0B\uFF08\u56DE\u8C03\u670D\u52A1\u5668\u968F\u8FDB\u7A0B\u5B58\u6D3B\uFF09\uFF0C\u65E5\u5FD7: ${state.stdoutLog}`);
|
|
@@ -4344,10 +4516,10 @@ async function managedDevEcoCliLogin(options) {
|
|
|
4344
4516
|
};
|
|
4345
4517
|
}
|
|
4346
4518
|
if (pid2 === null && existsSync6(state.exitFile)) {
|
|
4347
|
-
return failure(`\u767B\u5F55\u8FDB\u7A0B\u63D0\u524D\u9000\u51FA\uFF08exit ${
|
|
4519
|
+
return failure(`\u767B\u5F55\u8FDB\u7A0B\u63D0\u524D\u9000\u51FA\uFF08exit ${readFileSync6(state.exitFile, "utf8").trim()}\uFF09: ${tailFile(state.stderrLog, 800) || tailFile(state.stdoutLog, 800) || "\u65E0\u8F93\u51FA"}`);
|
|
4348
4520
|
}
|
|
4349
4521
|
if (pid2 !== null && !isAlive2(pid2) && !existsSync6(state.pidFile)) {
|
|
4350
|
-
return failure(`\u767B\u5F55\u8FDB\u7A0B\u63D0\u524D\u9000\u51FA\uFF08exit ${existsSync6(state.exitFile) ?
|
|
4522
|
+
return failure(`\u767B\u5F55\u8FDB\u7A0B\u63D0\u524D\u9000\u51FA\uFF08exit ${existsSync6(state.exitFile) ? readFileSync6(state.exitFile, "utf8").trim() : "unknown"}\uFF09: ${tailFile(state.stderrLog, 800) || tailFile(state.stdoutLog, 800) || "\u65E0\u8F93\u51FA"}`);
|
|
4351
4523
|
}
|
|
4352
4524
|
const remainingSeconds = Math.round((deadline - Date.now()) / 1e3);
|
|
4353
4525
|
if (lastCountdownSeconds - remainingSeconds >= 30) {
|
|
@@ -4776,13 +4948,13 @@ Select a scenario with query parameter \`?scenario=empty\` or header \`x-droid2h
|
|
|
4776
4948
|
}
|
|
4777
4949
|
|
|
4778
4950
|
// src/commands/logs.ts
|
|
4779
|
-
import { existsSync as existsSync7, readFileSync as
|
|
4951
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7, readdirSync as readdirSync4 } from "fs";
|
|
4780
4952
|
import path28 from "path";
|
|
4781
4953
|
function loadRecords(projectRoot) {
|
|
4782
4954
|
const directory = path28.join(migrationDirectory(projectRoot), "logs", "daily");
|
|
4783
4955
|
if (!existsSync7(directory)) return [];
|
|
4784
|
-
return
|
|
4785
|
-
(file) =>
|
|
4956
|
+
return readdirSync4(directory).filter((file) => file.endsWith(".jsonl")).sort().flatMap(
|
|
4957
|
+
(file) => readFileSync7(path28.join(directory, file), "utf8").split(/\r?\n/).filter(Boolean).map((line) => JSON.parse(line))
|
|
4786
4958
|
);
|
|
4787
4959
|
}
|
|
4788
4960
|
function queryCommandLogs(project, action, value) {
|
|
@@ -8296,7 +8468,7 @@ Usage:
|
|
|
8296
8468
|
droid2hmos config <init|validate> [project] [--harmony-project <path>]
|
|
8297
8469
|
droid2hmos build harmony [project] [--timeout-ms <ms>]
|
|
8298
8470
|
droid2hmos test harmony [project] [--runner arkts] (--class <class> [--case <case>] | --all) [--target <serial>] [--case-timeout-ms <ms>] [--ref <report-ref>...] [--timeout-ms <ms>]
|
|
8299
|
-
droid2hmos test harmony [project] --runner python --hypium-project <path> --test-list <name
|
|
8471
|
+
droid2hmos test harmony [project] --runner python --hypium-project <path> (--test-list <name>...|--all) [--target <serial>] [--python <path>] [--report-path <path>] [--ref <report-ref>...] [--timeout-ms <ms>]
|
|
8300
8472
|
droid2hmos report [project] [--require-complete]
|
|
8301
8473
|
droid2hmos report <init|validate|render> [project] [--require-complete]
|
|
8302
8474
|
droid2hmos report update [project] --ref <ref> [--status <status>] [--harmony-file <path>...] [--android-source <path>...] [--evidence <path>...] [--difference <text>|--clear-difference]
|
|
@@ -8479,7 +8651,7 @@ async function runCli(argv, runtime) {
|
|
|
8479
8651
|
const guardResult = guard("analyze:harmony", project);
|
|
8480
8652
|
const configPath = path36.join(migrationDirectory(projectRoot), "config.json");
|
|
8481
8653
|
if (!existsSync9(configPath)) throw new Error(`Migration config not found: ${configPath}`);
|
|
8482
|
-
const config = JSON.parse(
|
|
8654
|
+
const config = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
8483
8655
|
const configuredHarmony = config.harmonyProject ?? defaultHarmonyProjectPath(projectRoot);
|
|
8484
8656
|
const harmonyProject = path36.isAbsolute(configuredHarmony) ? configuredHarmony : path36.resolve(projectRoot, configuredHarmony);
|
|
8485
8657
|
const forwarded = ["build", harmonyProject, "--platform", "harmony"];
|
|
@@ -8640,7 +8812,7 @@ async function runCli(argv, runtime) {
|
|
|
8640
8812
|
const configPath = path36.join(migrationDirectory(projectRoot), "config.json");
|
|
8641
8813
|
if (!existsSync9(configPath)) throw new Error(`Migration config not found: ${configPath}`);
|
|
8642
8814
|
const guardResult = guard("build:harmony", projectRoot);
|
|
8643
|
-
const config = JSON.parse(
|
|
8815
|
+
const config = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
8644
8816
|
const configuredHarmony = config.harmonyProject ?? defaultHarmonyProjectPath(projectRoot);
|
|
8645
8817
|
const harmonyProject = path36.isAbsolute(configuredHarmony) ? configuredHarmony : path36.resolve(projectRoot, configuredHarmony);
|
|
8646
8818
|
let result;
|
|
@@ -8675,17 +8847,24 @@ async function runCli(argv, runtime) {
|
|
|
8675
8847
|
if (!Number.isFinite(caseTimeoutMs) || caseTimeoutMs <= 0) throw new CliError("--case-timeout-ms must be a positive number");
|
|
8676
8848
|
const configPath = path36.join(migrationDirectory(projectRoot), "config.json");
|
|
8677
8849
|
if (!existsSync9(configPath)) throw new Error(`Migration config not found: ${configPath}`);
|
|
8678
|
-
const config = JSON.parse(
|
|
8850
|
+
const config = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
8679
8851
|
const configuredHarmony = config.harmonyProject ?? defaultHarmonyProjectPath(projectRoot);
|
|
8680
8852
|
const harmonyProject = path36.isAbsolute(configuredHarmony) ? configuredHarmony : path36.resolve(projectRoot, configuredHarmony);
|
|
8681
8853
|
let result;
|
|
8682
8854
|
try {
|
|
8683
8855
|
if (runner === "python") {
|
|
8684
|
-
if (testClass || testCase
|
|
8856
|
+
if (testClass || testCase) throw new CliError("Python Hypium uses --test-list instead of --class or --case");
|
|
8685
8857
|
const hypiumProject = optionValue(args, "--hypium-project");
|
|
8686
|
-
const testLists = optionValues(args, "--test-list").flatMap((value) => value.split(";")).map((value) => value.trim()).filter(Boolean);
|
|
8687
8858
|
if (!hypiumProject) throw new CliError("Python Hypium requires --hypium-project");
|
|
8688
|
-
|
|
8859
|
+
let testLists = optionValues(args, "--test-list").flatMap((value) => value.split(";")).map((value) => value.trim()).filter(Boolean);
|
|
8860
|
+
if (fullRun) {
|
|
8861
|
+
const projectDir = path36.isAbsolute(hypiumProject) ? path36.resolve(hypiumProject) : path36.resolve(projectRoot, hypiumProject);
|
|
8862
|
+
const testcaseDir = path36.join(projectDir, "testcases");
|
|
8863
|
+
testLists = existsSync9(testcaseDir) ? readdirSync5(testcaseDir).filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/i, "")).sort() : [];
|
|
8864
|
+
if (!testLists.length) throw new CliError(`Python Hypium \u5168\u91CF\u56DE\u5F52\u672A\u53D1\u73B0\u7528\u4F8B\u914D\u7F6E\uFF08${testcaseDir}/*.json\uFF09`);
|
|
8865
|
+
} else if (!testLists.length) {
|
|
8866
|
+
throw new CliError("Python Hypium requires at least one --test-list");
|
|
8867
|
+
}
|
|
8689
8868
|
result = runHarmonyPythonHypiumTest({
|
|
8690
8869
|
projectRoot,
|
|
8691
8870
|
harmonyProject,
|
|
@@ -8790,7 +8969,7 @@ async function runCli(argv, runtime) {
|
|
|
8790
8969
|
const projectRoot = path36.resolve(project);
|
|
8791
8970
|
const configPath = path36.join(migrationDirectory(projectRoot), "config.json");
|
|
8792
8971
|
if (!existsSync9(configPath)) throw new Error(`Migration config not found: ${configPath}`);
|
|
8793
|
-
const config = JSON.parse(
|
|
8972
|
+
const config = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
8794
8973
|
const configuredHarmony = config.harmonyProject ?? defaultHarmonyProjectPath(projectRoot);
|
|
8795
8974
|
const harmonyProject = path36.isAbsolute(configuredHarmony) ? configuredHarmony : path36.resolve(projectRoot, configuredHarmony);
|
|
8796
8975
|
const timeoutMs = Number(optionValue(args, "--timeout-ms") ?? 5 * 60 * 1e3);
|
|
@@ -8838,7 +9017,7 @@ async function runCli(argv, runtime) {
|
|
|
8838
9017
|
let execution;
|
|
8839
9018
|
if (before.status !== "passed") execution = { status: "failed", skipped: true, summary: "Baseline evidence capture failed; interaction was not executed" };
|
|
8840
9019
|
else {
|
|
8841
|
-
const config = JSON.parse(
|
|
9020
|
+
const config = JSON.parse(readFileSync8(path36.join(migrationDirectory(projectRoot), "config.json"), "utf8"));
|
|
8842
9021
|
const harmonyProject = path36.isAbsolute(config.harmonyProject) ? config.harmonyProject : path36.resolve(projectRoot, config.harmonyProject);
|
|
8843
9022
|
const testClass = optionValue(args, "--class") ?? null;
|
|
8844
9023
|
const testCase = optionValue(args, "--case") ?? null;
|
|
@@ -8977,7 +9156,7 @@ var invokedHref = (() => {
|
|
|
8977
9156
|
if (invokedHref && invokedHref === entryHref) {
|
|
8978
9157
|
const argv = process.argv.slice(2);
|
|
8979
9158
|
const runtime = resolveRuntimePaths(import.meta.url);
|
|
8980
|
-
const version = runtime.packageRoot && existsSync9(path36.join(runtime.packageRoot, "package.json")) ? JSON.parse(
|
|
9159
|
+
const version = runtime.packageRoot && existsSync9(path36.join(runtime.packageRoot, "package.json")) ? JSON.parse(readFileSync8(path36.join(runtime.packageRoot, "package.json"), "utf8")).version ?? "unknown" : "unknown";
|
|
8981
9160
|
const excluded = /* @__PURE__ */ new Set(["help", "-h", "--help", "status", "internal", "dev", "logs"]);
|
|
8982
9161
|
const readOnlyTaskQuery = argv[0] === "task" && ["status", "next", "show"].includes(argv[1] ?? "");
|
|
8983
9162
|
Promise.resolve(excluded.has(argv[0] ?? "help") || readOnlyTaskQuery || process.env.DROID2HMOS_DISABLE_LOGGING === "1" ? runCli(argv, runtime) : withCommandLog(argv, version, () => runCli(argv, runtime))).then((exitCode) => {
|