diff --git a/src/commands/run/build.rs b/src/commands/run/build.rs index 3198e5d..e403d85 100644 --- a/src/commands/run/build.rs +++ b/src/commands/run/build.rs @@ -1,81 +1,114 @@ use std::fs; - -use crate::utils::parser::{self, env::get_install_env}; -use crate::utils::shell::{run_install_script,run_install_script_hook}; use crate::commands::link::link; -use super::download::download; -use super::patch::patch; - +use crate::utils::parser::{self, env::get_install_env}; +use crate::utils::shell::{run_install_script, run_install_script_hook}; +use super::{download, patch}; pub fn build(repo: &String, pkgname: &String) { - let pkgpath = &crate::commands::get_aeropkg_base().join(repo).join(pkgname); - fs::create_dir_all(&pkgpath).ok(); - let src = &pkgpath.join("src"); - - let pkg_md_path = &crate::commands::get_aeropkg_var().join(format!("{}/{}.md", repo, pkgname)); - let builded_pkg_md_path = &crate::commands::get_aeropkg_base().join(repo).join(pkgname).join("build-script.md"); - - let build_script = match parser::get_build_script(pkg_md_path) { - Ok(script) => script, - Err(error) => { - panic!("Failed to parse build script: {}", error); - } - }; - if builded_pkg_md_path.exists() { - let builded_script = match parser::get_build_script(builded_pkg_md_path) { - Ok(script) => script, - Err(error) => { - panic!("Failed to parse build block from {}: {}", builded_pkg_md_path.to_string_lossy(), error); - } - }; - if build_script == builded_script { return } - } + let base = crate::commands::get_aeropkg_base(); + let var = crate::commands::get_aeropkg_var(); - if src.join(".aeropkg.applied-build").exists() { - let src_build = fs::read_to_string(src.join(".aeropkg.applied-build")).unwrap_or("".to_string()); - if build_script == src_build { - return - } else { - fs::remove_dir_all(src).unwrap(); - download(repo, pkgname); - patch(repo, pkgname) - } + let pkg_dir = base.join(repo).join(pkgname); + let src_dir = pkg_dir.join("src"); + fs::create_dir_all(&pkg_dir).ok(); + + let md_path = var.join(format!("{}/{}.md", repo, pkgname)); + let built_md_path = pkg_dir.join("build-script.md"); + + let build_script = parser::get_build_script(&md_path) + .unwrap_or_else(|e| panic!("Failed to parse build script: {}", e)); + let full_env = get_install_env(repo, pkgname, &md_path, "build"); + + if is_build_up_to_date(&built_md_path, &build_script, &full_env, repo, pkgname) { + return; } - let full_env = get_install_env(repo, pkgname, pkg_md_path, "build"); - run_install_script(&build_script, src, &full_env); + let applied_build = src_dir.join(".aeropkg.applied-build"); + let applied_env = src_dir.join(".aeropkg.install-env"); + + if is_source_up_to_date(&applied_build, &applied_env, &build_script, &full_env) { + return; + } else if applied_build.exists() { + fs::remove_dir_all(&src_dir).unwrap(); + download::download(repo, pkgname); + patch::patch(repo, pkgname); + } + + save_env(&applied_env, &full_env); + + run_install_script(&build_script, &src_dir, &full_env); run_install_script_hook(repo, "build", &full_env); - let dest_dir = crate::commands::get_aeropkg_base().join(repo).join(pkgname); - if let Err(e) = fs::create_dir_all(&dest_dir) { panic!("Failed to create destination directory: {}", e) } - let dest_path = &dest_dir.join("build-script.md"); - fs::remove_file(dest_path).ok(); - if let Err(e) = fs::hard_link(pkg_md_path, dest_path) { panic!("Failed to copy build script to destination: {}", e) } - fs::write(src.join(".aeropkg.applied-build"), &build_script).unwrap(); + fs::create_dir_all(&pkg_dir).ok(); + let _ = fs::remove_file(&built_md_path); + fs::hard_link(&md_path, &built_md_path) + .unwrap_or_else(|e| panic!("Failed to link build script: {}", e)); + fs::write(&applied_build, &build_script).unwrap(); - - let save_source_flag = full_env.get("save_source").is_some(); - if !save_source_flag { - if let Err(e) = fs::remove_dir_all(&src) { panic!("Failed to remove source directory: {}", e) } + // Очистка и пост-хуки + if full_env.get("save_source").is_none() { + fs::remove_dir_all(&src_dir).ok(); } - hook(repo, pkgname); + hook(&pkg_dir); - if !full_env.get("disable").is_some() { - let _ = fs::File::create(crate::commands::get_aeropkg_base().join(repo).join(pkgname).join("disabled")); + if full_env.get("disable").is_some() { + link(repo, pkgname); } else { - link(repo, pkgname) + let _ = fs::File::create(pkg_dir.join("disabled")); } } - -fn hook(repo: &String, pkgname: &String) { - let pkg_dir = crate::commands::get_aeropkg_base().join(repo).join(pkgname); - let lib_dir = &pkg_dir.join("lib"); - let lib64_dir = &pkg_dir.join("lib64"); - let lib32_dir = &pkg_dir.join("lib32"); - crate::utils::fs::mv::mv(&lib64_dir, &lib_dir).ok(); - crate::utils::fs::mv::mv(&lib32_dir, &lib_dir).ok(); - fs::remove_dir_all(&lib64_dir).ok(); - fs::remove_dir_all(&lib32_dir).ok(); +fn hook(pkg_dir: &std::path::Path) { + let lib = pkg_dir.join("lib"); + for d in ["lib64", "lib32"] { + let dir = pkg_dir.join(d); + crate::utils::fs::mv::mv(&dir, &lib).ok(); + fs::remove_dir_all(&dir).ok(); + } +} + +fn is_build_up_to_date( + md_path: &std::path::Path, + script: &str, + env: &std::collections::HashMap, + repo: &String, + pkgname: &String +) -> bool { + if !md_path.exists() { return false; } + + let old_script = match parser::get_build_script(md_path) { + Ok(s) => s, + Err(_) => return false, + }; + + script == old_script && + env == &get_install_env(repo, pkgname, md_path, "build") +} + +fn is_source_up_to_date( + build_path: &std::path::Path, + env_path: &std::path::Path, + script: &str, + env: &std::collections::HashMap +) -> bool { + if !build_path.exists() { return false; } + + let old_script = fs::read_to_string(build_path).unwrap_or_default(); + let old_env = load_env(env_path); + + script == old_script && env == &old_env +} + +fn save_env(path: &std::path::Path, env: &std::collections::HashMap) { + let mut lines: Vec<_> = env.iter().map(|(k, v)| format!("{}={}", k, v)).collect(); + lines.sort(); + fs::write(path, lines.join("\n")).ok(); +} + +fn load_env(path: &std::path::Path) -> std::collections::HashMap { + let content = fs::read_to_string(path).unwrap_or_default(); + content.lines() + .filter_map(|l| l.split_once('=').map(|(k, v)| (k.to_string(), v.to_string()))) + .collect() }