Files
2026-01-03 20:17:49 +00:00

155 lines
3.9 KiB
TypeScript

import { execSync } from 'child_process'
import fs from 'fs'
import path from 'path'
import os from 'os'
import { log } from './logging'
import type { ExecResult, ExecOptions } from './types'
export const execCommand = (command: string, cppDir: string, options: ExecOptions = {}): ExecResult => {
try {
const result = execSync(command, {
cwd: options.cwd || cppDir,
encoding: 'utf-8',
stdio: options.silent ? 'pipe' : 'inherit',
})
return { success: true, output: result as string }
} catch (error: unknown) {
const execError = error as { message?: string; stdout?: string }
return { success: false, error: execError.message, output: execError.stdout }
}
}
export const ensureConanFile = (cppDir: string): boolean => {
log.section('Checking Conanfile')
const conanfilePath = path.join(cppDir, 'conanfile.txt')
if (fs.existsSync(conanfilePath)) {
log.success('conanfile.txt exists')
return true
}
log.info('Creating conanfile.txt...')
const conanfileContent = `[requires]
sqlite3/3.45.0
fmt/10.2.1
spdlog/1.13.0
nlohmann_json/3.11.3
[generators]
CMakeDeps
CMakeToolchain
[options]
sqlite3:shared=False
[layout]
cmake_layout
`
fs.writeFileSync(conanfilePath, conanfileContent)
log.success('Created conanfile.txt')
return true
}
export const installConanDeps = (cppDir: string, execFn: typeof execCommand): boolean => {
log.section('Installing Conan Dependencies')
const conanfilePath = path.join(cppDir, 'conanfile.txt')
if (!fs.existsSync(conanfilePath)) {
log.error('conanfile.txt not found')
return false
}
log.info('Running conan install...')
const buildType = process.env.CMAKE_BUILD_TYPE || 'Release'
const result = execFn(`conan install . --output-folder=build --build=missing -s build_type=${buildType}`, cppDir)
if (!result.success) {
log.error('Conan install failed')
return false
}
log.success('Conan dependencies installed')
return true
}
export const configureCMake = (cppDir: string, buildType: 'Debug' | 'Release', execFn: typeof execCommand): boolean => {
log.section('Configuring CMake with Ninja')
const buildDir = path.join(cppDir, 'build')
if (!fs.existsSync(buildDir)) {
fs.mkdirSync(buildDir, { recursive: true })
}
log.info(`Build type: ${buildType}`)
const toolchainPath = path.join(buildDir, 'conan_toolchain.cmake')
const cmakeArgs = [
'-G Ninja',
`-DCMAKE_BUILD_TYPE=${buildType}`,
'-DCMAKE_EXPORT_COMPILE_COMMANDS=ON',
]
if (fs.existsSync(toolchainPath)) {
cmakeArgs.push(`-DCMAKE_TOOLCHAIN_FILE=${toolchainPath}`)
log.info('Using Conan toolchain')
}
const result = execFn(`cmake -B build ${cmakeArgs.join(' ')} .`, cppDir)
if (!result.success) {
log.error('CMake configuration failed')
return false
}
log.success('CMake configured successfully')
return true
}
export const buildTarget = (cppDir: string, target = 'all', jobs = os.cpus().length, execFn: typeof execCommand): boolean => {
log.section('Building with Ninja')
log.info(`Building target: ${target}`)
log.info(`Using ${jobs} parallel jobs`)
const result = execFn(`cmake --build build --target ${target} -j ${jobs}`, cppDir)
if (!result.success) {
log.error('Build failed')
return false
}
log.success('Build completed successfully')
return true
}
export const runTests = (cppDir: string, execFn: typeof execCommand): boolean => {
log.section('Running Tests')
const result = execFn('ctest --test-dir build --output-on-failure', cppDir)
if (!result.success) {
log.error('Tests failed')
return false
}
log.success('All tests passed')
return true
}
export const cleanBuild = (buildDir: string): boolean => {
log.section('Cleaning Build Artifacts')
if (fs.existsSync(buildDir)) {
fs.rmSync(buildDir, { recursive: true, force: true })
log.success('Build directory removed')
} else {
log.info('Build directory does not exist')
}
return true
}