fnva 0.0.21 → 0.0.23
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/README.md +3 -1
- package/bin/fnva.js +33 -30
- package/package.json +1 -2
- package/platforms/fnva +0 -0
- package/platforms/fnva.exe +0 -0
- package/scripts/check-permissions.js +21 -3
- package/scripts/check-style.sh +72 -0
- package/scripts/ensure-executable-permissions.js +45 -36
- package/scripts/format-code.sh +23 -0
package/README.md
CHANGED
|
@@ -487,7 +487,7 @@ description = "AnyCC 代理服务"
|
|
|
487
487
|
# 仓库配置
|
|
488
488
|
[repositories]
|
|
489
489
|
java = [
|
|
490
|
-
"https://mirrors.
|
|
490
|
+
"https://mirrors.tuna.tsinghua.edu.cn/Adoptium",
|
|
491
491
|
"https://api.adoptium.net/v3"
|
|
492
492
|
]
|
|
493
493
|
maven = [
|
|
@@ -496,6 +496,8 @@ maven = [
|
|
|
496
496
|
]
|
|
497
497
|
```
|
|
498
498
|
|
|
499
|
+
> Java downloads default to the Tsinghua Adoptium mirror (https://mirrors.tuna.tsinghua.edu.cn/Adoptium). For fully stable setups, manually maintain versions in ~/.fnva/config.toml [[java_environments]] and JAVA_HOME.
|
|
500
|
+
|
|
499
501
|
### 常用命令速查
|
|
500
502
|
|
|
501
503
|
| 命令 | 功能 | 示例 |
|
package/bin/fnva.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
const { spawnSync } = require('child_process');
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
|
+
const EncodingUtils = require('../lib/encoding-utils');
|
|
6
7
|
|
|
7
8
|
function resolvePlatform() {
|
|
8
9
|
switch (process.platform) {
|
|
@@ -132,21 +133,18 @@ function removeAutoFlag(args) {
|
|
|
132
133
|
function createTempScriptFile(script, envType, envName) {
|
|
133
134
|
try {
|
|
134
135
|
const os = require('os');
|
|
135
|
-
const fs = require('fs');
|
|
136
136
|
const path = require('path');
|
|
137
137
|
|
|
138
|
-
const
|
|
139
|
-
const scriptFile =
|
|
140
|
-
|
|
141
|
-
fs.writeFileSync(scriptFile, script, 'utf8');
|
|
138
|
+
const prefix = `fnva_${envType}_${envName}`;
|
|
139
|
+
const scriptFile = EncodingUtils.createTempPowerShellScript(script, prefix);
|
|
142
140
|
|
|
143
141
|
console.log('');
|
|
144
|
-
console.log('
|
|
142
|
+
console.log('[INFO] 环境已切换到当前进程。要在新的 PowerShell 窗口中使用此环境,运行:');
|
|
145
143
|
console.log(` ${scriptFile}`);
|
|
146
144
|
console.log(' 或者: fnva', envType, 'use', envName, '--auto');
|
|
147
145
|
|
|
148
146
|
} catch (error) {
|
|
149
|
-
console.warn('
|
|
147
|
+
console.warn('[WARN] 无法创建临时脚本文件:', error.message);
|
|
150
148
|
}
|
|
151
149
|
}
|
|
152
150
|
|
|
@@ -208,18 +206,18 @@ function applyEnvironmentVariables(envVars) {
|
|
|
208
206
|
}
|
|
209
207
|
|
|
210
208
|
function displaySuccessMessage(envType, envName, envVars) {
|
|
211
|
-
console.log(
|
|
209
|
+
console.log(`[OK] Switched to ${envType} environment: ${envName}`);
|
|
212
210
|
|
|
213
211
|
if (envVars.JAVA_HOME) {
|
|
214
|
-
console.log(
|
|
212
|
+
console.log(`[DIR] JAVA_HOME: ${envVars.JAVA_HOME}`);
|
|
215
213
|
}
|
|
216
214
|
|
|
217
215
|
if (envVars.ANTHROPIC_AUTH_TOKEN) {
|
|
218
|
-
console.log(
|
|
216
|
+
console.log(`[KEY] ANTHROPIC_AUTH_TOKEN: [已设置]`);
|
|
219
217
|
}
|
|
220
218
|
|
|
221
219
|
if (envVars.OPENAI_API_KEY) {
|
|
222
|
-
console.log(
|
|
220
|
+
console.log(`[KEY] OPENAI_API_KEY: [已设置]`);
|
|
223
221
|
}
|
|
224
222
|
}
|
|
225
223
|
|
|
@@ -227,7 +225,8 @@ function generateSimpleScript(envVars, envType, envName) {
|
|
|
227
225
|
const lines = [];
|
|
228
226
|
|
|
229
227
|
if (process.platform === 'win32') {
|
|
230
|
-
// Windows PowerShell
|
|
228
|
+
// Windows PowerShell - 使用编码工具设置
|
|
229
|
+
lines.push(EncodingUtils.generatePowerShellEncodingSetup());
|
|
231
230
|
lines.push(`Write-Host "Switched to ${envType} environment: ${envName}" -ForegroundColor Green`);
|
|
232
231
|
|
|
233
232
|
if (envVars.JAVA_HOME) {
|
|
@@ -381,6 +380,9 @@ function handleNodeOnlyMode(args) {
|
|
|
381
380
|
}
|
|
382
381
|
|
|
383
382
|
function run() {
|
|
383
|
+
// 设置Windows控制台编码
|
|
384
|
+
EncodingUtils.setWindowsConsoleEncoding();
|
|
385
|
+
|
|
384
386
|
const binaryPath = buildBinaryPath();
|
|
385
387
|
|
|
386
388
|
if (!binaryPath) {
|
|
@@ -432,11 +434,11 @@ function run() {
|
|
|
432
434
|
|
|
433
435
|
if (result.error) {
|
|
434
436
|
if (result.error.code === 'EACCES' && process.platform !== 'win32') {
|
|
435
|
-
console.error(
|
|
436
|
-
console.error(
|
|
437
|
-
console.error(`
|
|
437
|
+
console.error(`[ERROR] Permission denied. The fnva binary is not executable.`);
|
|
438
|
+
console.error(`[INFO] To fix this, run: sudo chmod +x "${binaryPath}"`);
|
|
439
|
+
console.error(`[INFO] Or reinstall: npm install -g fnva --force`);
|
|
438
440
|
} else {
|
|
439
|
-
console.error(`Failed to execute fnva: ${result.error.message}`);
|
|
441
|
+
console.error(`[ERROR] Failed to execute fnva: ${result.error.message}`);
|
|
440
442
|
}
|
|
441
443
|
process.exit(result.status ?? 1);
|
|
442
444
|
}
|
|
@@ -456,16 +458,16 @@ function run() {
|
|
|
456
458
|
// Windows:默认不启动新的会话;可通过 --session 开启旧行为
|
|
457
459
|
if (process.platform === 'win32') {
|
|
458
460
|
if (hasSessionFlag(args)) {
|
|
459
|
-
console.log(
|
|
460
|
-
console.log(
|
|
461
|
+
console.log(`[OK] Switched to ${envType} environment: ${envName}`);
|
|
462
|
+
console.log(`[INFO] Starting new PowerShell session with ${envName} environment...`);
|
|
461
463
|
console.log(`Type "exit" to return to previous session\n`);
|
|
462
464
|
|
|
463
465
|
try {
|
|
464
466
|
const os = require('os');
|
|
465
|
-
const fs = require('fs');
|
|
466
467
|
const tempScript = os.tmpdir() + '\\fnva_env_' + Date.now() + '.ps1';
|
|
467
468
|
const fullScript = script + '\n';
|
|
468
|
-
|
|
469
|
+
// 使用编码工具写入文件
|
|
470
|
+
EncodingUtils.writeFileWithEncoding(tempScript, fullScript);
|
|
469
471
|
const { spawn } = require('child_process');
|
|
470
472
|
const ps = spawn('powershell', ['-NoExit', '-ExecutionPolicy', 'Bypass', '-File', tempScript], {
|
|
471
473
|
stdio: 'inherit',
|
|
@@ -473,7 +475,7 @@ function run() {
|
|
|
473
475
|
});
|
|
474
476
|
ps.on('exit', () => {
|
|
475
477
|
try { fs.unlinkSync(tempScript); } catch (_) {}
|
|
476
|
-
console.log('
|
|
478
|
+
console.log('[INFO] Returned to original session');
|
|
477
479
|
});
|
|
478
480
|
return;
|
|
479
481
|
} catch (error) {
|
|
@@ -501,7 +503,8 @@ function run() {
|
|
|
501
503
|
|
|
502
504
|
try {
|
|
503
505
|
const tempFile = path.join(os.tmpdir(), `fnva_auto_${Date.now()}.ps1`);
|
|
504
|
-
|
|
506
|
+
// 使用编码工具写入文件
|
|
507
|
+
EncodingUtils.writeFileWithEncoding(tempFile, simpleScript);
|
|
505
508
|
|
|
506
509
|
// 使用 PowerShell 执行脚本
|
|
507
510
|
spawn('powershell', ['-ExecutionPolicy', 'Bypass', '-File', tempFile], {
|
|
@@ -511,10 +514,10 @@ function run() {
|
|
|
511
514
|
try { fs.unlinkSync(tempFile); } catch (_) {}
|
|
512
515
|
});
|
|
513
516
|
|
|
514
|
-
console.log('
|
|
517
|
+
console.log('[OK] 环境已自动切换');
|
|
515
518
|
return;
|
|
516
519
|
} catch (error) {
|
|
517
|
-
console.warn('
|
|
520
|
+
console.warn('[WARN] 自动执行失败,回退到脚本输出');
|
|
518
521
|
}
|
|
519
522
|
}
|
|
520
523
|
|
|
@@ -524,9 +527,9 @@ function run() {
|
|
|
524
527
|
}
|
|
525
528
|
} else {
|
|
526
529
|
// Unix-like systems: 显示使用说明
|
|
527
|
-
console.log(
|
|
530
|
+
console.log(`[OK] Switched to ${envType} environment: ${envName}`);
|
|
528
531
|
console.log('');
|
|
529
|
-
console.log('
|
|
532
|
+
console.log('[INFO] To apply this environment, run:');
|
|
530
533
|
console.log(` node bin/fnva.js ${args.join(' ')} | bash`);
|
|
531
534
|
}
|
|
532
535
|
} else {
|
|
@@ -548,11 +551,11 @@ function run() {
|
|
|
548
551
|
|
|
549
552
|
if (result.error) {
|
|
550
553
|
if (result.error.code === 'EACCES' && process.platform !== 'win32') {
|
|
551
|
-
console.error(
|
|
552
|
-
console.error(
|
|
553
|
-
console.error(`
|
|
554
|
+
console.error(`[ERROR] Permission denied. The fnva binary is not executable.`);
|
|
555
|
+
console.error(`[INFO] To fix this, run: sudo chmod +x "${binaryPath}"`);
|
|
556
|
+
console.error(`[INFO] Or reinstall: npm install -g fnva --force`);
|
|
554
557
|
} else {
|
|
555
|
-
console.error(`Failed to execute fnva: ${result.error.message}`);
|
|
558
|
+
console.error(`[ERROR] Failed to execute fnva: ${result.error.message}`);
|
|
556
559
|
}
|
|
557
560
|
process.exit(result.status ?? 1);
|
|
558
561
|
}
|
package/package.json
CHANGED
package/platforms/fnva
CHANGED
|
Binary file
|
package/platforms/fnva.exe
CHANGED
|
Binary file
|
|
@@ -4,7 +4,7 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* 检查platforms目录中二进制文件的权限
|
|
7
|
+
* 检查 platforms 目录中二进制文件的权限
|
|
8
8
|
*/
|
|
9
9
|
function checkPermissions() {
|
|
10
10
|
console.log('🔍 检查二进制文件权限...');
|
|
@@ -12,13 +12,14 @@ function checkPermissions() {
|
|
|
12
12
|
const platformsDir = path.join(__dirname, '..', 'platforms');
|
|
13
13
|
|
|
14
14
|
if (!fs.existsSync(platformsDir)) {
|
|
15
|
-
console.log('❌ platforms目录不存在');
|
|
15
|
+
console.log('❌ platforms 目录不存在');
|
|
16
16
|
process.exit(1);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const platforms = fs.readdirSync(platformsDir);
|
|
20
20
|
let allGood = true;
|
|
21
21
|
|
|
22
|
+
// 优先检查新的 platform-arch 目录结构
|
|
22
23
|
for (const platform of platforms) {
|
|
23
24
|
const platformDir = path.join(platformsDir, platform);
|
|
24
25
|
|
|
@@ -43,6 +44,22 @@ function checkPermissions() {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
// 额外检查一次扁平结构: platforms/fnva
|
|
48
|
+
const flatBinaryName = process.platform === 'win32' ? 'fnva.exe' : 'fnva';
|
|
49
|
+
const flatBinaryPath = path.join(platformsDir, flatBinaryName);
|
|
50
|
+
|
|
51
|
+
if (fs.existsSync(flatBinaryPath)) {
|
|
52
|
+
const stats = fs.statSync(flatBinaryPath);
|
|
53
|
+
const hasExecPermission = (stats.mode & 0o111) !== 0;
|
|
54
|
+
const mode = stats.mode.toString(8).padStart(4, '0');
|
|
55
|
+
|
|
56
|
+
console.log(` (legacy)/${flatBinaryName}: ${mode} ${hasExecPermission ? '✅' : '❌'}`);
|
|
57
|
+
|
|
58
|
+
if (!hasExecPermission && flatBinaryName !== 'fnva.exe') {
|
|
59
|
+
allGood = false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
46
63
|
console.log(`\n${allGood ? '✅' : '❌'} 权限检查${allGood ? '通过' : '失败'}`);
|
|
47
64
|
|
|
48
65
|
if (!allGood) {
|
|
@@ -56,4 +73,5 @@ if (require.main === module) {
|
|
|
56
73
|
checkPermissions();
|
|
57
74
|
}
|
|
58
75
|
|
|
59
|
-
module.exports = { checkPermissions };
|
|
76
|
+
module.exports = { checkPermissions };
|
|
77
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 代码风格检查脚本
|
|
4
|
+
# 用于检查和格式化fnva项目的代码风格
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
echo "🔍 开始代码风格检查..."
|
|
9
|
+
|
|
10
|
+
# 检查是否安装了必要的工具
|
|
11
|
+
check_tool() {
|
|
12
|
+
if ! command -v $1 &> /dev/null; then
|
|
13
|
+
echo "❌ $1 未安装,请先安装 $1"
|
|
14
|
+
echo "安装命令: cargo install $1"
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
echo "📦 检查工具是否安装..."
|
|
20
|
+
check_tool "rustfmt"
|
|
21
|
+
check_tool "clippy"
|
|
22
|
+
|
|
23
|
+
# 运行rustfmt格式化代码
|
|
24
|
+
echo "🎨 格式化代码..."
|
|
25
|
+
cargo fmt --all
|
|
26
|
+
|
|
27
|
+
# 运行clippy检查
|
|
28
|
+
echo "🔍 运行Clippy静态分析..."
|
|
29
|
+
cargo clippy --all-targets --all-features -- -D warnings
|
|
30
|
+
|
|
31
|
+
# 检查是否有未提交的格式化更改
|
|
32
|
+
echo "📝 检查格式化结果..."
|
|
33
|
+
if ! git diff --exit-code --quiet; then
|
|
34
|
+
echo "⚠️ 代码格式化产生了更改,请提交这些更改"
|
|
35
|
+
echo "运行 'git add .' 和 'git commit' 来提交格式化结果"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
# 检查文档注释
|
|
40
|
+
echo "📚 检查文档注释..."
|
|
41
|
+
cargo doc --no-deps --document-private-items 2>/dev/null | grep -E "(warning|error)" || true
|
|
42
|
+
|
|
43
|
+
# 检查重复的代码
|
|
44
|
+
echo "🔄 检查重复代码..."
|
|
45
|
+
if command -v cargo-dup &> /dev/null; then
|
|
46
|
+
cargo dup
|
|
47
|
+
else
|
|
48
|
+
echo "💡 提示: 安装 cargo-dup 可以检查重复代码 (cargo install cargo-dup)"
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# 检查依赖安全性
|
|
52
|
+
echo "🔒 检查依赖安全性..."
|
|
53
|
+
if command -v cargo-audit &> /dev/null; then
|
|
54
|
+
cargo audit
|
|
55
|
+
else
|
|
56
|
+
echo "💡 提示: 安装 cargo-audit 可以检查依赖安全性 (cargo install cargo-audit)"
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# 检查未使用的依赖
|
|
60
|
+
echo "🧹 检查未使用的依赖..."
|
|
61
|
+
if command -v cargo-udeps &> /dev/null; then
|
|
62
|
+
cargo udeps --all-targets
|
|
63
|
+
else
|
|
64
|
+
echo "💡 提示: 安装 cargo-udeps 可以检查未使用的依赖 (cargo install cargo-udeps)"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# 统计代码行数
|
|
68
|
+
echo "📊 代码统计:"
|
|
69
|
+
echo "总Rust代码行数: $(find src -name '*.rs' -exec wc -l {} + | tail -1)"
|
|
70
|
+
echo "测试代码行数: $(find tests -name '*.rs' -exec wc -l {} + 2>/dev/null | tail -1 || echo "0")"
|
|
71
|
+
|
|
72
|
+
echo "✅ 代码风格检查完成!"
|
|
@@ -4,8 +4,8 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* 确保fnva二进制文件有可执行权限
|
|
8
|
-
*
|
|
7
|
+
* 确保 fnva 二进制文件有可执行权限
|
|
8
|
+
* 这是一个全局的 postinstall 脚本,处理本地安装和全局安装的权限问题
|
|
9
9
|
*/
|
|
10
10
|
function ensureExecutablePermissions() {
|
|
11
11
|
try {
|
|
@@ -13,82 +13,92 @@ function ensureExecutablePermissions() {
|
|
|
13
13
|
const projectRoot = path.resolve(scriptDir, '..');
|
|
14
14
|
const platformsDir = path.join(projectRoot, 'platforms');
|
|
15
15
|
|
|
16
|
-
console.log('
|
|
16
|
+
console.log('✅ Ensuring fnva binary permissions...');
|
|
17
17
|
|
|
18
|
-
// 如果没有platforms目录,说明是开发模式,不需要处理
|
|
18
|
+
// 如果没有 platforms 目录,说明是开发模式,不需要处理
|
|
19
19
|
if (!fs.existsSync(platformsDir)) {
|
|
20
20
|
console.log('ℹ️ No platforms directory found, skipping permission check');
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
// 检测当前平台
|
|
25
24
|
const platform = process.platform;
|
|
26
25
|
const arch = process.arch === 'arm64' ? 'arm64' : 'x64';
|
|
27
26
|
const platformDir = `${platform}-${arch}`;
|
|
28
27
|
|
|
29
|
-
// 确定二进制文件名和路径
|
|
30
28
|
const binaryName = platform === 'win32' ? 'fnva.exe' : 'fnva';
|
|
31
|
-
const
|
|
29
|
+
const archBinaryPath = path.join(platformsDir, platformDir, binaryName);
|
|
30
|
+
const flatBinaryPath = path.join(platformsDir, binaryName);
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
/**
|
|
33
|
+
* 确保指定路径的二进制文件具有可执行权限,并做一次简单的运行测试
|
|
34
|
+
*/
|
|
35
|
+
function ensureExecutable(binaryPath, label) {
|
|
35
36
|
try {
|
|
36
37
|
const stats = fs.statSync(binaryPath);
|
|
37
38
|
const hasExecPermission = (stats.mode & 0o111) !== 0;
|
|
38
39
|
|
|
39
|
-
console.log(`📍 Checking binary: ${binaryPath}`);
|
|
40
|
+
console.log(`📍 Checking binary (${label}): ${binaryPath}`);
|
|
40
41
|
console.log(` Current permissions: ${(stats.mode & 0o777).toString(8)}`);
|
|
41
42
|
|
|
42
43
|
if (!hasExecPermission) {
|
|
43
|
-
console.log(
|
|
44
|
+
console.log('🔧 Setting executable permissions...');
|
|
44
45
|
fs.chmodSync(binaryPath, 0o755); // rwxr-xr-x
|
|
45
46
|
|
|
46
|
-
// 验证权限设置成功
|
|
47
47
|
const newStats = fs.statSync(binaryPath);
|
|
48
48
|
const newHasExecPermission = (newStats.mode & 0o111) !== 0;
|
|
49
49
|
|
|
50
50
|
if (newHasExecPermission) {
|
|
51
|
-
console.log(`✅ Successfully set executable permissions (${
|
|
51
|
+
console.log(`✅ Successfully set executable permissions (${label})`);
|
|
52
52
|
} else {
|
|
53
|
-
console.log(`❌ Failed to set executable permissions (${
|
|
53
|
+
console.log(`❌ Failed to set executable permissions (${label})`);
|
|
54
54
|
console.log(` New permissions: ${(newStats.mode & 0o777).toString(8)}`);
|
|
55
55
|
console.log(` Manual fix may be required: chmod +x "${binaryPath}"`);
|
|
56
56
|
}
|
|
57
57
|
} else {
|
|
58
|
-
console.log(`✅ fnva binary already has executable permissions (${
|
|
58
|
+
console.log(`✅ fnva binary already has executable permissions (${label})`);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
//
|
|
61
|
+
// 尝试执行一次 --version 做简单验证
|
|
62
62
|
try {
|
|
63
63
|
const { spawnSync } = require('child_process');
|
|
64
64
|
const testResult = spawnSync(binaryPath, ['--version'], {
|
|
65
65
|
encoding: 'utf8',
|
|
66
66
|
timeout: 3000,
|
|
67
|
-
stdio: 'pipe'
|
|
67
|
+
stdio: 'pipe',
|
|
68
68
|
});
|
|
69
69
|
|
|
70
|
-
if (testResult.status === 0 || testResult.status === 1) {
|
|
71
|
-
console.log(
|
|
70
|
+
if (testResult.status === 0 || testResult.status === 1) {
|
|
71
|
+
console.log('✅ fnva binary is executable and responding');
|
|
72
72
|
} else if (testResult.error && testResult.error.code === 'EACCES') {
|
|
73
|
-
console.log(
|
|
73
|
+
console.log('❌ fnva binary still has permission issues');
|
|
74
74
|
console.log(` Manual fix required: chmod +x "${binaryPath}"`);
|
|
75
75
|
}
|
|
76
|
-
} catch
|
|
77
|
-
//
|
|
76
|
+
} catch {
|
|
77
|
+
// 测试失败不视为致命错误,可能是二进制本身的问题
|
|
78
78
|
}
|
|
79
|
-
|
|
80
79
|
} catch (error) {
|
|
81
|
-
console.warn(`⚠️ Could not fix binary permissions: ${error.message}`);
|
|
80
|
+
console.warn(`⚠️ Could not fix binary permissions (${label}): ${error.message}`);
|
|
82
81
|
console.log(` Manual fix required: chmod +x "${binaryPath}"`);
|
|
83
82
|
}
|
|
84
|
-
}
|
|
85
|
-
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Windows 不需要 chmod,可直接跳过
|
|
86
|
+
if (platform === 'win32') {
|
|
87
|
+
console.log('ℹ️ Windows platform detected, skipping permission check');
|
|
88
|
+
} else if (fs.existsSync(archBinaryPath)) {
|
|
89
|
+
// 优先处理新的平台子目录结构: platforms/<platform>-<arch>/fnva
|
|
90
|
+
ensureExecutable(archBinaryPath, platformDir);
|
|
91
|
+
} else if (fs.existsSync(flatBinaryPath)) {
|
|
92
|
+
// 兼容旧版本扁平结构: platforms/fnva
|
|
93
|
+
console.log('ℹ️ Platform-specific binary not found, falling back to legacy flat layout');
|
|
94
|
+
ensureExecutable(flatBinaryPath, 'platforms/fnva');
|
|
86
95
|
} else {
|
|
87
|
-
console.log(`❌ Binary not found: ${
|
|
88
|
-
console.log(`
|
|
96
|
+
console.log(`❌ Binary not found: ${archBinaryPath}`);
|
|
97
|
+
console.log(` Also checked legacy path: ${flatBinaryPath}`);
|
|
98
|
+
console.log(' This might indicate an incomplete installation');
|
|
89
99
|
}
|
|
90
100
|
|
|
91
|
-
//
|
|
101
|
+
// 额外检查:如果是全局安装,也尝试检查路径上的 fnva 权限
|
|
92
102
|
if (process.env.npm_config_global === 'true') {
|
|
93
103
|
try {
|
|
94
104
|
const { execSync } = require('child_process');
|
|
@@ -101,22 +111,21 @@ function ensureExecutablePermissions() {
|
|
|
101
111
|
const globalHasExecPermission = (globalStats.mode & 0o111) !== 0;
|
|
102
112
|
|
|
103
113
|
if (!globalHasExecPermission) {
|
|
104
|
-
console.log(
|
|
114
|
+
console.log('❌ Global fnva binary lacks executable permissions');
|
|
105
115
|
console.log(` Please run: sudo chmod +x "${globalFnvaPath}"`);
|
|
106
116
|
} else {
|
|
107
|
-
console.log(
|
|
117
|
+
console.log('✅ Global fnva binary has correct permissions');
|
|
108
118
|
}
|
|
109
119
|
}
|
|
110
|
-
} catch
|
|
111
|
-
|
|
112
|
-
console.log(`ℹ️ Could not verify global installation`);
|
|
120
|
+
} catch {
|
|
121
|
+
console.log('ℹ️ Could not verify global installation');
|
|
113
122
|
}
|
|
114
123
|
}
|
|
115
|
-
|
|
116
124
|
} catch (error) {
|
|
117
125
|
console.warn(`⚠️ Permission check failed: ${error.message}`);
|
|
118
126
|
}
|
|
119
127
|
}
|
|
120
128
|
|
|
121
129
|
// 运行权限检查
|
|
122
|
-
ensureExecutablePermissions();
|
|
130
|
+
ensureExecutablePermissions();
|
|
131
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 代码格式化脚本
|
|
4
|
+
# 自动格式化fnva项目的代码
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
echo "🎨 开始格式化代码..."
|
|
9
|
+
|
|
10
|
+
# 格式化所有Rust代码
|
|
11
|
+
cargo fmt --all
|
|
12
|
+
|
|
13
|
+
# 检查格式化结果
|
|
14
|
+
if git diff --exit-code --quiet; then
|
|
15
|
+
echo "✅ 代码已经是标准格式"
|
|
16
|
+
else
|
|
17
|
+
echo "📝 代码已格式化,请查看更改:"
|
|
18
|
+
git diff --stat
|
|
19
|
+
echo ""
|
|
20
|
+
echo "💡 提示: 使用 'git add .' 和 'git commit' 提交格式化更改"
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
echo "✅ 格式化完成!"
|