Skip to content

Commit

Permalink
readd asc
Browse files Browse the repository at this point in the history
  • Loading branch information
BrettMayson committed Jan 25, 2024
1 parent d292c35 commit b415bea
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 4 deletions.
Binary file added bin/dist/asc/linux/asc
Binary file not shown.
Binary file added bin/dist/asc/windows/asc.exe
Binary file not shown.
5 changes: 4 additions & 1 deletion bin/src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ use crate::{
context::{self, Context},
error::Error,
executor::Executor,
modules::{pbo::Collapse, Binarize, Files, Hooks, Rapifier, SQFCompiler},
modules::{
asc::ArmaScriptCompiler, pbo::Collapse, Binarize, Files, Hooks, Rapifier, SQFCompiler,
},
report::Report,
};

Expand Down Expand Up @@ -94,6 +96,7 @@ pub fn executor(ctx: Context, matches: &ArgMatches) -> Executor {
if matches.get_one::<bool>("no-bin") != Some(&true) {
executor.add_module(Box::<Binarize>::default());
}
executor.add_module(Box::<ArmaScriptCompiler>::default());
executor.add_module(Box::<Files>::default());

executor.init();
Expand Down
6 changes: 5 additions & 1 deletion bin/src/commands/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use crate::{
context::Context,
error::Error,
executor::Executor,
modules::{pbo::Collapse, Binarize, FilePatching, Files, Hooks, Rapifier, SQFCompiler},
modules::{
asc::ArmaScriptCompiler, pbo::Collapse, Binarize, FilePatching, Files, Hooks, Rapifier,
SQFCompiler,
},
report::Report,
};

Expand Down Expand Up @@ -118,6 +121,7 @@ pub fn context(matches: &ArgMatches, launch_optionals: &[String]) -> Result<Exec
executor.add_module(Box::<Hooks>::default());
executor.add_module(Box::<Rapifier>::default());
executor.add_module(Box::<SQFCompiler>::default());
executor.add_module(Box::<ArmaScriptCompiler>::default());
executor.add_module(Box::<Files>::default());
executor.add_module(Box::<FilePatching>::default());
if matches.get_one::<bool>("binarize") == Some(&true) {
Expand Down
4 changes: 4 additions & 0 deletions bin/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ pub enum Error {
#[error("`.hemtt/project.toml` not found")]
ConfigNotFound,

#[error("ASC: {0}")]
#[cfg(not(target_os = "macos"))]
ArmaScriptCompiler(String),

#[error("Unable to create link: {0}")]
#[allow(dead_code)] // Unused on Linux and Mac
Link(String),
Expand Down
231 changes: 231 additions & 0 deletions bin/src/modules/asc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
use std::{
fs::{create_dir_all, File},
io::{Read, Write},
process::Command,
sync::{
atomic::{AtomicU16, Ordering},
Arc, RwLock,
},
};

use hemtt_preprocessor::Processor;
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use rust_embed::RustEmbed;
use serde::Serialize;
use time::Instant;

use crate::{context::Context, error::Error, report::Report};

use super::Module;

#[cfg(windows)]
#[derive(RustEmbed)]
#[folder = "dist/asc/windows"]
struct Distributables;

#[cfg(not(windows))]
#[derive(RustEmbed)]
#[folder = "dist/asc/linux"]
struct Distributables;

#[derive(Default)]
pub struct ArmaScriptCompiler;

#[cfg(windows)]
const SOURCE: [&str; 1] = ["asc.exe"];

#[cfg(not(windows))]
const SOURCE: [&str; 1] = ["asc"];

impl Module for ArmaScriptCompiler {
fn name(&self) -> &'static str {
"ArmaScriptCompiler"
}

fn init(&mut self, ctx: &Context) -> Result<Report, Error> {
let asc = ctx.tmp().join("asc");
trace!("using asc folder at {:?}", asc.display());
create_dir_all(asc.join("output"))?;
Ok(Report::new())
}

#[allow(clippy::too_many_lines)]
fn pre_build(&self, ctx: &Context) -> Result<Report, Error> {
let mut out_file =
File::create(".hemttout/asc.log").expect("Unable to create `.hemttout/asc.log`");
let mut config = ASCConfig::new();
let tmp = ctx.tmp().join("asc");
for file in SOURCE {
let out = tmp.join(file);
trace!("unpacking {:?} to {:?}", file, out.display());
let mut f = File::create(&out)?;
f.write_all(&Distributables::get(file).unwrap().data)?;
#[cfg(target_os = "linux")]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(out, PermissionsExt::from_mode(0o744))?;
}
}
let sqf_ext = Some(String::from("sqf"));
let files = Arc::new(RwLock::new(Vec::new()));
let start = Instant::now();
let mut root_dirs = Vec::new();
for addon in ctx.addons() {
if !root_dirs.contains(&addon.prefix().main_prefix()) {
root_dirs.push(addon.prefix().main_prefix());
}
let tmp_addon = tmp.join(addon.prefix().as_pathbuf());
create_dir_all(&tmp_addon)?;
let mut entries = Vec::new();
for entry in ctx.workspace().join(addon.folder())?.walk_dir()? {
if entry.is_file()? {
if entry.extension() != sqf_ext {
continue;
}
entries.push(entry);
}
}
entries
.par_iter()
.map(|entry| {
let processed = Processor::run(entry)?;
let source = tmp_addon.join(
entry
.as_str()
.trim_start_matches(&format!("/{}/", addon.folder())),
);
let parent = source.parent().unwrap();
if !parent.exists() {
std::mem::drop(create_dir_all(parent));
}
let mut f = File::create(source)?;
f.write_all(processed.as_str().as_bytes())?;
files.write().unwrap().push((
format!(
"{}{}",
addon
.prefix()
.to_string()
.replace('\\', "/")
.trim_end_matches(&addon.folder().replacen(
"optionals/",
"addons/",
1
))
.trim_end_matches(&addon.folder()),
entry.as_str().to_string().trim_start_matches('/'),
),
entry
.as_str()
.to_string()
.trim_start_matches('/')
.to_string(),
));
Ok(())
})
.collect::<Result<_, Error>>()?;
}
debug!(
"ASC Preprocess took {:?}",
start.elapsed().whole_milliseconds()
);
for root in root_dirs {
config.add_input_dir(root.to_string());
}
config.set_output_dir(tmp.join("output").display().to_string());
let include = tmp.join("source").join("include");
if include.exists() {
config.add_include_dir(include.display().to_string());
}
config.set_worker_threads(num_cpus::get());
let mut f = File::create(tmp.join("sqfc.json"))?;
f.write_all(serde_json::to_string_pretty(&config)?.as_bytes())?;
std::env::set_current_dir(&tmp)?;
let start = Instant::now();
let command = Command::new(tmp.join(SOURCE[0])).output()?;
out_file.write_all(&command.stdout)?;
out_file.write_all(&command.stderr)?;
if String::from_utf8(command.stdout.clone())
.unwrap()
.contains("Parse Error")
{
warn!("ASC 'Parse Error' - check .hemttout/asc.log");
}
if command.status.success() {
debug!("ASC took {:?}", start.elapsed().whole_milliseconds());
} else {
return Err(Error::ArmaScriptCompiler(
String::from_utf8(command.stdout).unwrap(),
));
}
std::env::set_current_dir(ctx.project_folder())?;
let tmp_output = tmp.join("output");
let counter = AtomicU16::new(0);
for (src, dst) in &*files.read().unwrap() {
let from = tmp_output.join(&format!("{src}c"));
let to = ctx.workspace().join(&format!("{dst}c"))?;
if !from.exists() {
// sqf that have parse errors OR just empty//no-code
debug!("asc didn't process {}", src);
continue;
}
let mut f = File::open(from)?;
let mut data = Vec::new();
f.read_to_end(&mut data)?;
to.create_file()?.write_all(&data)?;
counter.fetch_add(1, Ordering::Relaxed);
}
info!("Compiled {} sqf files", counter.load(Ordering::Relaxed));
Ok(Report::new())
}
}

#[derive(Default, Serialize)]
pub struct ASCConfig {
#[serde(rename = "inputDirs")]
input_dirs: Vec<String>,
#[serde(rename = "outputDir")]
output_dir: String,
#[serde(rename = "includePaths")]
include_dirs: Vec<String>,
#[serde(rename = "excludeList")]
exclude_list: Vec<String>,
#[serde(rename = "workerThreads")]
worker_threads: usize,
}

impl ASCConfig {
#[must_use]
pub const fn new() -> Self {
Self {
input_dirs: vec![],
output_dir: String::new(),
include_dirs: vec![],
exclude_list: vec![],
worker_threads: 2,
}
}

pub fn add_input_dir(&mut self, dir: String) {
if self.input_dirs.contains(&dir) {
return;
}
self.input_dirs.push(dir);
}

pub fn set_output_dir(&mut self, dir: String) {
self.output_dir = dir;
}

pub fn add_include_dir(&mut self, dir: String) {
self.include_dirs.push(dir);
}

pub fn add_exclude(&mut self, dir: &str) {
self.exclude_list.push(dir.replace('/', "\\"));
}

pub fn set_worker_threads(&mut self, threads: usize) {
self.worker_threads = threads;
}
}
1 change: 1 addition & 0 deletions bin/src/modules/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::{context::Context, error::Error, report::Report};

pub mod archive;
pub mod asc;
pub mod hook;
pub mod pbo;

Expand Down
4 changes: 2 additions & 2 deletions bin/src/modules/sqf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ impl Module for SQFCompiler {
}
match hemtt_sqf::parser::run(&database, &processed) {
Ok(sqf) => {
let mut out = entry.with_extension("sqfc")?.create_file()?;
// let mut out = entry.with_extension("sqfc")?.create_file()?;
let (warnings, errors) =
analyze(&sqf, Some(ctx.config()), &processed, Some(addon), &database);
for warning in warnings {
report.warn(warning);
}
if errors.is_empty() {
sqf.compile_to_writer(&processed, &mut out)?;
// sqf.compile_to_writer(&processed, &mut out)?;
counter.fetch_add(1, Ordering::Relaxed);
}
for error in errors {
Expand Down

0 comments on commit b415bea

Please sign in to comment.