From d10ac4cc08d679e7971296b79c6eafadcdbc78de Mon Sep 17 00:00:00 2001 From: Namilskyy Date: Sat, 29 Nov 2025 20:26:35 +0300 Subject: Big refactors and additions, implemented http package getter and refactored i2p fn --- src/pkgtoolkit/pkgtools.rs | 205 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 169 insertions(+), 36 deletions(-) (limited to 'src/pkgtoolkit/pkgtools.rs') diff --git a/src/pkgtoolkit/pkgtools.rs b/src/pkgtoolkit/pkgtools.rs index 5acbd11..cfd3d59 100644 --- a/src/pkgtoolkit/pkgtools.rs +++ b/src/pkgtoolkit/pkgtools.rs @@ -6,8 +6,10 @@ use std::{ io, path::Path, process::Command, - str}; + str, + os::unix::fs::PermissionsExt}; + use emissary_core::i2np::tunnel::build; // use emissary_core::i2np::tunnel::build; use flate2::read::GzDecoder; use serde::{Deserialize, Serialize}; @@ -81,44 +83,74 @@ impl archs { #[allow(dead_code)] impl Package { - fn builder_backend(&mut self) -> Result { - let config: Config = Config::parse().unwrap(); - let metadata = Self::loadmeta(self).unwrap(); - let path = Path::new(&config.paths.cache_dir).join(format!("{}-{}/BUILD", metadata.0.package.name, metadata.0.package.version)); - let _ = create_dir_all(&path); - - if metadata.2.is_none() { - Err(std::io::Error::new(std::io::ErrorKind::NotFound, "BUILD file not found"))? - } - - match metadata.2.unwrap().build_system { + /// Execute the build script for the package. + /// + /// This function takes the `Build` meta information as an argument and + /// executes the build script accordingly. It also handles the different + /// build systems supported (Make, CMake, Meson, Cargo). + /// + /// # Errors + /// + /// Returns an error if the build command fails. + fn execute_build(&self, build_meta: &Build) -> Result<(), std::io::Error> { + let config = Config::parse() + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; + let build_dir = Path::new(&config.paths.cache_dir) + .join(format!("{}-{}", self.name, self.version)); + + let mut cmd = match build_meta.build_system { BuildSystems::Make => { - let _setup = Command::new("make") - .arg("all") - .arg("all") - .output(); + let mut c = Command::new("make"); + c.current_dir(&build_dir); + if build_meta.script.is_some() { + c.arg("-f").arg(build_meta.script.as_ref().unwrap()); + } + c.arg("all"); + c } - BuildSystems::CMake => { - let _setup = Command::new("cmake") - .arg("-S") - .arg(&path) - .arg("-B") - .arg(&path) - .output(); - - let _make = Command::new("make") - .arg("-C") - .arg(&path) - .output(); + let build_dir_build = build_dir.join("build"); + create_dir_all(&build_dir_build)?; + let mut c = Command::new("cmake"); + c.arg("-S").arg(&build_dir) + .arg("-B").arg(&build_dir_build) + .current_dir(&build_dir); + c } - - _ => { - Err(std::io::Error::new(std::io::ErrorKind::NotFound, "BUILD file not found"))? + BuildSystems::Meson => { + let build_dir_build = build_dir.join("build"); + create_dir_all(&build_dir_build)?; + let mut c = Command::new("meson"); + c.arg("setup") + .arg(&build_dir_build) + .current_dir(&build_dir); + c + } + BuildSystems::Cargo => { + let mut c = Command::new("cargo"); + c.arg("build") + .arg("--release") + .current_dir(&build_dir); + c } + }; + + let output = cmd.output().map_err(|e| { + std::io::Error::new( + std::io::ErrorKind::Other, + format!("Build command failed: {}", e), + ) + })?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!("Build failed:\n{}", stderr), + )); } - Ok(true) + Ok(()) } /// Extracts a .tar.gz archive to the cache directory specified in Config. @@ -366,15 +398,116 @@ impl Package { } Strategies::SOURCE => { log::info!("Strategy: SOURCE; Running default build hook."); - todo!(); + let _ = self.execute_build(&build_meta.unwrap()); } } Ok(true) } - pub fn install() -> Result { - todo!(); - } + + + /// Installs the package according to the INSTALL file in the archive. + /// + /// There are two strategies for installing the package. If the BUILD file is empty, the package is assumed to be a binary package and the default install hook is skipped. If the BUILD file is not empty, the package is assumed to be a source package and the default build hook is skipped. + /// + /// If the BUILD file is empty and the INSTALL file contains a custom script, the custom script is run instead of the default install hook. + /// If the BUILD file is not empty and the INSTALL file contains a custom script, the custom script is ignored. + /// + /// # Errors + /// + /// Returns an error if the BUILD file is invalid or if the build or install hook fails. + pub fn install(&mut self) -> Result { + let config = Config::parse() + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; + let (install_meta, _setts_meta, build_meta) = Self::loadmeta(self) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?; + + + let is_build_present_and_not_empty = build_meta.is_some(); + + if is_build_present_and_not_empty { + log::info!("Found BUILD file, preparing to build and install package: {}", self.name); + let build_meta_ref = build_meta.as_ref().unwrap(); + self.execute_build(build_meta_ref); + + + if matches!(build_meta_ref.build_system, BuildSystems::Make) { + log::info!("Running 'make install' for package: {}", self.name); + let build_dir = Path::new(&config.paths.cache_dir) + .join(format!("{}-{}", self.name, self.version)); + let output = Command::new("make") + .arg("install") + .current_dir(&build_dir) + .output() + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("'make install' failed: {}", e)))?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + format!("'make install' failed:\n{}", stderr), + )); + } + } + } else { + log::info!("No BUILD file or it's empty. Treating as binary package. Installing via INSTALL config or custom script."); + // Установка бинарного пакета + if let Some(ref script) = install_meta.custom_script { + log::info!("Executing custom install script for {}", install_meta.package.name); + let status = if script.starts_with("./") || script.contains('/') { + Command::new("/bin/sh").arg("-c").arg(script).status() + } else { + Command::new(script).status() + } + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to run custom script: {}", e)))?; + + if !status.success() { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Custom install script failed", + )); + } + } else { + log::info!("No custom script. Running default install hook for {}", install_meta.package.name); + // --- Дефолтный хук установки --- + // 1. Копируем файл из build_dir (предположим, что бинарный файл лежит в корне распакованного архива) + let source_file_name = &self.name; // Предполагаем имя файла = имя пакета + let build_dir = Path::new(&config.paths.cache_dir) + .join(format!("{}-{}", self.name, self.version)); + let src_path = build_dir.join(source_file_name); + let dest_path = Path::new(&install_meta.path); + + // Убедимся, что целевая директория существует + if let Some(parent) = dest_path.parent() { + create_dir_all(parent) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to create parent dir: {}", e)))?; + } + + fs::copy(&src_path, dest_path) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to copy file: {}", e)))?; + + let mode = u32::from_str_radix(&install_meta.mode, 8) + .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid mode string in INSTALL"))?; + let perms = PermissionsExt::from_mode(mode); + fs::set_permissions(dest_path, perms) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to set permissions: {}", e)))?; + + let output = Command::new("chown") + .arg(&format!("{}:{}", install_meta.user, install_meta.group)) + .arg(dest_path) + .output() + .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("'chown' command failed: {}", e)))?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + log::warn!("Warning: 'chown' command failed (requires root?):\n{}", stderr); + } + } + } + + log::info!("Package {} installed successfully.", self.name); + Ok(true) + } pub fn gen_index() -> Result { todo!(); -- cgit v1.2.3