diff options
| author | Namilskyy <alive6863@gmail.com> | 2025-12-03 21:00:31 +0300 |
|---|---|---|
| committer | Namilskyy <alive6863@gmail.com> | 2025-12-03 21:00:31 +0300 |
| commit | 2c8b804cd61a480501069cdf4d4377f3c2cf30bb (patch) | |
| tree | 2eecc7396b2445d881c316848f158830aa6a8d7d /src/pkgtoolkit | |
| parent | 2c7b2b72edf32ec19ac9b72b47c075209717deb4 (diff) | |
Not much of the documentation has been implemented, as well as some minor changes
Diffstat (limited to 'src/pkgtoolkit')
| -rw-r--r-- | src/pkgtoolkit/pkgtools.rs | 176 |
1 files changed, 115 insertions, 61 deletions
diff --git a/src/pkgtoolkit/pkgtools.rs b/src/pkgtoolkit/pkgtools.rs index a0433ac..2a8a18e 100644 --- a/src/pkgtoolkit/pkgtools.rs +++ b/src/pkgtoolkit/pkgtools.rs @@ -1,17 +1,13 @@ -// I think I should split this file into a few smaller ones. - use crate::cfg::config::Config; use std::{ - fs::{self, File, create_dir_all}, + fs::{self, File, Permissions, create_dir_all, set_permissions}, io, os::unix::fs::PermissionsExt, - path::Path, + path::{Path, StripPrefixError}, process::Command, str, }; - // use emissary_core::i2np::tunnel::build; - use flate2::read::GzDecoder; use serde::{Deserialize, Serialize}; use tar::Archive; @@ -38,12 +34,13 @@ pub struct Package { #[derive(Deserialize, Debug, Clone)] pub struct InstallMeta { - path: String, - user: String, - group: String, - mode: String, + pub path: String, + pub user: String, + pub group: String, + pub mode: String, // Cancels the previous fields and installs them using the shell script - custom_script: Option<String>, + pub custom_script: Option<String>, + // pub files: Option<Vec<String>>, } #[allow(dead_code)] @@ -51,6 +48,8 @@ pub struct InstallMeta { struct Install { package: Package, install: InstallMeta, + #[serde(default)] + files: Vec<String>, } #[allow(dead_code)] @@ -70,6 +69,13 @@ pub enum BuildSystems { Cargo, } +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct PackageManifest { + pub name: String, + pub version: String, + pub all_files: Vec<String>, +} + #[allow(dead_code)] #[derive(Deserialize)] struct Build { @@ -153,6 +159,36 @@ impl Package { Ok(()) } + /// Recursively collects all files from a directory and its subdirectories + /// and returns them as a vector of strings. + /// + /// # Arguments + /// + /// * `root`: The root directory from which to collect files. + /// * `base`: The base directory from which to strip the prefix from the file paths. + /// + /// # Returns + /// + /// A vector of strings containing the file paths relative to the `base` directory. + fn collect_files_from_dir(root: &Path, base: &Path) -> Result<Vec<String>, std::io::Error> { + let mut files = Vec::new(); + for entry in fs::read_dir(root)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + files.extend(Self::collect_files_from_dir(&path, base)?); + } else { + let rel_path = path + .strip_prefix(base) + .map_err(|e: StripPrefixError| io::Error::new(io::ErrorKind::InvalidData, e))? + .to_string_lossy() + .to_string(); + files.push(rel_path); + } + } + Ok(files) + } + /// Extracts a .tar.gz archive to the cache directory specified in Config. /// /// This function handles opening the archive file, decompressing it with GzDecoder, @@ -165,22 +201,19 @@ impl Package { /// * `Ok(())` if the archive is successfully unpacked. /// * `Err(std::io::Error)` if there's an issue opening, reading, or unpacking the archive. pub fn extract_archive(path_to_archive: &str) -> Result<(), std::io::Error> { - let config = Config::parse().unwrap(); + let config = Config::parse().map_err(|e| std::io::Error::other(e.to_string()))?; let cache_dir = &config.paths.cache_dir; create_dir_all(cache_dir)?; - // Очистим возможные мета-файлы предыдущих распаковок, чтобы не было утечек состояния for meta_name in ["INSTALL", "SETTS", "BUILD"] { let meta_path = Path::new(cache_dir).join(meta_name); if meta_path.exists() { - let _ = fs::remove_file(&meta_path); + fs::remove_file(&meta_path)?; } } - let file = File::open(path_to_archive)?; let gz = GzDecoder::new(file); let mut archive = Archive::new(gz); - // Unpack directly into the cache directory. Игнорируем AlreadyExists, чтобы не мешать валидации. match archive.unpack(cache_dir) { Ok(()) => Ok(()), @@ -206,7 +239,7 @@ impl Package { #[allow(clippy::type_complexity)] fn loadmeta( minimal_package_meta: &mut Self, - ) -> Result<(Install, Option<Setts>, Option<Build>), Box<dyn std::error::Error>> { + ) -> Result<(Install, Option<Setts>, Option<Build>), std::io::Error> { // Changed return type for more flexibility /* Example INSTALL format: @@ -234,7 +267,7 @@ impl Package { # """ */ - let config = Config::parse()?; // Propagate error if parsing fails + let config = Config::parse().map_err(|e| std::io::Error::other(e.to_string()))?; // Propagate error if parsing fails // Ensure the cache directory exists fs::create_dir_all(&config.paths.cache_dir)?; @@ -245,43 +278,41 @@ impl Package { let setts_path = Path::new(cache_dir).join(format!("{}/SETTS", minimal_package_meta.name)); let build_path = Path::new(cache_dir).join(format!("{}/BUILD", minimal_package_meta.name)); - // Check for required 'INSTALL' file if !install_path.exists() { return Err(io::Error::new( io::ErrorKind::NotFound, "File INSTALL not found in cache directory", - ) - .into()); // Convert to Box<dyn Error> + )); } - // Read and deserialize the INSTALL file let install_content = fs::read_to_string(&install_path)?; - let install_meta: Install = toml::from_str(&install_content)?; + let install_meta: Install = toml::from_str(&install_content) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; - // Initialize optional structures as None let mut setts_meta: Option<Setts> = None; let mut build_meta: Option<Build> = None; - // Attempt to read and deserialize the SETTS file if it exists if setts_path.exists() { let setts_content = fs::read_to_string(&setts_path)?; - setts_meta = Some(toml::from_str(&setts_content)?); + setts_meta = Some( + toml::from_str(&setts_content) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?, + ); } - // Attempt to read and deserialize the BUILD file if it exists if build_path.exists() { let build_content = fs::read_to_string(&build_path)?; - build_meta = Some(toml::from_str(&build_content)?); + build_meta = Some( + toml::from_str(&build_content) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?, + ); } - // Log if custom script is present if let Some(ref _script) = install_meta.install.custom_script { println!( "Custom script found for package: {}", install_meta.package.name ); - // Consider logging the script content or just its presence based on verbosity - // e.g., log::debug!("Custom script content: {}", script); } else { println!( "No custom script for package: {}", @@ -305,12 +336,11 @@ impl Package { pub fn check(path_to_archive: String) -> Result<bool, std::io::Error> { Self::extract_archive(&path_to_archive)?; - let archive_path = Path::new(&path_to_archive); - let archive_dir = archive_path.parent().unwrap_or_else(|| Path::new(".")); + let config = Config::parse().map_err(|e| std::io::Error::other(e.to_string()))?; - let install_path = archive_dir.join("INSTALL"); - let setts_path = archive_dir.join("SETTS"); - let build_path = archive_dir.join("BUILD"); + let install_path = Path::new(&config.paths.cache_dir).join("INSTALL"); + let setts_path = Path::new(&config.paths.cache_dir).join("SETTS"); + let build_path = Path::new(&config.paths.cache_dir).join("BUILD"); if !install_path.exists() { return Err(std::io::Error::new( @@ -352,7 +382,6 @@ impl Package { let install_content: Result<Install, toml::de::Error> = toml::from_str(&content); log::info!("Validating arch..."); - let install_parsed = match install_content { Ok(v) => v, Err(e) => { @@ -363,7 +392,6 @@ impl Package { )); } }; - if std::env::consts::ARCH != install_parsed.package.arch.as_str() { let pkg_arch = &install_parsed.package.arch; log::error!( @@ -392,7 +420,7 @@ impl Package { /// /// Returns an error if the BUILD file is invalid or if the build or install hook fails. pub fn build(&mut self) -> Result<bool, std::io::Error> { - let meta = Self::loadmeta(self).unwrap(); + let meta = Self::loadmeta(self)?; let install_meta = meta.0; // let setts_meta = meta.1; let build_meta = meta.2; @@ -449,8 +477,12 @@ impl Package { /// Returns an error if the BUILD file is invalid or if the build or install hook fails. pub fn install(&mut self) -> Result<bool, std::io::Error> { let config = Config::parse().map_err(|e| std::io::Error::other(e.to_string()))?; - let (install_meta, _setts_meta, build_meta) = - Self::loadmeta(self).map_err(|e| std::io::Error::other(e.to_string()))?; + let (install_meta, _setts_meta, build_meta) = Self::loadmeta(self)?; + + let installed_db = Path::new(&config.paths.installed_db); + create_dir_all(installed_db)?; + + let mut all_files: Vec<String> = Vec::new(); let is_build_present_and_not_empty = build_meta.is_some(); @@ -462,29 +494,29 @@ impl Package { let build_meta_ref = build_meta.as_ref().unwrap(); let _ = 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::other(format!("'make install' failed: {}", e)))?; - - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); - return Err(std::io::Error::other(format!( - "'make install' failed:\n{}", - stderr - ))); + let staging_dir = Path::new(&config.paths.cache_dir).join("staging"); + create_dir_all(&staging_dir)?; + all_files = Self::collect_files_from_dir(&staging_dir, &staging_dir)? + .iter() + .map(|rel| format!("/{}", rel)) // Преобразуйте в абсолютные пути (предполагаем root=/) + .collect(); + + for file in &all_files { + let src = staging_dir.join(file.trim_start_matches('/')); + let dest = Path::new(file); + if let Some(parent) = dest.parent() { + create_dir_all(parent)?; } + fs::copy(&src, dest)?; + // TODO: Permission } + + // Cleanup staging + fs::remove_dir_all(&staging_dir)?; } 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.install.custom_script { log::info!( "Executing custom install script for {}", @@ -502,6 +534,11 @@ impl Package { if !status.success() { return Err(std::io::Error::other("Custom install script failed")); } + + log::warn!( + "Custom script used; file list may be incomplete. Add manual tracking if needed." + ); + // Опционально: all_files = vec![]; или сканируйте систему (не рекомендуется) } else { log::info!( "No custom script. Running default install hook for {}", @@ -528,8 +565,8 @@ impl Package { "Invalid mode string in INSTALL", ) })?; - let perms = PermissionsExt::from_mode(mode); - fs::set_permissions(dest_path, perms).map_err(|e| { + let perms = Permissions::from_mode(mode); + set_permissions(dest_path, perms).map_err(|e| { std::io::Error::other(format!("Failed to set permissions: {}", e)) })?; @@ -549,12 +586,29 @@ impl Package { stderr ); } + + all_files = install_meta.files; } } - log::info!("Package {} installed successfully.", self.name); + let manifest = PackageManifest { + name: self.name.clone(), + version: self.version.clone(), + all_files, + }; + let manifest_path = installed_db.join(format!("{}-{}.toml", self.name, self.version)); + let manifest_toml = + toml::to_string(&manifest).map_err(|e| std::io::Error::other(e.to_string()))?; + fs::write(&manifest_path, manifest_toml)?; + + log::info!( + "Package {} installed successfully. Manifest generated at {:?}", + self.name, + manifest_path + ); Ok(true) } + pub fn gen_index() -> Result<bool, std::io::Error> { todo!(); } |
