Files
damn_simple_architecture/dsx_server/src/common/builder/mod.rs
T
2026-02-23 09:04:30 +00:00

161 lines
4.4 KiB
Rust

use std::{
env, fs, io,
path::{Path, PathBuf},
process::Command,
};
use crate::common::config::DsxConfig;
use assembler::prelude::Assembler;
use common::build::{BuildError, Builder};
use compiler::Compiler;
// ---------- build ----------------------------------------------------------
pub fn build_project(cwd: &Path) -> Result<(), BuildError> {
let config: DsxConfig = toml::from_str(&fs::read_to_string(cwd.join("Dsx.toml"))?)
.map_err(|deser_err| {
io::Error::new(io::ErrorKind::InvalidData, deser_err.to_string())
})?;
let src_dir = cwd.join("src");
if !src_dir.exists() {
return Err(BuildError::Generic(String::from(
"Source Directory does not exist",
)));
}
// make sure there's a main file to assemble later.
if !main_exists(&src_dir)? {
return Err(BuildError::Generic(String::from(
"No main.dsa or main.dsc file found in top level of src directory.",
)));
}
// detect src.
let (has_dsa, has_dsc) = detect_source_language(&src_dir);
// create a build dir and copy all files across
let build_dir = cwd.join("build");
fs::create_dir_all(&build_dir)?;
env::set_current_dir(&build_dir)?;
copy_recursively(&src_dir, &build_dir)?;
if has_dsc {
build_all_dsc(&build_dir)?;
}
// Replace .dsc with .dsa only in include statements, recursively for each file.
let mut sed_cmd = Command::new("bash");
sed_cmd.args([
"-c",
&format!(
"find \"{}\" -type f -name '*.dsa' -exec sed -i '/^include/ s/\\.dsc/.dsa/g' {{}} +",
build_dir.display()
),
]);
run(&mut sed_cmd);
// assemble result
{
fs::create_dir_all(cwd.join("artifacts"))?;
let mut asm = Assembler::new("./main.dsa");
asm.start();
asm.write_result("../artifacts/out.dsb")?;
}
println!("Build finished. Binary at {}/main.dsb", build_dir.display());
Ok(())
}
// ----- Helpers -------------------------------
struct BuildStep;
impl BuildStep {
pub fn compiling(path: &Path) {
println!("Compiling {}", path.display());
}
pub fn assembling(path: &Path) {
println!("Assembling {}", path.display());
}
}
/// Checks what source languages are used in the project.
fn detect_source_language(src_dir: &Path) -> (bool, bool) {
let mut contains_dsc = false;
let mut contains_dsa = false;
for entry in walkdir::WalkDir::new(src_dir).into_iter().flatten() {
match entry.path().extension().and_then(|s| s.to_str()) {
Some("dsc") => contains_dsc = true,
Some("dsa") => contains_dsa = true,
_ => {}
}
}
(contains_dsa, contains_dsc)
}
// Checks if either main.dsa or main.dsc exist in the source directory
fn main_exists(src_dir: &Path) -> Result<bool, std::io::Error> {
for entry in fs::read_dir(src_dir).into_iter().flatten() {
match entry?.path().file_name().and_then(|s| s.to_str()) {
Some("main.dsc") => return Ok(true),
Some("main.dsa") => return Ok(true),
_ => {}
}
}
Ok(false)
}
// Copy contents of one directory to another
fn copy_recursively(src: &Path, dst: &Path) -> Result<(), std::io::Error> {
if src.is_file() {
fs::create_dir_all(dst.parent().unwrap())?;
fs::copy(src, dst)?;
return Ok(());
}
if src.is_dir() {
for entry in fs::read_dir(src)? {
let entry = entry?;
let child_src = entry.path();
let child_dst = dst.join(entry.file_name());
copy_recursively(&child_src, &child_dst)?;
}
}
Ok(())
}
fn build_all_dsc(path: &Path) -> Result<(), BuildError> {
if path.is_dir() {
for entry in fs::read_dir(path)? {
let entry = entry?;
build_all_dsc(&entry.path())?;
}
return Ok(());
}
if path.extension().and_then(|s| s.to_str()) == Some("dsc") {
let input_path = path;
let output_path = path.with_extension("dsa");
let mut compiler = Compiler::new(input_path);
compiler.start();
compiler.write_result(output_path.clone())?;
}
Ok(())
}
/// Run a command and exit on failure.
fn run(cmd: &mut Command) {
let status = cmd.status().expect("failed to execute command");
if !status.success() {
std::process::exit(1);
}
}