修复AGC随包资源校验边界
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
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
修复变参 feature 解析、Windows Codex 缓存幂等性、插件缓存产物检查和插件根目录链接校验。 补齐 staging/backup 忽略规则与 feature 回归测试。
This commit is contained in:
@@ -60,6 +60,10 @@ temp*build*/
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/node-runtime-staging-*/
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/plugins-staging-*/
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/codex/*-staging-*/
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/plugins-backup-*/
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/codex/*-backup-*/
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/claude-agent-staging-*/
|
||||
/apps/ai-game-creator-shell/src-tauri/resources/claude-agent-backup-*/
|
||||
/apps/ai-game-creator-shell/.llm-drafts/
|
||||
/apps/ai-game-creator-shell/game-creator.config.local.json
|
||||
/apps/mobile-shell/.expo/
|
||||
|
||||
@@ -499,6 +499,15 @@ export function runTauriBuild(
|
||||
const resourceTarget =
|
||||
explicitBuildTarget(args) ||
|
||||
(bundling ? context.target : supportedHostTarget(platform, arch));
|
||||
if (
|
||||
!bundling &&
|
||||
!resourceTarget &&
|
||||
defaultEditorFeatures(platform).length > 0
|
||||
) {
|
||||
throw new Error(
|
||||
`当前宿主 ${platform}/${arch} 不在随包资源声明覆盖内;请用 --target 指定受支持的构建目标`,
|
||||
);
|
||||
}
|
||||
const features = resolveEditorFeatures({
|
||||
argv: tauriArguments,
|
||||
target: resourceTarget ?? platform,
|
||||
|
||||
@@ -39,7 +39,7 @@ function hasExplicitFeatures(value) {
|
||||
|
||||
function parseFeatureNames(raw) {
|
||||
return String(raw)
|
||||
.split(',')
|
||||
.split(/[\s,]+/u)
|
||||
.map((name) => name.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
@@ -119,11 +119,12 @@ export function featuresFromArgv(argv = []) {
|
||||
features.push(...parseFeatureNames(value.slice('--features='.length)));
|
||||
} else if (value === '--features' || value === '-f') {
|
||||
found = true;
|
||||
index += 1;
|
||||
const next = options[index];
|
||||
// 变参 flag:后面不是选项时才是它的取值。
|
||||
if (next !== undefined && !String(next).startsWith('-')) {
|
||||
features.push(...parseFeatureNames(next));
|
||||
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;
|
||||
|
||||
@@ -2,7 +2,10 @@ import assert from 'node:assert/strict';
|
||||
import { test } from 'node:test';
|
||||
|
||||
import { buildTauriBuildArguments } from './build-release.mjs';
|
||||
import { withDefaultCargoFeatures } from './cargo-features.mjs';
|
||||
import {
|
||||
featuresFromArgv,
|
||||
withDefaultCargoFeatures,
|
||||
} from './cargo-features.mjs';
|
||||
|
||||
test('Windows release includes the same editor feature as development', () => {
|
||||
assert.deepEqual(
|
||||
@@ -47,3 +50,16 @@ test('explicit Cargo features override defaults in every supported spelling', ()
|
||||
['--features=cocos-editor-execute', '--', '--features=app'],
|
||||
);
|
||||
});
|
||||
|
||||
test('features 变参会完整消费空格与逗号分隔的值', () => {
|
||||
assert.deepEqual(
|
||||
featuresFromArgv([
|
||||
'-f',
|
||||
'cocos-editor-execute,unity-editor-execute',
|
||||
'godot-editor-execute',
|
||||
'--target',
|
||||
'x86_64-pc-windows-msvc',
|
||||
]),
|
||||
['cocos-editor-execute', 'unity-editor-execute', 'godot-editor-execute'],
|
||||
);
|
||||
});
|
||||
|
||||
@@ -374,7 +374,11 @@ function unitMatchesExisting(unitPath, declaration, unit, desired) {
|
||||
if (info.size !== file.size || sha256File(filePath) !== file.sha256) {
|
||||
return false;
|
||||
}
|
||||
if (relative === member.layout.executable && (info.mode & 0o111) === 0) {
|
||||
if (
|
||||
process.platform !== 'win32' &&
|
||||
relative === member.layout.executable &&
|
||||
(info.mode & 0o111) === 0
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1084,6 +1088,10 @@ function pluginTreeMatches(
|
||||
sourceRoot,
|
||||
'插件资源',
|
||||
)) {
|
||||
const staged = path.join(stagedDirectory, relative);
|
||||
if (!existsSync(staged)) {
|
||||
return false;
|
||||
}
|
||||
allowedFiles.add(`${relativePrefix}${relative}`);
|
||||
}
|
||||
continue;
|
||||
@@ -1117,6 +1125,14 @@ function pluginTreeMatches(
|
||||
libraryStagingEnabled(staging, target, features)
|
||||
) {
|
||||
for (const relative of staging.files) {
|
||||
const staged = path.join(
|
||||
pluginDestination,
|
||||
staging.sourceSubdirectory,
|
||||
relative,
|
||||
);
|
||||
if (!existsSync(staged)) {
|
||||
return false;
|
||||
}
|
||||
allowedFiles.add(
|
||||
`${plugin.name}/${staging.sourceSubdirectory}/${relative}`,
|
||||
);
|
||||
@@ -1128,9 +1144,11 @@ function pluginTreeMatches(
|
||||
plugin.name === payload.plugin &&
|
||||
nativePayloadEnabled(payload, target, features)
|
||||
) {
|
||||
allowedFiles.add(
|
||||
`${plugin.name}/${payload.destinationSubdirectory}/${payload.destinationFileName ?? payload.sourceFileName}`,
|
||||
);
|
||||
const relative = `${payload.destinationSubdirectory}/${payload.destinationFileName ?? payload.sourceFileName}`;
|
||||
if (!existsSync(path.join(pluginDestination, relative))) {
|
||||
return false;
|
||||
}
|
||||
allowedFiles.add(`${plugin.name}/${relative}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,12 +308,19 @@ pub fn validate_staged_plugins(
|
||||
if !plugin_staging_applies(target) {
|
||||
return Ok(());
|
||||
}
|
||||
if !destination_root.is_dir() {
|
||||
let metadata = std::fs::symlink_metadata(destination_root).map_err(|error| {
|
||||
format!(
|
||||
"插件随包资源目录不可读 {}:{error}",
|
||||
destination_root.display()
|
||||
)
|
||||
})?;
|
||||
if metadata.file_type().is_symlink() || !metadata.is_dir() {
|
||||
return Err(format!(
|
||||
"插件随包资源目录缺失:{}",
|
||||
"插件随包资源目录缺失或不允许符号链接:{}",
|
||||
destination_root.display()
|
||||
));
|
||||
}
|
||||
|
||||
let declared_plugins = plugin_directories(source_root, plugins().manifest_file_name)?;
|
||||
let declared_names = declared_plugins
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user