mirror of
https://github.com/phantomptr/ps5upload.git
synced 2026-10-22 11:53:22 -05:00
Upload, install, convert and manage PS5 game packages over the network. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
141 lines
5.3 KiB
JavaScript
Executable File
141 lines
5.3 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
import { spawnSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
|
|
const repoRoot = path.resolve(import.meta.dirname, "..");
|
|
const coverageRoot = path.join(repoRoot, "coverage");
|
|
const installTools = process.argv.includes("--install-tools");
|
|
const clientOnly = process.argv.includes("--client-only");
|
|
const engineOnly = process.argv.includes("--engine-only");
|
|
|
|
function run(label, command, args, opts = {}) {
|
|
process.stdout.write(`\n==> ${label}\n`);
|
|
const res = spawnSync(command, args, {
|
|
cwd: opts.cwd || repoRoot,
|
|
stdio: "inherit",
|
|
shell: os.platform() === "win32",
|
|
env: { ...process.env, ...opts.env },
|
|
});
|
|
if (res.status !== 0) {
|
|
process.stderr.write(`\ncoverage: ${label} failed with exit ${res.status}\n`);
|
|
process.exit(res.status || 1);
|
|
}
|
|
}
|
|
|
|
function existsOnPath(bin) {
|
|
if (os.platform() === "win32") {
|
|
return spawnSync("where", [bin], { stdio: "ignore" }).status === 0;
|
|
}
|
|
return spawnSync("sh", ["-c", "command -v \"$1\" >/dev/null 2>&1", "sh", bin], {
|
|
stdio: "ignore",
|
|
}).status === 0;
|
|
}
|
|
|
|
function firstExisting(paths) {
|
|
return paths.find((p) => fs.existsSync(p)) || null;
|
|
}
|
|
|
|
function llvmToolEnv() {
|
|
// Caller-provided override always wins.
|
|
if (process.env.LLVM_COV && process.env.LLVM_PROFDATA) return {};
|
|
|
|
// Prefer the llvm-tools that ship with the active rustup toolchain
|
|
// over anything on PATH. cargo-llvm-cov otherwise resolves
|
|
// llvm-profdata via PATH, which on GitHub's ubuntu-24.04 image
|
|
// picks up /usr/lib/llvm-18/bin/llvm-profdata — older than rustc's
|
|
// bundled LLVM and rejects current-rustc profraw with
|
|
// "raw profile version mismatch: Profile uses raw profile format
|
|
// version = 10; expected version = 9", failing the whole merge.
|
|
// The toolchain-shipped tools are guaranteed to match rustc's
|
|
// profraw output, so pin to them whenever they're present.
|
|
const sysrootRes = spawnSync("rustc", ["--print", "sysroot"], { encoding: "utf8" });
|
|
const hostRes = spawnSync("rustc", ["-vV"], { encoding: "utf8" });
|
|
if (sysrootRes.status === 0 && hostRes.status === 0) {
|
|
const sysroot = sysrootRes.stdout.trim();
|
|
const hostMatch = hostRes.stdout.match(/^host:\s*(.+)$/m);
|
|
if (sysroot && hostMatch) {
|
|
const exe = os.platform() === "win32" ? ".exe" : "";
|
|
const toolBin = path.join(sysroot, "lib", "rustlib", hostMatch[1].trim(), "bin");
|
|
const toolchainCov = path.join(toolBin, "llvm-cov" + exe);
|
|
const toolchainProfdata = path.join(toolBin, "llvm-profdata" + exe);
|
|
if (fs.existsSync(toolchainCov) && fs.existsSync(toolchainProfdata)) {
|
|
return { LLVM_COV: toolchainCov, LLVM_PROFDATA: toolchainProfdata };
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fallback: llvm-tools-preview isn't installed. Try PATH, then
|
|
// well-known LLVM prefixes. Version-mismatch risk is on the user
|
|
// here — but at least the script runs instead of failing outright.
|
|
if (existsOnPath("llvm-cov") && existsOnPath("llvm-profdata")) return {};
|
|
|
|
const prefixes = os.platform() === "darwin"
|
|
? ["/opt/homebrew/opt/llvm/bin", "/opt/homebrew/opt/llvm@22/bin", "/opt/homebrew/opt/llvm@18/bin", "/usr/local/opt/llvm/bin"]
|
|
: ["/usr/lib/llvm-18/bin", "/usr/lib/llvm-17/bin", "/usr/lib/llvm-16/bin", "/usr/bin"];
|
|
const llvmCov = firstExisting(prefixes.map((p) => path.join(p, "llvm-cov")));
|
|
const llvmProfdata = firstExisting(prefixes.map((p) => path.join(p, "llvm-profdata")));
|
|
if (llvmCov && llvmProfdata) {
|
|
return {
|
|
LLVM_COV: process.env.LLVM_COV || llvmCov,
|
|
LLVM_PROFDATA: process.env.LLVM_PROFDATA || llvmProfdata,
|
|
};
|
|
}
|
|
return {};
|
|
}
|
|
|
|
fs.mkdirSync(coverageRoot, { recursive: true });
|
|
|
|
if (!engineOnly) {
|
|
run("client vitest coverage", "npm", ["run", "test:coverage"], {
|
|
cwd: path.join(repoRoot, "client"),
|
|
});
|
|
}
|
|
|
|
if (clientOnly) {
|
|
process.stdout.write("\ncoverage reports:\n");
|
|
process.stdout.write(` client: ${path.relative(repoRoot, path.join(repoRoot, "client", "coverage", "index.html"))}\n`);
|
|
process.exit(0);
|
|
}
|
|
|
|
if (!existsOnPath("cargo-llvm-cov")) {
|
|
if (!installTools) {
|
|
process.stderr.write(
|
|
"\ncoverage: cargo-llvm-cov is not installed. Run `npm run coverage -- --install-tools` or install it with `cargo install cargo-llvm-cov --locked`.\n",
|
|
);
|
|
process.exit(1);
|
|
}
|
|
run("install cargo-llvm-cov", "cargo", ["install", "cargo-llvm-cov", "--locked"]);
|
|
}
|
|
|
|
fs.mkdirSync(path.join(coverageRoot, "engine"), { recursive: true });
|
|
const llvmEnv = llvmToolEnv();
|
|
run("engine llvm-cov lcov", "cargo", [
|
|
"llvm-cov",
|
|
"--workspace",
|
|
"--lcov",
|
|
"--output-path",
|
|
path.join("..", "coverage", "engine", "lcov.info"),
|
|
], {
|
|
cwd: path.join(repoRoot, "engine"),
|
|
env: llvmEnv,
|
|
});
|
|
run("engine llvm-cov html", "cargo", [
|
|
"llvm-cov",
|
|
"--workspace",
|
|
"--html",
|
|
"--output-dir",
|
|
path.join("..", "coverage", "engine"),
|
|
], {
|
|
cwd: path.join(repoRoot, "engine"),
|
|
env: llvmEnv,
|
|
});
|
|
|
|
process.stdout.write("\ncoverage reports:\n");
|
|
if (!engineOnly) {
|
|
process.stdout.write(` client: ${path.relative(repoRoot, path.join(repoRoot, "client", "coverage", "index.html"))}\n`);
|
|
}
|
|
process.stdout.write(` engine: ${path.relative(repoRoot, path.join(coverageRoot, "engine", "html", "index.html"))}\n`);
|
|
process.stdout.write(` lcov: ${path.relative(repoRoot, path.join(coverageRoot, "engine", "lcov.info"))}\n`);
|