docker-backend / src /RuntimeDetector.ts
Karan6933's picture
Upload 93 files
c85705b verified
import path from 'path';
export type RuntimeType = 'node' | 'python' | 'static';
export interface RuntimeConfig {
type: RuntimeType;
installCommand: string[];
startCommand: string[];
image: string;
packageManager: 'npm' | 'yarn' | 'pnpm' | 'bun' | 'pip';
}
export class RuntimeDetector {
static detect(files: { path: string, content: string }[]): RuntimeConfig {
const filenames = files.map(f => f.path);
// Check for package manager hints
const hasYarn = filenames.includes('yarn.lock');
const hasPnpm = filenames.includes('pnpm-lock.yaml');
const hasBun = filenames.includes('bun.lockb');
const hasPackageLock = filenames.includes('package-lock.json');
// Default to npm, only use other package managers if lock file exists
let packageManager: 'npm' | 'yarn' | 'pnpm' | 'bun' = 'npm';
if (hasYarn) packageManager = 'yarn';
else if (hasPnpm) packageManager = 'pnpm';
else if (hasBun) packageManager = 'bun';
// 1. Node.js detection
if (filenames.includes('package.json')) {
const packageJsonFile = files.find(f => f.path === 'package.json');
let startCommand = ['bun', 'run', 'start'];
if (packageJsonFile) {
try {
const pkg = JSON.parse(packageJsonFile.content);
// Always use bun to run scripts — it's pre-installed and fast in the worker image
if (pkg.scripts?.dev) {
startCommand = ['bun', 'run', 'dev'];
} else if (pkg.scripts?.start) {
startCommand = ['bun', 'run', 'start'];
}
} catch (e) { }
}
// Always use bun for installation — it's pre-installed and much faster than npm in Docker
const installCmd = ['bun', 'install'];
return {
type: 'node',
installCommand: installCmd,
startCommand: startCommand,
image: 'coder-node',
packageManager: 'bun', // Always bun in Docker
};
}
// 2. Python detection
if (filenames.includes('requirements.txt') || filenames.some(f => f.endsWith('.py'))) {
let entryPoint = 'main.py';
if (filenames.includes('app.py')) entryPoint = 'app.py';
return {
type: 'python',
installCommand: filenames.includes('requirements.txt') ? [
'python3', '-m', 'venv', 'venv',
'&&', 'source', 'venv/bin/activate',
'&&', 'pip', 'install', '-r', 'requirements.txt'
] : [],
startCommand: [
'source', 'venv/bin/activate',
'&&', 'python3', '-u', entryPoint
],
image: 'coder-python',
packageManager: 'pip' as const,
};
}
// 3. C++ detection
if (filenames.some(f => f.endsWith('.cpp') || f.endsWith('.c'))) {
const cppFile = filenames.find(f => f.endsWith('.cpp') || f.endsWith('.c'))!;
return {
type: 'static',
installCommand: ['g++', cppFile, '-o', 'app'],
startCommand: ['./app'],
image: 'coder-node',
packageManager: 'npm' as const,
};
}
// 4. Static detection (Fallback)
return {
type: 'static',
installCommand: [],
startCommand: ['npx', 'serve', '.', '-p', '8000'],
image: 'coder-node',
packageManager: 'npm',
};
}
}