summaryrefslogtreecommitdiff
path: root/src/pkgtoolkit
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkgtoolkit')
-rw-r--r--src/pkgtoolkit/archive.rs136
-rw-r--r--src/pkgtoolkit/build.rs11
-rw-r--r--src/pkgtoolkit/git_source.rs47
3 files changed, 141 insertions, 53 deletions
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<Setts>, Option<Build>), 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<Vec<std::path::PathBuf>, std::io::Error> {
let mut installs = Vec::new();
for entry in fs::read_dir(root)? {
@@ -208,7 +295,6 @@ impl ArchiveOperations for Package {
)
})?;
- // Проверим, что структура именно <cachedir>/<packagename>/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<String, Box<dyn std::error::Error>> {
- let git_repo = package.git_repo.as_ref()
+ pub fn get_package_source(
+ package: &Package,
+ config: &Config,
+ ) -> Result<String, Box<dyn std::error::Error>> {
+ 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<String, Box<dyn std::error::Error>> {
- // First try to get git_repo from INSTALL file in cache
+ pub fn get_source_by_name(
+ pkg_name: &str,
+ config: &Config,
+ ) -> Result<String, Box<dyn std::error::Error>> {
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))?;