- created dsx and dsx_server in place of dsx-build
- dsx replaces dsx-build and is a build tool/package manager for the DSA ecosystem - dsx_server is the repository/server for dsx packages. dsx is a WIP.
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
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.",
|
||||
)));
|
||||
}
|
||||
|
||||
// check is redundant as we're already checking for main files.
|
||||
// if !has_dsc && !has_dsa {
|
||||
// return Err(io::Error::new(
|
||||
// io::ErrorKind::NotFound,
|
||||
// "No .dsc or .dsa source found in 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user