From 778a979e2e774e1b2e91227fa2db2e56d41927c1 Mon Sep 17 00:00:00 2001 From: Namilskyy Date: Sun, 7 Dec 2025 14:29:35 +0300 Subject: Fixed logical issues --- src/main.rs | 90 +++++++++++++++++++--------- src/net/http_package.rs | 5 +- src/net/i2p_package.rs | 12 ++-- src/pkgtoolkit/archive.rs | 136 +++++++++++++++++++++++++++++++++++-------- src/pkgtoolkit/build.rs | 11 +--- src/pkgtoolkit/git_source.rs | 47 +++++++++------ 6 files changed, 209 insertions(+), 92 deletions(-) (limited to 'src') diff --git a/src/main.rs b/src/main.rs index 2bdb29c..068a8fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,10 +6,10 @@ use crate::cfg::config::Config; use crate::net::{http_package::HTTPPackage, i2p_package::I2PPackage}; use crate::pkgtoolkit::Package; -use crate::pkgtoolkit::index::IndexOperations; -use crate::pkgtoolkit::git_source::GitSource; use crate::pkgtoolkit::archive::ArchiveOperations; use crate::pkgtoolkit::build::BuildOperations; +use crate::pkgtoolkit::git_source::GitSource; +use crate::pkgtoolkit::index::IndexOperations; use clap::{Args, Parser, Subcommand}; use std::io::Write; @@ -72,7 +72,6 @@ struct RemoteInstallArgs { clean: bool, } - #[tokio::main] async fn main() -> Result<(), Box> { let cli: Cli = Cli::parse(); @@ -91,7 +90,7 @@ async fn main() -> Result<(), Box> { } Err(e) => { log::error!("Failed to validate package '{}': {}", path, e); - return Err(e.into()); + return Err(e.into()); } } return Ok(()); @@ -101,24 +100,52 @@ async fn main() -> Result<(), Box> { let path = Path::new(&pkgname); if !path.exists() { - return Err(std::io::Error::other(format!("Package archive not found: {}", pkgname)).into()); + return Err(std::io::Error::other(format!( + "Package archive not found: {}", + pkgname + )) + .into()); } if !path.is_file() { - return Err(std::io::Error::other(format!("Path is not a file: {}", pkgname)).into()); + return Err( + std::io::Error::other(format!("Path is not a file: {}", pkgname)).into(), + ); } println!("Extracting archive..."); Package::extract_archive(&pkgname)?; - let config = Config::parse().unwrap(); + let config = Config::parse().unwrap(); let cache_dir = &config.paths.cache_dir; - let install_toml_path = Path::new(cache_dir).join("INSTALL"); - + + // Find the package directory (should be name-version format) + let mut pkg_dir_name = None; + for entry in std::fs::read_dir(cache_dir)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + let dir_name = path.file_name().unwrap().to_string_lossy(); + if dir_name.contains('-') && dir_name != "temp_extract" { + let install_path = path.join("INSTALL"); + if install_path.exists() { + pkg_dir_name = Some(dir_name.to_string()); + break; + } + } + } + } + + let pkg_dir_name = pkg_dir_name.ok_or_else(|| { + std::io::Error::other("Package directory not found in cache") + })?; + + let install_toml_path = Path::new(cache_dir).join(format!("{}/INSTALL", pkg_dir_name)); + if !install_toml_path.exists() { - return Err(std::io::Error::other("INSTALL file not found in archive").into()); + return Err(std::io::Error::other("INSTALL file not found in package directory").into()); } - + let install_content = std::fs::read_to_string(&install_toml_path)?; let install_data: crate::pkgtoolkit::types::Install = toml::from_str(&install_content)?; @@ -129,21 +156,25 @@ async fn main() -> Result<(), Box> { println!("Package '{}' built successfully.", pkg.name); return Ok(()); } - Commands::Install { pkgname, source: _, args } => { - let config = Config::parse().unwrap(); + Commands::Install { + pkgname, + source: _, + args, + } => { + let config = Config::parse().unwrap(); if args.http { println!("Installing {} via HTTP", pkgname); let mut http_client = HTTPPackage::new(config); - http_client.fetch_index_http().await?; + http_client.fetch_index_http().await?; log::info!("Index fetched successfully."); http_client.fetch_package_http(pkgname).await?; log::info!("Package '{}' installed successfully.", pkgname); } else { println!("Installing {} via I2P", pkgname); let mut i2p_client = I2PPackage::new(config); - i2p_client.fetch_index().await?; + i2p_client.fetch_index().await?; log::info!("Index fetched successfully."); - i2p_client.fetch_package(pkgname).await?; + i2p_client.fetch_package(pkgname).await?; log::info!("Package '{}' installed successfully.", pkgname); } return Ok(()); @@ -153,15 +184,19 @@ async fn main() -> Result<(), Box> { return Ok(()); } Commands::GetSource { pkgname } => { - let config = Config::parse().unwrap(); + let config = Config::parse().unwrap(); println!("Getting source of {}", pkgname); - let source_path = GitSource::get_source_by_name(pkgname, &config)?; println!("Source code successfully downloaded to: {}", source_path); return Ok(()); } - Commands::DefaultConfig { repo, cachedir, buildir, installed_db } => { + Commands::DefaultConfig { + repo, + cachedir, + buildir, + installed_db, + } => { println!("Generating config file"); if cachedir.is_none() && repo.is_none() && buildir.is_none() { let config = Config::default().unwrap(); @@ -173,12 +208,12 @@ async fn main() -> Result<(), Box> { log::warn!("Writing the default config to /etc/mesk/mesk.toml"); let path = Path::new("/etc/mesk/mesk.toml"); - std::fs::create_dir_all(path.parent().unwrap())?; - let mut file = std::fs::File::create(path)?; + std::fs::create_dir_all(path.parent().unwrap())?; + let mut file = std::fs::File::create(path)?; file.write_all(config.as_bytes())?; println!("Config tool ending work."); } else { - let config = Config::generate(repo, cachedir, buildir, installed_db).unwrap(); + let config = Config::generate(repo, cachedir, buildir, installed_db).unwrap(); println!("---- Start of generated config ----"); println!("{:?}", config); @@ -187,19 +222,19 @@ async fn main() -> Result<(), Box> { log::warn!("Writing the default config to /etc/mesk/mesk.toml"); let path = Path::new("/etc/mesk/mesk.toml"); - std::fs::create_dir_all(path.parent().unwrap())?; - let mut file = std::fs::File::create(path)?; - file.write_all(config.as_bytes())?; + std::fs::create_dir_all(path.parent().unwrap())?; + let mut file = std::fs::File::create(path)?; + file.write_all(config.as_bytes())?; println!("Config tool ending work."); } return Ok(()); } Commands::Update => { - let config = Config::parse().unwrap(); + let config = Config::parse().unwrap(); println!("Updating index from {}", config.repo.repo_url); let mut i2p_client = I2PPackage::new(config); - i2p_client.fetch_index().await?; + i2p_client.fetch_index().await?; println!("Index updated successfully."); return Ok(()); } @@ -223,5 +258,4 @@ async fn main() -> Result<(), Box> { return Ok(()); } } - } diff --git a/src/net/http_package.rs b/src/net/http_package.rs index 4566e05..4924805 100644 --- a/src/net/http_package.rs +++ b/src/net/http_package.rs @@ -12,9 +12,8 @@ use std::{collections::HashMap, path::Path}; use tar::Archive; use tokio::{fs::File, io::AsyncWriteExt}; -use crate::pkgtoolkit::install::InstallOperations; use crate::pkgtoolkit::archive::ArchiveOperations; - +use crate::pkgtoolkit::install::InstallOperations; pub struct HTTPPackage { pub config: Config, @@ -278,7 +277,7 @@ impl HTTPPackage { // Install the package log::info!("Installing package '{}'...", package_name); let mut package = package_info.clone(); - + match package.install() { Ok(_) => { log::info!("Package '{}' installed successfully.", package_name); diff --git a/src/net/i2p_package.rs b/src/net/i2p_package.rs index cebfa34..fed3361 100644 --- a/src/net/i2p_package.rs +++ b/src/net/i2p_package.rs @@ -1,5 +1,7 @@ use crate::cfg::config::Config; use crate::pkgtoolkit::Package; +use crate::pkgtoolkit::archive::ArchiveOperations; +use crate::pkgtoolkit::install::InstallOperations; use flate2::read::GzDecoder; use futures_util::stream::TryStreamExt; use indicatif::{ProgressBar, ProgressStyle}; @@ -9,9 +11,6 @@ use std::fs::File as StdFile; use std::{collections::HashMap, path::Path}; use tar::Archive; use tokio::{fs::File, io::AsyncWriteExt}; -use crate::pkgtoolkit::archive::ArchiveOperations; -use crate::pkgtoolkit::install::InstallOperations; - pub struct I2PPackage { pub config: Config, @@ -44,9 +43,7 @@ impl I2PPackage { fn create_proxy_client(&self) -> Result> { let proxy_url = format!("http://127.0.0.1:{}", self.config.repo.i2p_http_proxy_port); let proxy = reqwest::Proxy::http(&proxy_url)?; - let client = reqwest::Client::builder() - .proxy(proxy) - .build()?; + let client = reqwest::Client::builder().proxy(proxy).build()?; Ok(client) } @@ -182,7 +179,6 @@ impl I2PPackage { file_path: &Path, description: &str, ) -> Result<(), Box> { - let head_response = client.head(url).send().await?; let content_length: u64 = head_response .headers() @@ -275,7 +271,7 @@ impl I2PPackage { // Install the package log::info!("Installing package '{}'...", package_name); let mut package = package_info.clone(); - + match package.install() { Ok(_) => { log::info!("Package '{}' installed successfully.", package_name); diff --git a/src/pkgtoolkit/archive.rs b/src/pkgtoolkit/archive.rs index 9d9a7d1..eef0888 100644 --- a/src/pkgtoolkit/archive.rs +++ b/src/pkgtoolkit/archive.rs @@ -39,21 +39,105 @@ impl ArchiveOperations for Package { 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() { - fs::remove_file(&meta_path)?; - } + // Extract to temporary directory first + let temp_dir = Path::new(cache_dir).join("temp_extract"); + if temp_dir.exists() { + fs::remove_dir_all(&temp_dir)?; } + fs::create_dir_all(&temp_dir)?; + 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) { + + // Unpack into temporary directory + match archive.unpack(&temp_dir) { Ok(()) => Ok(()), Err(e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(()), Err(e) => Err(e), + }?; + + // Read package name from INSTALL file to determine final directory + let install_path = temp_dir.join("INSTALL"); + if !install_path.exists() { + // Try to find INSTALL in subdirectories + for entry in fs::read_dir(&temp_dir)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + let install_in_subdir = path.join("INSTALL"); + if install_in_subdir.exists() { + // Move contents to temp_dir + for item in fs::read_dir(&path)? { + let item = item?; + let item_path = item.path(); + let dest_path = temp_dir.join(item_path.file_name().unwrap()); + fs::rename(&item_path, &dest_path)?; + } + fs::remove_dir(&path)?; + break; + } + } + } + } + + let mut install_path = None; + let mut pkg_dir_name = None; + + let root_install = temp_dir.join("INSTALL"); + if root_install.exists() { + install_path = Some(root_install); + pkg_dir_name = Some("package".to_string()); + } else { + for entry in fs::read_dir(&temp_dir)? { + let entry = entry?; + let path = entry.path(); + if path.is_dir() { + let install_in_subdir = path.join("INSTALL"); + if install_in_subdir.exists() { + install_path = Some(install_in_subdir); + pkg_dir_name = Some(path.file_name().unwrap().to_string_lossy().to_string()); + break; + } + } + } + } + + let install_path = install_path.ok_or_else(|| { + io::Error::new( + io::ErrorKind::NotFound, + "INSTALL file not found in archive", + ) + })?; + + let install_content = fs::read_to_string(&install_path)?; + let install_meta: Install = toml::from_str(&install_content) + .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; + + let final_dir_name = format!("{}-{}", install_meta.package.name, install_meta.package.version); + let final_dir = Path::new(cache_dir).join(&final_dir_name); + + if final_dir.exists() { + fs::remove_dir_all(&final_dir)?; } + fs::create_dir_all(&final_dir)?; + + if pkg_dir_name.clone().unwrap() == "package" { + for entry in fs::read_dir(&temp_dir)? { + let entry = entry?; + let src_path = entry.path(); + let dest_path = final_dir.join(src_path.file_name().unwrap()); + fs::rename(&src_path, &dest_path)?; + } + fs::remove_dir(&temp_dir)?; + } else { + let pkg_subdir = temp_dir.join(pkg_dir_name.clone().unwrap()); + fs::rename(&pkg_subdir, &final_dir)?; + + fs::remove_dir(&temp_dir)?; + } + + Ok(()) } /// Load meta information from the .mesk archive. @@ -72,7 +156,7 @@ impl ArchiveOperations for Package { /// is not found, or if the 'INSTALL' file is empty. #[allow(clippy::type_complexity)] fn loadmeta( - minimal_package_meta: &mut Self, + minimal_package_meta: &mut Package, ) -> Result<(Install, Option, Option), std::io::Error> { // Changed return type for more flexibility /* @@ -82,34 +166,38 @@ impl ArchiveOperations for Package { version = "1.0.0" arch = "X86_64" descr = "Just example INSTALL script" + license = "BSD-2-Clause" + url = "/repo/my-package.mesk" + git_repo = "https://github.com/example/my-package.git" [install] path = "/usr/bin/my-package" + dependencies = ["package", "i2pd", "llvm-19-devel", "etc..."] # Leave it empty if there are no dependencies user = "root" group = "root" mode = "755" - # Also [install] can be - # path = "/usr/bin/my-package" - # user = "root" - # group = "root" - # mode = "755" - # custom_script = "./install.sh" OR - # custom_script = """ - # echo "Installing my-package" - # sudo apt-get install my-package - # """ + Also [install] can be + path = "/usr/bin/my-package" + user = "root" + group = "root" + mode = "755" + custom_script = "./install.sh" OR + custom_script = """ + echo "Installing my-package" + sudo apt-get install my-package + """ + If there is a custom_script field, mesk will not automatically install your package and other fields in [install] will not be required. */ - let config = Config::parse().map_err(|e| std::io::Error::other(e.to_string()))?; fs::create_dir_all(&config.paths.cache_dir)?; let cache_dir = &config.paths.cache_dir; - let install_path = - Path::new(cache_dir).join(format!("{}/INSTALL", minimal_package_meta.name)); - 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)); + let pkg_dir_name = format!("{}-{}", minimal_package_meta.name, minimal_package_meta.version); + let install_path = Path::new(cache_dir).join(format!("{}/INSTALL", pkg_dir_name)); + let setts_path = Path::new(cache_dir).join(format!("{}/SETTS", pkg_dir_name)); + let build_path = Path::new(cache_dir).join(format!("{}/BUILD", pkg_dir_name)); if !install_path.exists() { return Err(io::Error::new( @@ -171,7 +259,6 @@ impl ArchiveOperations for Package { let config = Config::parse().map_err(|e| std::io::Error::other(e.to_string()))?; let cache_root = Path::new(&config.paths.cache_dir); - // Рекурсивно находим все файлы INSTALL под cache_root fn find_install(root: &Path) -> Result, std::io::Error> { let mut installs = Vec::new(); for entry in fs::read_dir(root)? { @@ -208,7 +295,6 @@ impl ArchiveOperations for Package { ) })?; - // Проверим, что структура именно //INSTALL if pkg_dir.parent() != Some(cache_root) { return Err(std::io::Error::new( std::io::ErrorKind::InvalidData, diff --git a/src/pkgtoolkit/build.rs b/src/pkgtoolkit/build.rs index a323521..6264b58 100644 --- a/src/pkgtoolkit/build.rs +++ b/src/pkgtoolkit/build.rs @@ -26,7 +26,6 @@ impl BuildOperations for Package { let config = Config::parse().map_err(|e| std::io::Error::other(e.to_string()))?; let build_dir = Path::new(&config.paths.cache_dir).join(format!("{}-{}", self.name, self.version)); - // Check if build directory exists if !build_dir.exists() { return Err(std::io::Error::other(format!( "Build directory not found: {}", @@ -34,7 +33,6 @@ impl BuildOperations for Package { ))); } - // Prepare environment variables let mut cmd_envs: Vec<(String, String)> = Vec::new(); if let Some(ref env_vars) = build_meta.env { for env_line in env_vars.lines() { @@ -44,12 +42,10 @@ impl BuildOperations for Package { } } - // Handle custom build script if provided if let Some(ref script) = build_meta.script { log::info!("Executing custom build script: {}", script); Self::validate_custom_script(script)?; - let mut cmd = if script.starts_with("./") || script.contains('/') { - // Assume it's a file path + let mut cmd = if script.starts_with("./") || script.starts_with('/') { let script_path = build_dir.join(script); if !script_path.exists() { return Err(std::io::Error::other(format!( @@ -62,7 +58,6 @@ impl BuildOperations for Package { inner_cmd.arg(script_path.to_str().unwrap()); inner_cmd } else { - // Inline script let mut inner_cmd = Command::new("/bin/sh"); inner_cmd.arg("-c"); inner_cmd.arg(script); @@ -121,7 +116,7 @@ impl BuildOperations for Package { } } BuildSystems::CMake => { - // Check for CMakeLists.txt + let cmake_file = build_dir.join("CMakeLists.txt"); if !cmake_file.exists() { return Err(std::io::Error::other(format!( @@ -153,7 +148,6 @@ impl BuildOperations for Package { ))); } - // Now build let mut build_cmd = Command::new("make"); build_cmd.current_dir(&build_dir_build); build_cmd.arg("-j").arg(num_cpus::get().to_string()); // Parallel build @@ -174,7 +168,6 @@ impl BuildOperations for Package { } } BuildSystems::Meson => { - // Check for meson.build let meson_file = build_dir.join("meson.build"); if !meson_file.exists() { return Err(std::io::Error::other(format!( diff --git a/src/pkgtoolkit/git_source.rs b/src/pkgtoolkit/git_source.rs index 2f33c14..0bedf0a 100644 --- a/src/pkgtoolkit/git_source.rs +++ b/src/pkgtoolkit/git_source.rs @@ -1,8 +1,8 @@ +use crate::cfg::config::Config; +use crate::pkgtoolkit::types::Package; +use git2::Repository; use std::fs; use std::path::Path; -use git2::Repository; -use crate::pkgtoolkit::types::Package; -use crate::cfg::config::Config; use toml; pub struct GitSource; @@ -15,8 +15,13 @@ impl GitSource { } /// Get source code for a package from its git repository - pub fn get_package_source(package: &Package, config: &Config) -> Result> { - let git_repo = package.git_repo.as_ref() + pub fn get_package_source( + package: &Package, + config: &Config, + ) -> Result> { + let git_repo = package + .git_repo + .as_ref() .ok_or("Package does not have a git repository specified")?; let source_dir = Path::new(&config.paths.cache_dir) @@ -31,53 +36,57 @@ impl GitSource { let source_path = source_dir.to_string_lossy().to_string(); println!("Source code downloaded to: {}", source_path); - + Ok(source_path) } /// Get source code for a package by name, first checking INSTALL file, then falling back to index - pub fn get_source_by_name(pkg_name: &str, config: &Config) -> Result> { - // First try to get git_repo from INSTALL file in cache + pub fn get_source_by_name( + pkg_name: &str, + config: &Config, + ) -> Result> { let install_path = Path::new(&config.paths.cache_dir).join(format!("{}/INSTALL", pkg_name)); - + if install_path.exists() { let install_content = fs::read_to_string(&install_path)?; let install_data: crate::pkgtoolkit::types::Install = toml::from_str(&install_content) .map_err(|e| format!("Failed to parse INSTALL file: {}", e))?; - + // Check if InstallMeta has git_repo if let Some(git_repo) = install_data.install.git_repo { println!("Found git repository in INSTALL file: {}", git_repo); - + let source_dir = Path::new(&config.paths.cache_dir) .join("sources") .join(&install_data.package.name) .join(&install_data.package.version); fs::create_dir_all(&source_dir)?; - + println!("Cloning {} from {}", install_data.package.name, git_repo); Self::clone_repo(&git_repo, &source_dir)?; - + let source_path = source_dir.to_string_lossy().to_string(); println!("Source code downloaded to: {}", source_path); - + return Ok(source_path); } } - + // Fall back to index if INSTALL file doesn't exist or doesn't have git_repo let index_path = Path::new(&config.paths.cache_dir).join("INDEX.toml"); - + if !index_path.exists() { return Err("Index file not found. Please run 'mesk update' first.".into()); } let index_content = fs::read_to_string(&index_path)?; - let index: crate::pkgtoolkit::types::Index = toml::from_str(&index_content) - .map_err(|e| format!("Failed to parse index: {}", e))?; + let index: crate::pkgtoolkit::types::Index = + toml::from_str(&index_content).map_err(|e| format!("Failed to parse index: {}", e))?; - let package = index.packages.iter() + let package = index + .packages + .iter() .find(|pkg| pkg.name == pkg_name) .ok_or(format!("Package '{}' not found in index", pkg_name))?; -- cgit v1.2.3