Files
Genarrative/apps/ai-game-creator-shell/scripts/cargo-features.mjs
T
suzmii e7fa90ae18
Project CI / AI game creator shell Rust crates (pull_request) Successful in 1m28s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m4s
Project CI / Backend tests (pull_request) Successful in 3m43s
Project CI / Frontend tests (pull_request) Successful in 2m7s
Project CI / Native shell tests (pull_request) Successful in 5m38s
Project CI / AI game creator shell Rust lane 2/2 (pull_request) Successful in 8m37s
Project CI / AI game creator shell Rust lane 1/2 (pull_request) Successful in 9m14s
Project CI / AI game creator shell web tests (pull_request) Successful in 1m38s
Project CI / Repository checks (pull_request) Successful in 2m14s
修复AGC随包资源校验边界
修复变参 feature 解析、Windows Codex 缓存幂等性、插件缓存产物检查和插件根目录链接校验。

补齐 staging/backup 忽略规则与 feature 回归测试。
2026-10-01 11:35:27 +08:00

136 lines
5.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** 默认桌面能力;显式 feature 参数优先,不把应用参数当 Cargo 参数。 */
export function withDefaultCargoFeatures(argv, features) {
// 只看第一个 `--` 之前的 Tauri 选项:runner 参数区里的 `--features` 会与这里注入的
// 默认值在 Cargo 侧合并,不能当作「用户已经指定过了」而跳过注入。
if (!features.length || tauriOptions(argv).some(hasExplicitFeatures)) {
return argv;
}
return [`--features=${features.join(',')}`, ...argv];
}
/// 第一个 `--` 之前是 Tauri 自己的选项,之后是 runner(Cargo)参数。
function tauriOptions(argv) {
const separator = argv.indexOf('--');
return separator < 0 ? argv : argv.slice(0, separator);
}
/**
* 交给 Tauri 与 Cargo 的参数区间:第一个 `--` 之前是 Tauri 选项,之后到第二个 `--` 是
* runner(Cargo)参数;第二个 `--` 之后由 Tauri 转交应用,不属于构建参数。
* dev 入口(`buildTauriArguments` 会把启动器的单个 `--` 补成 runner + 应用两段)与发布
* 入口都用这一份区间解析,两边的目标与 feature 必须来自同一个口径。
*/
function cargoArguments(argv) {
const separator = argv.indexOf('--');
if (separator < 0) return argv;
const applicationStart = argv.indexOf('--', separator + 1);
return applicationStart < 0 ? argv : argv.slice(0, applicationStart);
}
/// 四种拼写(`--features x` / `--features=x` / `-f x` / `-fx`)都算显式指定。
function hasExplicitFeatures(value) {
return (
value === '--features' ||
value === '-f' ||
value.startsWith('--features=') ||
/^-f.+/u.test(value)
);
}
function parseFeatureNames(raw) {
return String(raw)
.split(/[\s,]+/u)
.map((name) => name.trim())
.filter(Boolean);
}
export function defaultEditorFeatures(target) {
return target === 'win32' || target.includes('windows')
? ['cocos-editor-execute', 'unity-editor-execute', 'godot-editor-execute']
: [];
}
/**
* 显式 Cargo 目标解析:`--target <triple>` / `--target=<triple>` / `-t <triple>`。
* 应用参数区(第二个 `--` 之后)不参与解析。未显式指定返回 undefined;取值缺失、
* 取到另一个选项或重复指定都失败关闭。
* dev 入口与发布入口共用这一份解析:cargo 的构建目标与随包资源 staging 目标
* 必须来自同一个显式来源,不能一方读参数、另一方回退宿主默认值。
*/
export function readCargoTarget(argv = []) {
const options = cargoArguments(argv);
let target;
for (let index = 0; index < options.length; index += 1) {
const argument = String(options[index]);
let value;
if (argument === '--target' || argument === '-t') {
value = options[index + 1];
index += 1;
} else if (argument.startsWith('--target=')) {
value = argument.slice('--target='.length);
} else if (argument.startsWith('-t') && argument.length > 2) {
value = argument.slice(2).replace(/^=/u, '');
} else {
continue;
}
if (!value?.trim() || String(value).startsWith('-')) {
throw new Error('--target 缺少有效目标');
}
if (target !== undefined) throw new Error('不能重复指定 --target');
target = String(value).trim();
}
return target;
}
/**
* 单一声明式解析:本次构建实际生效的编辑器 feature 集。
* 解析顺序:命令行 `--features`(Cargo 真正收到的参数,不能被环境覆盖)
* > 环境变量 `AGC_DEV_CARGO_FEATURES`(存在即以它为准,空串即关闭默认 feature)
* > 目标平台默认值。
* 传入的必须是「最终交给 Tauri 的参数」:dev 入口与发布入口的 cargo 参数与随包资源
* 准备步骤都消费这里的返回值,否则会出现「cargo 开了 feature、staging 没开(或反之)」。
*/
export function resolveEditorFeatures({
argv = [],
target,
env = process.env,
} = {}) {
const fromArgv = featuresFromArgv(argv);
if (fromArgv) {
return fromArgv;
}
// 变量存在本身即声明「本次 feature 集由环境决定」:空串是有意的关闭,不是未设置。
if (env.AGC_DEV_CARGO_FEATURES !== undefined) {
return parseFeatureNames(env.AGC_DEV_CARGO_FEATURES);
}
return defaultEditorFeatures(target);
}
/// 汇总 cargo 参数区里出现在任何位置的 `--features` / `-f`(Cargo 会把多个 flag 合并);
/// 没有任何 feature flag 时返回 null。显式但为空(如 `--features=`)返回空数组。
export function featuresFromArgv(argv = []) {
const options = cargoArguments(argv);
const features = [];
let found = false;
for (let index = 0; index < options.length; index += 1) {
const value = String(options[index]);
if (value.startsWith('--features=')) {
found = true;
features.push(...parseFeatureNames(value.slice('--features='.length)));
} else if (value === '--features' || value === '-f') {
found = true;
while (
index + 1 < options.length &&
!String(options[index + 1]).startsWith('-')
) {
index += 1;
features.push(...parseFeatureNames(options[index]));
}
} else if (value.startsWith('-f') && value.length > 2) {
found = true;
features.push(...parseFeatureNames(value.slice(2).replace(/^=/u, '')));
}
}
return found ? features : null;
}