fix(builder): preserve module tree structure, sanitize cmake include paths, and suppress console windows

This commit is contained in:
Дмитрий committed 2026-11-03 17:00:18 +05:00
1 parent c2bf8ecbb6
commit 4ebf86d222
2 files changed
+77 -25

No files matched your search

+17 -1
View File
@@ -413,7 +413,13 @@ pub fn analyze_repository_with_contract(repo_path: &Path, contract: &SdkExportCo
// Check git commit if available
let commit = if repo_path.join(".git").exists() {
std::process::Command::new("git")
let mut git_cmd = std::process::Command::new("git");
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
git_cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
}
git_cmd
.args(["-C", &repo_path.to_string_lossy(), "rev-parse", "HEAD"])
.output()
.ok()
@@ -959,6 +965,11 @@ pub fn analyze_github_repository(url_str: &str, cache_base_dir: Option<&Path>) -
// 1. Resolve commit SHA via git ls-remote (isolated env, no hooks)
let repo_remote_url = format!("https://github.com/{}/{}.git", owner, repo);
let mut ls_cmd = std::process::Command::new("git");
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
ls_cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
}
ls_cmd.env("GIT_CONFIG_NOSYSTEM", "1")
.env("GIT_CONFIG_GLOBAL", "")
.env("GIT_TERMINAL_PROMPT", "0")
@@ -1013,6 +1024,11 @@ pub fn analyze_github_repository(url_str: &str, cache_base_dir: Option<&Path>) -
fs::create_dir_all(&staging_dir)?;
let mut clone_cmd = std::process::Command::new("git");
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
clone_cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
}
clone_cmd.env("GIT_CONFIG_NOSYSTEM", "1")
.env("GIT_CONFIG_GLOBAL", "")
.env("GIT_TERMINAL_PROMPT", "0")
+60 -24
View File
@@ -483,22 +483,26 @@ pub fn build_module_from_source(
)));
}
// Helper to strip verbatim extended path prefix (\\?\) so CMake and MSVC can parse include dirs
let clean_path = |p: &Path| -> String {
let s = p.to_string_lossy();
let stripped = s.strip_prefix(r"\\?\").unwrap_or(&s);
stripped.replace('\\', "/")
};
let mut staged_cpp_paths = Vec::new();
staged_cpp_paths.push(adapter_path.to_string_lossy().replace('\\', "/"));
staged_cpp_paths.push(clean_path(&adapter_path));
for cpp in &upstream_cpps {
let file_name = cpp.file_name().unwrap();
// Avoid naming collision with adapter.cpp
let dest_file_name = if file_name == "adapter.cpp" {
format!("upstream_{}", file_name.to_string_lossy())
} else {
file_name.to_string_lossy().into_owned()
};
let dest = staging_src.join(&dest_file_name);
let rel = cpp.strip_prefix(module_source_dir).unwrap_or_else(|_| Path::new(cpp.file_name().unwrap()));
let dest = staging_src.join(rel);
if let Some(parent) = dest.parent() {
fs::create_dir_all(parent)?;
}
fs::copy(cpp, &dest)?;
// Resilient compatibility patching for older / cached mod-coa-playerbots
if dest_file_name == "BotMgr.cpp" {
if dest.file_name().map(|n| n == "BotMgr.cpp").unwrap_or(false) {
if let Ok(content) = fs::read_to_string(&dest) {
if content.contains("_GetPurchasedTabsSize") || content.contains("_CreateNewBankTab") {
let patched = content
@@ -513,20 +517,46 @@ pub fn build_module_from_source(
}
}
staged_cpp_paths.push(dest.to_string_lossy().replace('\\', "/"));
staged_cpp_paths.push(clean_path(&dest));
}
// Collect include directories from upstream
let mut include_dirs = Vec::new();
include_dirs.push(staging_src.to_string_lossy().replace('\\', "/"));
include_dirs.push(module_source_dir.to_string_lossy().replace('\\', "/"));
// Also copy all headers (.h and .hpp) preserving directory structure
let upstream_headers = collect_files_with_ext(module_source_dir, "h");
for h in upstream_headers {
for h in &upstream_headers {
let rel = h.strip_prefix(module_source_dir).unwrap_or_else(|_| Path::new(h.file_name().unwrap()));
let dest = staging_src.join(rel);
if let Some(parent) = dest.parent() {
let _ = fs::create_dir_all(parent);
}
let _ = fs::copy(h, &dest);
}
let upstream_hpps = collect_files_with_ext(module_source_dir, "hpp");
for h in &upstream_hpps {
let rel = h.strip_prefix(module_source_dir).unwrap_or_else(|_| Path::new(h.file_name().unwrap()));
let dest = staging_src.join(rel);
if let Some(parent) = dest.parent() {
let _ = fs::create_dir_all(parent);
}
let _ = fs::copy(h, &dest);
}
// Collect include directories from upstream and staging
let mut include_dirs = Vec::new();
include_dirs.push(clean_path(&staging_src));
include_dirs.push(clean_path(module_source_dir));
for h in upstream_headers.iter().chain(upstream_hpps.iter()) {
if let Some(parent) = h.parent() {
let p_str = parent.to_string_lossy().replace('\\', "/");
if !include_dirs.contains(&p_str) {
include_dirs.push(p_str);
let p_clean = clean_path(parent);
if !include_dirs.contains(&p_clean) {
include_dirs.push(p_clean);
}
if let Ok(rel) = parent.strip_prefix(module_source_dir) {
let staged_parent = staging_src.join(rel);
let sp_clean = clean_path(&staged_parent);
if !include_dirs.contains(&sp_clean) {
include_dirs.push(sp_clean);
}
}
}
}
@@ -534,7 +564,7 @@ pub fn build_module_from_source(
// 3. Write controlled CMakeLists.txt (eliminating D9025 /Zi vs /Z7 conflict)
let sources_block = staged_cpp_paths.iter().map(|s| format!(" \"{}\"", s)).collect::<Vec<_>>().join("\n");
let includes_block = include_dirs.iter().map(|s| format!(" \"{}\"", s)).collect::<Vec<_>>().join("\n");
let cmake_sdk_path = sdk_dir.replace('\\', "/");
let cmake_sdk_path = clean_path(Path::new(&sdk_dir));
let controlled_cmake = format!(r#"cmake_minimum_required(VERSION 3.22)
project(coa_plugin_{safe_target_name} LANGUAGES CXX)
@@ -576,14 +606,20 @@ set "PATH={ninja_dir};%PATH%"
if errorlevel 1 exit /b 102
"{cmake}" --build "{build_dir}" -- -j8
if errorlevel 1 exit /b 103
"#, vcvars64 = vcvars64, ninja_dir = ninja_dir, cmake = cmake, staging_dir = staging_dir.display(), build_dir = build_output_dir.display(), sdk_dir = sdk_dir);
"#, vcvars64 = vcvars64, ninja_dir = ninja_dir, cmake = cmake, staging_dir = clean_path(&staging_dir), build_dir = clean_path(&build_output_dir), sdk_dir = clean_path(Path::new(&sdk_dir)));
fs::write(&runner_bat, &runner_content)?;
emit_progress("COMPILING", 45, "Compiling C++ sources via MSVC Cl.exe...", None);
// 5. Execute build command
let output = Command::new("cmd.exe")
// 5. Execute build command silently without console popup
let mut cmd = Command::new("cmd.exe");
#[cfg(windows)]
{
use std::os::windows::process::CommandExt;
cmd.creation_flags(0x08000000); // CREATE_NO_WINDOW
}
let output = cmd
.args(["/c", &runner_bat.to_string_lossy()])
.output();