summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs102
-rw-r--r--src/pkgtoolkit/archive.rs28
-rw-r--r--src/pkgtoolkit/build.rs1
-rw-r--r--src/pkgtoolkit/install.rs205
4 files changed, 256 insertions, 80 deletions
diff --git a/src/main.rs b/src/main.rs
index 068a8fb..4de9e55 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -10,11 +10,11 @@ use crate::pkgtoolkit::archive::ArchiveOperations;
use crate::pkgtoolkit::build::BuildOperations;
use crate::pkgtoolkit::git_source::GitSource;
use crate::pkgtoolkit::index::IndexOperations;
+use crate::pkgtoolkit::install::InstallOperations;
use clap::{Args, Parser, Subcommand};
use std::io::Write;
use std::path::Path;
-use toml;
#[derive(Parser)]
struct Cli {
@@ -34,8 +34,12 @@ enum Commands {
Build { pkgname: String },
#[command(about = "Install package from remote or local sources")]
Install {
+ #[arg(help = "Package name or path to local .mesk file")]
pkgname: String,
source: Option<String>,
+ #[arg(short = 'p', long = "path")]
+ #[arg(help = "Install from local .mesk file")]
+ path: bool,
#[command(flatten)]
args: RemoteInstallArgs,
},
@@ -74,6 +78,7 @@ struct RemoteInstallArgs {
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
+
let cli: Cli = Cli::parse();
match &cli.command {
@@ -114,11 +119,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
println!("Extracting archive...");
- Package::extract_archive(&pkgname)?;
+ Package::extract_archive(pkgname)?;
let config = Config::parse().unwrap();
let cache_dir = &config.paths.cache_dir;
-
+
// Find the package directory (should be name-version format)
let mut pkg_dir_name = None;
for entry in std::fs::read_dir(cache_dir)? {
@@ -135,17 +140,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
}
}
-
- let pkg_dir_name = pkg_dir_name.ok_or_else(|| {
- std::io::Error::other("Package directory not found in cache")
- })?;
-
+
+ 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 package directory").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)?;
@@ -159,23 +165,69 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
Commands::Install {
pkgname,
source: _,
+ path,
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?;
- log::info!("Index fetched successfully.");
- http_client.fetch_package_http(pkgname).await?;
- log::info!("Package '{}' installed successfully.", pkgname);
+ if *path {
+ println!("Installing package from local file: {}", pkgname);
+
+ println!("Extracting archive...");
+ Package::extract_archive(pkgname)?;
+
+ let config = Config::parse().unwrap();
+ let cache_dir = &config.paths.cache_dir;
+
+ 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));
+ let install_content = std::fs::read_to_string(&install_toml_path)?;
+ let install_data: crate::pkgtoolkit::types::Install =
+ toml::from_str(&install_content)?;
+
+ let mut pkg = install_data.package;
+
+ println!("Building package '{}'...", pkg.name);
+ pkg.build()?;
+
+ println!("Installing package '{}'...", pkg.name);
+ pkg.install()?;
+ println!("Package '{}' installed successfully.", pkg.name);
} else {
- println!("Installing {} via I2P", pkgname);
- let mut i2p_client = I2PPackage::new(config);
- i2p_client.fetch_index().await?;
- log::info!("Index fetched successfully.");
- i2p_client.fetch_package(pkgname).await?;
- log::info!("Package '{}' installed successfully.", pkgname);
+
+ 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?;
+ 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?;
+ log::info!("Index fetched successfully.");
+ i2p_client.fetch_package(pkgname).await?;
+ log::info!("Package '{}' installed successfully.", pkgname);
+ }
}
return Ok(());
}
diff --git a/src/pkgtoolkit/archive.rs b/src/pkgtoolkit/archive.rs
index eef0888..db10f01 100644
--- a/src/pkgtoolkit/archive.rs
+++ b/src/pkgtoolkit/archive.rs
@@ -49,7 +49,7 @@ impl ArchiveOperations for Package {
let file = File::open(path_to_archive)?;
let gz = GzDecoder::new(file);
let mut archive = Archive::new(gz);
-
+
// Unpack into temporary directory
match archive.unpack(&temp_dir) {
Ok(()) => Ok(()),
@@ -87,7 +87,7 @@ impl ArchiveOperations for Package {
let root_install = temp_dir.join("INSTALL");
if root_install.exists() {
install_path = Some(root_install);
- pkg_dir_name = Some("package".to_string());
+ pkg_dir_name = Some("package".to_string());
} else {
for entry in fs::read_dir(&temp_dir)? {
let entry = entry?;
@@ -96,7 +96,8 @@ impl ArchiveOperations for Package {
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());
+ pkg_dir_name =
+ Some(path.file_name().unwrap().to_string_lossy().to_string());
break;
}
}
@@ -104,19 +105,19 @@ impl ArchiveOperations for Package {
}
let install_path = install_path.ok_or_else(|| {
- io::Error::new(
- io::ErrorKind::NotFound,
- "INSTALL file not found in archive",
- )
+ 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_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)?;
}
@@ -177,12 +178,12 @@ impl ArchiveOperations for Package {
group = "root"
mode = "755"
- Also [install] can be
+ Also [install] can be
path = "/usr/bin/my-package"
user = "root"
group = "root"
mode = "755"
- custom_script = "./install.sh" OR
+ custom_script = "./install.sh" OR
custom_script = """
echo "Installing my-package"
sudo apt-get install my-package
@@ -194,7 +195,10 @@ impl ArchiveOperations for Package {
fs::create_dir_all(&config.paths.cache_dir)?;
let cache_dir = &config.paths.cache_dir;
- let pkg_dir_name = format!("{}-{}", minimal_package_meta.name, minimal_package_meta.version);
+ 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));
diff --git a/src/pkgtoolkit/build.rs b/src/pkgtoolkit/build.rs
index 6264b58..326be1e 100644
--- a/src/pkgtoolkit/build.rs
+++ b/src/pkgtoolkit/build.rs
@@ -116,7 +116,6 @@ impl BuildOperations for Package {
}
}
BuildSystems::CMake => {
-
let cmake_file = build_dir.join("CMakeLists.txt");
if !cmake_file.exists() {
return Err(std::io::Error::other(format!(
diff --git a/src/pkgtoolkit/install.rs b/src/pkgtoolkit/install.rs
index 65476d9..37155c2 100644
--- a/src/pkgtoolkit/install.rs
+++ b/src/pkgtoolkit/install.rs
@@ -157,58 +157,179 @@ impl InstallOperations for Package {
"No custom script. Running default install hook for {}",
install_meta.package.name
);
- let source_file_name = &self.name;
+ log::info!("Starting default install process");
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.install.path);
- // Check if source file exists
- if !src_path.exists() {
- return Err(std::io::Error::other(format!(
- "Source binary file not found: {}",
- src_path.display()
- )));
- }
+ log::info!(
+ "Install path: {:?}, is_dir: {}, ends_with_slash: {}",
+ dest_path,
+ dest_path.is_dir(),
+ dest_path.to_string_lossy().ends_with('/')
+ );
- if let Some(parent) = dest_path.parent() {
- create_dir_all(parent).map_err(|e| {
- std::io::Error::other(format!("Failed to create parent dir: {}", e))
+ // Check if dest_path is a directory, if so, copy all executables from target/release
+ if dest_path.is_dir() || dest_path.to_string_lossy().ends_with('/') {
+ log::info!("Taking multi-binary package path");
+ // Multi-binary package - copy all executables from target/release
+ let target_release = build_dir.join("target/release");
+ if !target_release.exists() {
+ return Err(std::io::Error::other(format!(
+ "target/release directory not found: {}",
+ target_release.display()
+ )));
+ }
+
+ // Create destination directory if it doesn't exist
+ create_dir_all(dest_path).map_err(|e| {
+ std::io::Error::other(format!("Failed to create dest dir: {}", e))
})?;
- }
- fs::copy(&src_path, dest_path)
- .map_err(|e| std::io::Error::other(format!("Failed to copy file: {}", e)))?;
+ let mut copied_files = Vec::new();
+ for entry in fs::read_dir(&target_release)? {
+ let entry = entry?;
+ let path = entry.path();
+
+ // Check if it's an executable file
+ if path.is_file()
+ && let Ok(metadata) = fs::metadata(&path) {
+ let mode = metadata.permissions().mode();
+ log::debug!(
+ "Checking file: {:?}, mode: {:o}",
+ path.file_name(),
+ mode
+ );
+ if mode & 0o111 != 0 {
+ let file_name = path.file_name().unwrap().to_string_lossy();
+ let dest_file = dest_path.join(&*file_name);
+
+ log::info!(
+ "Copying executable: {} to {}",
+ file_name,
+ dest_file.display()
+ );
+ fs::copy(&path, &dest_file).map_err(|e| {
+ std::io::Error::other(format!(
+ "Failed to copy {}: {}",
+ file_name, e
+ ))
+ })?;
+
+ copied_files.push(dest_file);
+ } else {
+ log::debug!(
+ "File {:?} is not executable (mode: {:o})",
+ path.file_name(),
+ mode
+ );
+ }
+ }
+
+ }
- let mode = u32::from_str_radix(&install_meta.install.mode, 8).map_err(|_| {
- std::io::Error::new(
- std::io::ErrorKind::InvalidData,
- "Invalid mode string in INSTALL",
- )
- })?;
- let perms = Permissions::from_mode(mode);
- set_permissions(dest_path, perms).map_err(|e| {
- std::io::Error::other(format!("Failed to set permissions: {}", e))
- })?;
+ if copied_files.is_empty() {
+ return Err(std::io::Error::other(
+ "No executable files found in target/release",
+ ));
+ }
- let output = Command::new("chown")
- .arg(format!(
- "{}:{}",
- install_meta.install.user, install_meta.install.group
- ))
- .arg(dest_path)
- .output()
- .map_err(|e| std::io::Error::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
- );
- }
+ // Set permissions and ownership for all copied files
+ let mode =
+ u32::from_str_radix(&install_meta.install.mode, 8).map_err(|_| {
+ std::io::Error::new(
+ std::io::ErrorKind::InvalidData,
+ "Invalid mode string in INSTALL",
+ )
+ })?;
+ let perms = Permissions::from_mode(mode);
+
+ for file_path in &copied_files {
+ set_permissions(file_path, perms.clone()).map_err(|e| {
+ std::io::Error::other(format!(
+ "Failed to set permissions for {}: {}",
+ file_path.display(),
+ e
+ ))
+ })?;
+
+ let output = Command::new("chown")
+ .arg(format!(
+ "{}:{}",
+ install_meta.install.user, install_meta.install.group
+ ))
+ .arg(file_path)
+ .output()
+ .map_err(|e| {
+ std::io::Error::other(format!("'chown' command failed: {}", e))
+ })?;
+
+ if !output.status.success() {
+ let stderr = String::from_utf8_lossy(&output.stderr);
+ log::warn!(
+ "Warning: 'chown' command failed for {} (requires root?):\n{}",
+ file_path.display(),
+ stderr
+ );
+ }
+ }
+ } else {
+ log::info!("Taking single binary package path");
+ // Single binary package - copy specific file
+ let source_file_name = &self.name;
+ let src_path = build_dir.join(source_file_name);
+
+ // Check if source file exists
+ if !src_path.exists() {
+ return Err(std::io::Error::other(format!(
+ "Source binary file not found: {}",
+ src_path.display()
+ )));
+ }
+
+ if let Some(parent) = dest_path.parent() {
+ create_dir_all(parent).map_err(|e| {
+ std::io::Error::other(format!("Failed to create parent dir: {}", e))
+ })?;
+ }
+
+ fs::copy(&src_path, dest_path).map_err(|e| {
+ std::io::Error::other(format!("Failed to copy file: {}", e))
+ })?;
+
+ let mode =
+ u32::from_str_radix(&install_meta.install.mode, 8).map_err(|_| {
+ std::io::Error::new(
+ std::io::ErrorKind::InvalidData,
+ "Invalid mode string in INSTALL",
+ )
+ })?;
+ let perms = Permissions::from_mode(mode);
+ set_permissions(dest_path, perms).map_err(|e| {
+ std::io::Error::other(format!("Failed to set permissions: {}", e))
+ })?;
- all_files = install_meta.files;
+ let output = Command::new("chown")
+ .arg(format!(
+ "{}:{}",
+ install_meta.install.user, install_meta.install.group
+ ))
+ .arg(dest_path)
+ .output()
+ .map_err(|e| {
+ std::io::Error::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
+ );
+ }
+
+ all_files = install_meta.files;
+ }
}
}