Skip to content

Commit e3d832e

Browse files
author
Marvin Zhang
committed
feat: Enhance Rust build scripts and add binary copying functionality
1 parent b45c0a1 commit e3d832e

File tree

3 files changed

+152
-6
lines changed

3 files changed

+152
-6
lines changed

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828
"docs:dev": "pnpm --dir docs-site start",
2929
"docs:build": "pnpm --dir docs-site build",
3030
"docs:serve": "pnpm --dir docs-site serve",
31-
"rust:build": "cargo build --release --manifest-path rust/Cargo.toml",
32-
"rust:build:dev": "cargo build --manifest-path rust/Cargo.toml",
31+
"rust:build": "cargo build --release --manifest-path rust/Cargo.toml && node scripts/copy-rust-binaries.mjs",
32+
"rust:build:dev": "cargo build --manifest-path rust/Cargo.toml && node scripts/copy-rust-binaries.mjs",
33+
"rust:build:all": "cargo build --release --manifest-path rust/Cargo.toml && node scripts/copy-rust-binaries.mjs --all",
34+
"rust:copy": "node scripts/copy-rust-binaries.mjs",
3335
"rust:test": "cargo test --manifest-path rust/Cargo.toml",
3436
"rust:test:watch": "cargo watch -x 'test --manifest-path rust/Cargo.toml'",
3537
"rust:check": "cargo check --manifest-path rust/Cargo.toml",

packages/cli/bin/lean-spec-rust.js

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ const require = createRequire(import.meta.url);
2020
const __filename = fileURLToPath(import.meta.url);
2121
const __dirname = dirname(__filename);
2222

23+
// Debug mode - enable with LEANSPEC_DEBUG=1
24+
const DEBUG = process.env.LEANSPEC_DEBUG === '1';
25+
const debug = (...args) => DEBUG && console.error('[lean-spec debug]', ...args);
26+
2327
// Platform detection mapping
2428
const PLATFORM_MAP = {
2529
darwin: { x64: 'darwin-x64', arm64: 'darwin-arm64' },
@@ -31,6 +35,8 @@ function getBinaryPath() {
3135
const platform = process.platform;
3236
const arch = process.arch;
3337

38+
debug('Platform detection:', { platform, arch });
39+
3440
const platformKey = PLATFORM_MAP[platform]?.[arch];
3541
if (!platformKey) {
3642
console.error(`Unsupported platform: ${platform}-${arch}`);
@@ -41,21 +47,38 @@ function getBinaryPath() {
4147
const isWindows = platform === 'win32';
4248
const binaryName = isWindows ? 'lean-spec.exe' : 'lean-spec';
4349
const packageName = `lean-spec-${platformKey}`;
50+
51+
debug('Binary info:', { platformKey, binaryName, packageName });
4452

4553
// Try to resolve platform package
4654
try {
47-
return require.resolve(`${packageName}/${binaryName}`);
55+
const resolvedPath = require.resolve(`${packageName}/${binaryName}`);
56+
debug('Found platform package binary:', resolvedPath);
57+
return resolvedPath;
4858
} catch (e) {
49-
// Platform package not found
59+
debug('Platform package not found:', packageName, '-', e.message);
5060
}
5161

5262
// Try local binaries directory (for development/testing)
5363
try {
5464
const localPath = join(__dirname, '..', 'binaries', platformKey, binaryName);
65+
debug('Trying local binary:', localPath);
5566
accessSync(localPath);
67+
debug('Found local binary:', localPath);
5668
return localPath;
5769
} catch (e) {
58-
// Local binary not found
70+
debug('Local binary not found:', e.message);
71+
}
72+
73+
// Try rust/target/release directory (for local development)
74+
try {
75+
const rustTargetPath = join(__dirname, '..', '..', '..', 'rust', 'target', 'release', binaryName);
76+
debug('Trying rust target binary:', rustTargetPath);
77+
accessSync(rustTargetPath);
78+
debug('Found rust target binary:', rustTargetPath);
79+
return rustTargetPath;
80+
} catch (e) {
81+
debug('Rust target binary not found:', e.message);
5982
}
6083

6184
console.error(`Binary not found for ${platform}-${arch}`);
@@ -71,16 +94,23 @@ function getBinaryPath() {
7194

7295
// Execute binary
7396
const binaryPath = getBinaryPath();
74-
const child = spawn(binaryPath, process.argv.slice(2), {
97+
const args = process.argv.slice(2);
98+
99+
debug('Spawning binary:', binaryPath);
100+
debug('Arguments:', args);
101+
102+
const child = spawn(binaryPath, args, {
75103
stdio: 'inherit',
76104
windowsHide: true,
77105
});
78106

79107
child.on('exit', (code) => {
108+
debug('Binary exited with code:', code);
80109
process.exit(code ?? 1);
81110
});
82111

83112
child.on('error', (err) => {
84113
console.error('Failed to start lean-spec:', err.message);
114+
debug('Spawn error:', err);
85115
process.exit(1);
86116
});

scripts/copy-rust-binaries.mjs

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#!/usr/bin/env node
2+
/**
3+
* copy-rust-binaries.mjs
4+
*
5+
* Copies Rust binaries from rust/target/release to packages/{cli,mcp}/binaries/{platform}/
6+
* Automatically detects current platform and copies the appropriate binary.
7+
*
8+
* Usage:
9+
* node scripts/copy-rust-binaries.mjs # Copy current platform
10+
* node scripts/copy-rust-binaries.mjs --all # Copy all platforms (requires cross-compilation)
11+
*/
12+
import { promises as fs } from 'node:fs';
13+
import os from 'node:os';
14+
import path from 'node:path';
15+
import { fileURLToPath } from 'node:url';
16+
17+
const __filename = fileURLToPath(import.meta.url);
18+
const __dirname = path.dirname(__filename);
19+
const ROOT = path.resolve(__dirname, '..');
20+
21+
// Platform mapping
22+
const PLATFORM_MAP = {
23+
linux: { x64: 'linux-x64', arm64: 'linux-arm64' },
24+
darwin: { x64: 'darwin-x64', arm64: 'darwin-arm64' },
25+
win32: { x64: 'windows-x64', arm64: 'windows-arm64' }
26+
};
27+
28+
// All platforms for --all flag
29+
const ALL_PLATFORMS = [
30+
'darwin-x64',
31+
'darwin-arm64',
32+
'linux-x64',
33+
'linux-arm64',
34+
'windows-x64',
35+
];
36+
37+
function getCurrentPlatform() {
38+
const platform = process.platform;
39+
const arch = process.arch;
40+
const platformKey = PLATFORM_MAP[platform]?.[arch];
41+
42+
if (!platformKey) {
43+
throw new Error(`Unsupported platform: ${platform}-${arch}`);
44+
}
45+
46+
return platformKey;
47+
}
48+
49+
async function copyBinary(binaryName, platformKey) {
50+
const isWindows = platformKey.startsWith('windows-');
51+
const sourceExt = isWindows ? '.exe' : '';
52+
const sourcePath = path.join(ROOT, 'rust', 'target', 'release', `${binaryName}${sourceExt}`);
53+
54+
// Determine destination based on binary name
55+
const packagePath = binaryName === 'lean-spec' ? 'cli' : 'mcp';
56+
const destDir = path.join(ROOT, 'packages', packagePath, 'binaries', platformKey);
57+
const destPath = path.join(destDir, binaryName + sourceExt);
58+
59+
// Check if source exists
60+
try {
61+
await fs.access(sourcePath);
62+
} catch (e) {
63+
console.warn(`⚠️ Source binary not found: ${sourcePath}`);
64+
return false;
65+
}
66+
67+
// Ensure destination directory exists
68+
await fs.mkdir(destDir, { recursive: true });
69+
70+
// Copy binary
71+
await fs.copyFile(sourcePath, destPath);
72+
73+
// Make executable on Unix
74+
if (!isWindows) {
75+
await fs.chmod(destPath, 0o755);
76+
}
77+
78+
console.log(`✅ Copied ${binaryName} to ${packagePath}/binaries/${platformKey}/`);
79+
return true;
80+
}
81+
82+
async function main() {
83+
const args = process.argv.slice(2);
84+
const copyAll = args.includes('--all');
85+
86+
console.log('🔧 Copying Rust binaries...\n');
87+
88+
const binaries = ['lean-spec', 'leanspec-mcp'];
89+
90+
if (copyAll) {
91+
console.log('📦 Copying all platforms (requires cross-compiled binaries)\n');
92+
93+
for (const platformKey of ALL_PLATFORMS) {
94+
console.log(`\nPlatform: ${platformKey}`);
95+
for (const binary of binaries) {
96+
await copyBinary(binary, platformKey);
97+
}
98+
}
99+
} else {
100+
const currentPlatform = getCurrentPlatform();
101+
console.log(`📦 Copying for current platform: ${currentPlatform}\n`);
102+
103+
for (const binary of binaries) {
104+
await copyBinary(binary, currentPlatform);
105+
}
106+
}
107+
108+
console.log('\n✨ Done!');
109+
}
110+
111+
main().catch(err => {
112+
console.error('❌ Error:', err.message);
113+
process.exit(1);
114+
});

0 commit comments

Comments
 (0)