summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock222
-rw-r--r--Cargo.toml8
-rw-r--r--examples/INSTALL2
-rw-r--r--src/cfg/config.rs4
-rw-r--r--src/main.rs160
-rw-r--r--src/net/http_package.rs37
-rw-r--r--src/net/i2p_package.rs342
-rw-r--r--src/pkgtoolkit/git_source.rs86
-rw-r--r--src/pkgtoolkit/index.rs1
-rw-r--r--src/pkgtoolkit/mod.rs5
-rw-r--r--src/pkgtoolkit/types.rs3
-rw-r--r--tests/http_funcs.rs1
-rw-r--r--tests/i2p_functions.rs1
-rw-r--r--tests/pkgtoolkit_funcs.rs32
-rw-r--r--tests/shared.rs12
15 files changed, 507 insertions, 409 deletions
diff --git a/Cargo.lock b/Cargo.lock
index fbadd4a..b276d20 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -136,6 +136,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
dependencies = [
"find-msvc-tools",
+ "jobserver",
+ "libc",
"shlex",
]
@@ -368,28 +370,12 @@ dependencies = [
]
[[package]]
-name = "futures"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
-dependencies = [
- "futures-channel",
- "futures-core",
- "futures-executor",
- "futures-io",
- "futures-sink",
- "futures-task",
- "futures-util",
-]
-
-[[package]]
name = "futures-channel"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
dependencies = [
"futures-core",
- "futures-sink",
]
[[package]]
@@ -399,17 +385,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
[[package]]
-name = "futures-executor"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
-dependencies = [
- "futures-core",
- "futures-task",
- "futures-util",
-]
-
-[[package]]
name = "futures-io"
version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -444,7 +419,6 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
dependencies = [
- "futures-channel",
"futures-core",
"futures-io",
"futures-macro",
@@ -480,6 +454,21 @@ dependencies = [
]
[[package]]
+name = "git2"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724"
+dependencies = [
+ "bitflags",
+ "libc",
+ "libgit2-sys",
+ "log",
+ "openssl-probe",
+ "openssl-sys",
+ "url",
+]
+
+[[package]]
name = "h2"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -820,6 +809,16 @@ dependencies = [
]
[[package]]
+name = "jobserver"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
+dependencies = [
+ "getrandom 0.3.4",
+ "libc",
+]
+
+[[package]]
name = "js-sys"
version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -836,6 +835,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
[[package]]
+name = "libgit2-sys"
+version = "0.17.0+1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224"
+dependencies = [
+ "cc",
+ "libc",
+ "libssh2-sys",
+ "libz-sys",
+ "openssl-sys",
+ "pkg-config",
+]
+
+[[package]]
name = "libredox"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -847,6 +860,32 @@ dependencies = [
]
[[package]]
+name = "libssh2-sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9"
+dependencies = [
+ "cc",
+ "libc",
+ "libz-sys",
+ "openssl-sys",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "libz-sys"
+version = "1.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -883,25 +922,24 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
name = "mesk"
version = "0.0.1"
dependencies = [
- "cc",
"clap",
"env_logger",
"flate2",
"futures-util",
+ "git2",
"indicatif",
"log",
"mockito",
"num_cpus",
"reqwest",
"serde",
- "serde_json",
"tar",
"tempfile",
"tokio",
"tokio-test",
"toml",
"url",
- "yosemite",
+ "uuid",
]
[[package]]
@@ -911,12 +949,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
-[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -954,7 +986,7 @@ dependencies = [
"hyper-util",
"log",
"pin-project-lite",
- "rand 0.9.2",
+ "rand",
"regex",
"serde_json",
"serde_urlencoded",
@@ -980,16 +1012,6 @@ dependencies = [
]
[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
-]
-
-[[package]]
name = "num_cpus"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1161,33 +1183,12 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
[[package]]
name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha 0.3.1",
- "rand_core 0.6.4",
-]
-
-[[package]]
-name = "rand"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
- "rand_chacha 0.9.0",
- "rand_core 0.9.3",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core 0.6.4",
+ "rand_chacha",
+ "rand_core",
]
[[package]]
@@ -1197,16 +1198,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
- "rand_core 0.9.3",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom 0.2.16",
+ "rand_core",
]
[[package]]
@@ -1480,6 +1472,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
+name = "signal-hook-registry"
+version = "1.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "simd-adler32"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1608,26 +1609,6 @@ dependencies = [
]
[[package]]
-name = "thiserror"
-version = "1.0.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "tinystr"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1648,6 +1629,7 @@ dependencies = [
"mio",
"parking_lot",
"pin-project-lite",
+ "signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys 0.61.2",
@@ -1811,24 +1793,11 @@ version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
dependencies = [
- "log",
"pin-project-lite",
- "tracing-attributes",
"tracing-core",
]
[[package]]
-name = "tracing-attributes"
-version = "0.1.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
name = "tracing-core"
version = "0.1.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1892,6 +1861,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
+name = "uuid"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
+dependencies = [
+ "getrandom 0.3.4",
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2264,20 +2244,6 @@ dependencies = [
]
[[package]]
-name = "yosemite"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19cf621ae2b2d7e5d1e3827231fbf59ca4fb72b3589e36cdf648e820f1cf6e0d"
-dependencies = [
- "futures",
- "nom",
- "rand 0.8.5",
- "thiserror",
- "tokio",
- "tracing",
-]
-
-[[package]]
name = "zerocopy"
version = "0.8.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index d6bcb88..6c255df 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,19 +11,16 @@ description = "An i2p-based package manager developed by Anthrill project"
clap = { version = "4.5.53", features = ["derive"] }
toml = { version = "0.9.8", features = ["serde"] }
serde = { version = "1.0.228", features = ["derive"] }
-tokio = { version = "1.48.0", features = ["fs", "io-util", "macros", "rt"] }
+tokio = { version = "1.48.0", features = ["full"] }
reqwest = { version = "0.12.24", features = ["stream"] }
flate2 = "1.1.5"
log = "0.4.28"
tar = "0.4.44"
-yosemite = "0.6.1"
-cc = "1.2.48"
url = "2.5.7"
indicatif = "0.18.3"
futures-util = "0.3.31"
num_cpus = "1.17.0"
-tempfile = "3.23.0"
-serde_json = "1.0.145"
+git2 = "0.19.0"
[dev-dependencies]
env_logger = "0.11.8"
@@ -31,4 +28,5 @@ log = "0.4.28"
mockito = "1.7.1"
tempfile = "3.23.0"
tokio-test = "0.4.4"
+uuid = { version = "1.19.0", features = ["v4"] }
diff --git a/examples/INSTALL b/examples/INSTALL
index 76f08a0..d33accf 100644
--- a/examples/INSTALL
+++ b/examples/INSTALL
@@ -4,6 +4,8 @@ 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"
diff --git a/src/cfg/config.rs b/src/cfg/config.rs
index f14ec93..ce9df87 100644
--- a/src/cfg/config.rs
+++ b/src/cfg/config.rs
@@ -39,6 +39,8 @@ pub struct Repo {
pub destination: (String, String),
#[serde(rename = "repo_http_url")]
pub repo_http_url: Option<String>,
+ #[serde(rename = "i2p_http_proxy_port")]
+ pub i2p_http_proxy_port: u16,
// #[serde(rename = "arch")]
// pub arch = arch;
}
@@ -92,6 +94,7 @@ impl Config {
std::env::consts::ARCH
)
.into(),
+ i2p_http_proxy_port: 4444,
// Its a hurt place, you need to generate destinations by i2pd and paste here (to mesk.toml)
// Better to leave it empty or set it to (mesk, mesk), now destination conn not implemented
},
@@ -126,6 +129,7 @@ impl Config {
auto_update: true,
destination: (String::from("mesk"), String::from("mesk")),
repo_http_url: None,
+ i2p_http_proxy_port: 4444,
},
log: Log {
log_file: String::from("/var/log/mesk.log"),
diff --git a/src/main.rs b/src/main.rs
index b3367f3..2bdb29c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -7,12 +7,14 @@ 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 clap::{Args, Parser, Subcommand};
-use std::fs::File;
-use std::fs::create_dir_all;
use std::io::Write;
use std::path::Path;
+use toml;
#[derive(Parser)]
struct Cli {
@@ -70,70 +72,79 @@ struct RemoteInstallArgs {
clean: bool,
}
+
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
- // Changed return type to be more general
let cli: Cli = Cli::parse();
match &cli.command {
Commands::Validate { path } => {
println!("Validating {}", path);
+ match Package::check(path.to_string()) {
+ Ok(is_valid) => {
+ if is_valid {
+ println!("Package archive is valid.");
+ } else {
+ println!("Package archive is invalid.");
+ return Err(std::io::Error::other("Invalid package archive").into());
+ }
+ }
+ Err(e) => {
+ log::error!("Failed to validate package '{}': {}", path, e);
+ return Err(e.into());
+ }
+ }
return Ok(());
}
Commands::Build { pkgname } => {
- println!("Building {}", pkgname);
+ println!("Building package from archive: {}", pkgname);
+
+ let path = Path::new(&pkgname);
+ if !path.exists() {
+ 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());
+ }
+
+ println!("Extracting archive...");
+ Package::extract_archive(&pkgname)?;
+
+ let config = Config::parse().unwrap();
+ let cache_dir = &config.paths.cache_dir;
+ let install_toml_path = Path::new(cache_dir).join("INSTALL");
+
+ if !install_toml_path.exists() {
+ return Err(std::io::Error::other("INSTALL file not found in archive").into());
+ }
+
+ 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!("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);
- match http_client.fetch_index_http().await {
- Ok(_) => {
- log::info!("Index fetched successfully.");
- }
- Err(e) => {
- log::error!("Failed to fetch index: {}", e);
- return Err(e);
- }
- }
- match http_client.fetch_package_http(pkgname).await {
- Ok(_) => {
- log::info!("Package '{}' installed successfully.", pkgname);
- }
- Err(e) => {
- log::error!("Failed to install package '{}': {}", pkgname, e);
- return Err(e);
- }
- }
+ 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);
-
- match i2p_client.fetch_index().await {
- Ok(_) => {
- log::info!("Index fetched successfully.");
- }
- Err(e) => {
- log::error!("Failed to fetch index: {}", e);
- return Err(e);
- }
- }
- match i2p_client.fetch_package(pkgname).await {
- Ok(_) => {
- log::info!("Package '{}' installed successfully.", pkgname);
- }
- Err(e) => {
- log::error!("Failed to install package '{}': {}", pkgname, e);
- return Err(e);
- }
- }
+ i2p_client.fetch_index().await?;
+ log::info!("Index fetched successfully.");
+ i2p_client.fetch_package(pkgname).await?;
+ log::info!("Package '{}' installed successfully.", pkgname);
}
return Ok(());
}
@@ -142,15 +153,15 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
return Ok(());
}
Commands::GetSource { pkgname } => {
+ 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();
@@ -162,12 +173,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
log::warn!("Writing the default config to /etc/mesk/mesk.toml");
let path = Path::new("/etc/mesk/mesk.toml");
- create_dir_all(path.parent().unwrap())?;
- let mut file = 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);
@@ -176,27 +187,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
log::warn!("Writing the default config to /etc/mesk/mesk.toml");
let path = Path::new("/etc/mesk/mesk.toml");
- create_dir_all(path.parent().unwrap())?;
- let mut file = 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);
- match i2p_client.fetch_index().await {
- Ok(_) => {
- println!("Index updated successfully.");
- }
- Err(e) => {
- log::error!("Failed to update index: {}", e);
- return Err(e);
- }
- }
+ i2p_client.fetch_index().await?;
+ println!("Index updated successfully.");
return Ok(());
}
Commands::Upgrade { pkgname } => {
@@ -208,22 +212,16 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
"CREATED BY: Asya and Namilsk as part of the Anthrill independent Global network distribution project"
);
println!(" ");
- println!("The Anthrill project repos: https://codeberg.org/NamelessTeam ");
+ println!("The Anthrill project repos: https://codeberg.org/NamelessTeam ");
+ return Ok(());
}
Commands::GenIndex { path } => {
println!("Generating index for {}", path);
- match Package::gen_index(path) {
- Ok(_) => {
- println!("Index generated successfully.");
- }
- Err(e) => {
- log::error!("Failed to generate index: {}", e);
- return Err(Box::new(e));
- }
- }
+
+ Package::gen_index(path)?;
+ println!("Index generated successfully.");
return Ok(());
}
}
- Ok(())
}
diff --git a/src/net/http_package.rs b/src/net/http_package.rs
index d31cc90..4566e05 100644
--- a/src/net/http_package.rs
+++ b/src/net/http_package.rs
@@ -12,6 +12,10 @@ 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;
+
+
pub struct HTTPPackage {
pub config: Config,
pub index_packages: Option<HashMap<String, Package>>,
@@ -143,7 +147,10 @@ impl HTTPPackage {
let mut package_map = HashMap::new();
for pkg in index_data.packages {
- let base_url = url::Url::parse(&self.config.repo.repo_url)?;
+ let base_url = match &self.config.repo.repo_http_url {
+ Some(url) => url::Url::parse(url)?,
+ None => url::Url::parse(&self.config.repo.repo_url)?,
+ };
let full_url = base_url.join(&pkg.url)?;
let mut pkg_clone = pkg.clone();
pkg_clone.url = full_url.to_string();
@@ -227,12 +234,13 @@ impl HTTPPackage {
/// Fetches a specific package identified by `package_name`.
/// Assumes `fetch_index_http` has been called and `self.index_packages` is populated to get the URL.
- /// Downloads the package file (.mesk) to the cache directory with a progress bar.
+ /// Downloads the package file (.mesk) to the cache directory with a progress bar,
+ /// extracts it, and installs the package.
///
/// # Errors
///
/// Returns an error if the index is not loaded, the package is not found in the index,
- /// the package URL is invalid, the request fails, or if there's an issue writing the file.
+ /// the package URL is invalid, the request fails, extraction fails, or installation fails.
pub async fn fetch_package_http(
&self,
package_name: &str,
@@ -259,7 +267,28 @@ impl HTTPPackage {
package_name,
file_path
);
- Ok(true)
+
+ // Extract the package archive
+ log::info!("Extracting package archive for '{}'...", package_name);
+ Package::extract_archive(&file_path.to_string_lossy())
+ .map_err(|e| format!("Failed to extract package archive: {}", e))?;
+
+ log::info!("Package archive extracted successfully.");
+
+ // 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);
+ Ok(true)
+ }
+ Err(e) => {
+ log::error!("Failed to install package '{}': {}", package_name, e);
+ Err(format!("Installation failed: {}", e).into())
+ }
+ }
}
/// Fetches a specific package identified by `index` (likely the package name).
diff --git a/src/net/i2p_package.rs b/src/net/i2p_package.rs
index a9d39d2..cebfa34 100644
--- a/src/net/i2p_package.rs
+++ b/src/net/i2p_package.rs
@@ -1,23 +1,17 @@
use crate::cfg::config::Config;
use crate::pkgtoolkit::Package;
-use crate::pkgtoolkit::archive::ArchiveOperations;
-use serde::Deserialize;
-use tokio;
-
-/*
-use emissary_core::runtime::{
- AsyncRead,
- AsyncWrite,
-};
-*/
-
+use flate2::read::GzDecoder;
+use futures_util::stream::TryStreamExt;
use indicatif::{ProgressBar, ProgressStyle};
+use reqwest;
+use serde::Deserialize;
+use std::fs::File as StdFile;
use std::{collections::HashMap, path::Path};
-use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader};
+use tar::Archive;
+use tokio::{fs::File, io::AsyncWriteExt};
+use crate::pkgtoolkit::archive::ArchiveOperations;
+use crate::pkgtoolkit::install::InstallOperations;
-use url;
-use yosemite::Session;
-use yosemite::SessionOptions;
pub struct I2PPackage {
pub config: Config,
@@ -30,81 +24,69 @@ struct IndexData {
}
impl I2PPackage {
- /// Creates a new I2P object with the given configuration.
+ /// Creates a new I2PPackage object with the given configuration.
///
/// # Returns
///
- /// A new I2P object with the given configuration. The session is initially set to None and the connected status is set to false.
- pub fn new(cfg: Config) -> Self {
+ /// A new I2PPackage object with the given configuration.
+ pub fn new(config: Config) -> Self {
I2PPackage {
- config: cfg,
+ config,
index_packages: None,
}
}
- /// Downloads the INDEX.tar.gz file from the configured repository
- /// and stores it in the configured cache directory.
+ /// Creates a reqwest client configured to use the I2P HTTP proxy.
+ ///
+ /// # Returns
+ ///
+ /// A reqwest Client with proxy configuration for I2P.
+ fn create_proxy_client(&self) -> Result<reqwest::Client, Box<dyn std::error::Error>> {
+ 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()?;
+ Ok(client)
+ }
+
+ /// Downloads the INDEX.tar.gz file from the configured I2P repository
+ /// and stores it in the configured cache directory with a progress bar.
///
/// # Errors
///
/// Returns an error if the request fails, if the response status is not successful, or if there's an issue while reading or writing the file.
pub async fn fetch_index(&mut self) -> Result<bool, Box<dyn std::error::Error>> {
- let repo_url_str = &self.config.repo.repo_url;
+ let repo_url = &self.config.repo.repo_url;
let cache_dir = &self.config.paths.cache_dir;
- let url = url::Url::parse(repo_url_str)?;
- let host = url.host_str().ok_or("No host in URL")?;
+ log::debug!("Cache directory: {:?}", cache_dir);
- let request_path = url.path();
- let request_path = if request_path.ends_with(".tar.gz") {
- request_path.to_string()
+ let index_url = if repo_url.ends_with(".tar.gz") {
+ repo_url.to_string()
} else {
- format!("{}/INDEX.tar.gz", request_path.trim_end_matches('/'))
+ format!("{}/INDEX.tar.gz", repo_url.trim_end_matches('/'))
};
- let session_options = SessionOptions::default();
- let mut session = Session::new(session_options).await?;
- let mut stream = session.connect(host).await?;
+ let client = self.create_proxy_client()?;
- let request = format!(
- "GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n",
- request_path, host
- );
- stream.write_all(request.as_bytes()).await?;
-
- let mut reader = BufReader::new(stream);
- let mut response_buffer = Vec::new();
- reader.read_to_end(&mut response_buffer).await?;
-
- let headers_end = response_buffer
- .windows(4)
- .position(|window| window == b"\r\n\r\n")
- .ok_or("Invalid response: no headers end")?;
-
- let headers_str = std::str::from_utf8(&response_buffer[..headers_end])?;
- if !headers_str.starts_with("HTTP/1.1 200") && !headers_str.starts_with("HTTP/1.0 200") {
- return Err(format!(
- "HTTP Error: {}",
- headers_str.lines().next().unwrap_or("Unknown")
- )
- .into());
- }
-
- let content_length = headers_str
- .lines()
- .find(|line| line.to_lowercase().starts_with("content-length:"))
- .and_then(|line| line.split_at(15).1.trim().parse::<u64>().ok())
+ // Make a HEAD request to get the content length for the progress bar
+ let head_response = client.head(&index_url).send().await?;
+ let content_length: u64 = head_response
+ .headers()
+ .get(reqwest::header::CONTENT_LENGTH)
+ .and_then(|ct_len| ct_len.to_str().ok())
+ .and_then(|ct_len| ct_len.parse().ok())
.unwrap_or(0);
- let body_start = headers_end + 4;
- let mut body_reader = std::io::Cursor::new(&response_buffer[body_start..]);
- let file_path = Path::new(cache_dir).join("INDEX.tar.gz");
-
+ // Create progress bar
let pb = if content_length > 0 {
let pb = ProgressBar::new(content_length);
- pb.set_style(ProgressStyle::default_bar()
- .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")?
- .progress_chars("#>-"));
+ pb.set_style(
+ ProgressStyle::default_bar()
+ .template("{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})")?
+ .progress_chars("#>-"),
+ );
pb
} else {
let pb = ProgressBar::new_spinner();
@@ -115,34 +97,41 @@ impl I2PPackage {
pb
};
- let mut file = tokio::fs::File::create(&file_path).await?;
-
- let chunk_size = 8192u64;
- let mut buffer = vec![0; chunk_size as usize];
+ // Send GET request and stream the response body
+ let response = client.get(&index_url).send().await?;
+ if !response.status().is_success() {
+ return Err(format!("HTTP Error: {}", response.status()).into());
+ }
- loop {
- let bytes_read_result = std::io::Read::read(&mut body_reader, &mut buffer);
- let bytes_read = match bytes_read_result {
- Ok(n) => n,
- Err(e) => return Err(e.into()),
- };
+ let mut stream = response.bytes_stream();
+ let file_path = Path::new(cache_dir).join("INDEX.tar.gz");
- if bytes_read == 0 {
- break;
- }
- file.write_all(&buffer[..bytes_read]).await?;
+ // Ensure cache_dir exists
+ tokio::fs::create_dir_all(cache_dir)
+ .await
+ .map_err(|e| format!("Failed to create cache dir: {}", e))?;
- pb.inc(bytes_read as u64);
+ let mut file = File::create(&file_path).await?;
+ let mut downloaded: u64 = 0;
- if bytes_read < chunk_size as usize {
- break;
- }
+ while let Some(chunk) = stream.try_next().await? {
+ file.write_all(&chunk).await?;
+ let chunk_len = chunk.len() as u64;
+ downloaded += chunk_len;
+ pb.set_position(downloaded);
}
pb.finish_with_message("INDEX.tar.gz download finished");
log::info!("Extracting INDEX.tar.gz to cache directory...");
- Package::extract_archive(&file_path.to_string_lossy())?;
+
+ let archive_file =
+ StdFile::open(&file_path).map_err(|e| format!("Failed to open archive: {}", e))?;
+ let gz_decoder = GzDecoder::new(archive_file);
+ let mut archive = Archive::new(gz_decoder);
+ archive
+ .unpack(cache_dir)
+ .map_err(|e| format!("Failed to unpack archive: {}", e))?;
let index_toml_path = Path::new(cache_dir).join("INDEX.toml");
if !index_toml_path.exists() {
@@ -151,13 +140,14 @@ impl I2PPackage {
return Ok(true);
}
- let index_content = std::fs::read_to_string(&index_toml_path)?;
- let index_data: IndexData = toml::from_str(&index_content)?;
+ let index_content = tokio::fs::read_to_string(&index_toml_path).await?;
+ log::debug!("Content of INDEX.toml:\n{}", index_content);
+
+ let index_data: IndexData = toml::from_str(&index_content)
+ .map_err(|e| format!("Failed to parse INDEX.toml: {}", e))?;
let mut package_map = HashMap::new();
for pkg in index_data.packages {
- // PKG_URL = /repo/package.mesk
- // FULL URL = "http://mesk.anthrill.i2p/i2p/repo/pkg.mesk"
let base_url = url::Url::parse(&self.config.repo.repo_url)?;
let full_url = base_url.join(&pkg.url)?;
let mut pkg_clone = pkg.clone();
@@ -178,25 +168,38 @@ impl I2PPackage {
/// An internal auxiliary function for downloading data and writing it to a file with a progress display.
///
/// # Arguments
- /// * `data' - Byte slice (&[u8]) with data to write.
- /// * `file_path' is the path to the file to write the data to.
- /// * `content_length' is the expected data size (for the progress bar). Maybe 0.
- /// * `description' - Description of the operation for the progress bar.
+ /// * `client` - The reqwest client to use for requests.
+ /// * `url` - The URL to download from.
+ /// * `file_path` - The path to the file to write the data to.
+ /// * `description` - Description of the operation for the progress bar.
///
/// # Errors
///
- /// Returns an error if there is a problem when creating or writing to a file.
- async fn download_and_write_file_with_progress(
- data: &[u8],
+ /// Returns an error if the request fails, if the response status is not successful, or if there's an issue while writing the file.
+ async fn download_file_with_progress(
+ client: &reqwest::Client,
+ url: &str,
file_path: &Path,
- content_length: u64,
description: &str,
) -> Result<(), Box<dyn std::error::Error>> {
+
+ let head_response = client.head(url).send().await?;
+ let content_length: u64 = head_response
+ .headers()
+ .get(reqwest::header::CONTENT_LENGTH)
+ .and_then(|ct_len| ct_len.to_str().ok())
+ .and_then(|ct_len| ct_len.parse().ok())
+ .unwrap_or(0);
let pb = if content_length > 0 {
let pb = ProgressBar::new(content_length);
- pb.set_style(ProgressStyle::default_bar()
- .template(&format!("{{spinner:.green}} [{{elapsed_precise}}] [{{bar:40.cyan/blue}}] {{bytes}}/{{total_bytes}} ({} {{eta}})", description))?
- .progress_chars("#>-"));
+ pb.set_style(
+ ProgressStyle::default_bar()
+ .template(&format!(
+ "{{spinner:.green}} [{{elapsed_precise}}] [{{bar:40.cyan/blue}}] {{bytes}}/{{total_bytes}} ({} {{eta}})",
+ description
+ ))?
+ .progress_chars("#>-"),
+ );
pb
} else {
let pb = ProgressBar::new_spinner();
@@ -206,117 +209,98 @@ impl I2PPackage {
))?);
pb
};
+ let response = client.get(url).send().await?;
+ if !response.status().is_success() {
+ return Err(format!("HTTP Error: {}", response.status()).into());
+ }
- let mut file = tokio::fs::File::create(&file_path).await?;
-
- let chunk_size = 8192usize;
- let mut pos = 0;
+ let mut stream = response.bytes_stream();
+ let mut file = File::create(&file_path).await?;
+ let mut downloaded: u64 = 0;
- while pos < data.len() {
- let end = std::cmp::min(pos + chunk_size, data.len());
- let chunk = &data[pos..end];
- file.write_all(chunk).await?;
- pb.inc(chunk.len() as u64);
- pos = end;
+ while let Some(chunk) = stream.try_next().await? {
+ file.write_all(&chunk).await?;
+ let chunk_len = chunk.len() as u64;
+ downloaded += chunk_len;
+ pb.set_position(downloaded);
}
pb.finish_with_message(format!("{} download finished", description));
Ok(())
}
- /// Fetches a specific package identified by `index` (likely the package name).
- /// Assumes `fetch_index` has been called and `self.index_packages` is populated.
- pub fn fetch_package_info(
- &self,
- package_name: &str,
- ) -> Result<&Package, Box<dyn std::error::Error>> {
- let packages = self
- .index_packages
- .as_ref()
- .ok_or("Index not loaded. Call fetch_index first.")?;
- let pkg_info = packages
- .get(package_name)
- .ok_or(format!("Package '{}' not found in index.", package_name))?;
- Ok(pkg_info)
- }
-
/// Fetches a specific package identified by `package_name`.
/// Assumes `fetch_index` has been called and `self.index_packages` is populated to get the URL.
- /// Downloads the package file (.mesk) to the cache directory.
+ /// Downloads the package file (.mesk) to the cache directory with a progress bar,
+ /// extracts it, and installs the package.
///
/// # Errors
///
/// Returns an error if the index is not loaded, the package is not found in the index,
- /// the package URL is invalid, the request fails, or if there's an issue writing the file.
- /// Why didn't I just abstract the download functionality into a separate function initially?
- /// Yes, I'm scared to work with fetch_index, even I don't often write such shit code.
+ /// the package URL is invalid, the request fails, extraction fails, or installation fails.
pub async fn fetch_package(
&self,
package_name: &str,
) -> Result<bool, Box<dyn std::error::Error>> {
let package_info = self.fetch_package_info(package_name)?;
- let url = url::Url::parse(&package_info.url)?;
- let host = url.host_str().ok_or("No host in package URL")?;
- let request_path = url.path();
+ let url = &package_info.url;
- let session_options = SessionOptions::default();
- let mut session = Session::new(session_options).await?;
- let mut stream = session.connect(host).await?;
+ let client = self.create_proxy_client()?;
- let request = format!(
- "GET {} HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n",
- request_path, host
- );
- stream.write_all(request.as_bytes()).await?;
-
- let mut reader = BufReader::new(stream);
- let mut response_buffer = Vec::new();
- reader.read_to_end(&mut response_buffer).await?;
-
- let headers_end = response_buffer
- .windows(4)
- .position(|window| window == b"\r\n\r\n")
- .ok_or("Invalid response: no headers end")?;
-
- let headers_str = std::str::from_utf8(&response_buffer[..headers_end])?;
- if !headers_str.starts_with("HTTP/1.1 200") && !headers_str.starts_with("HTTP/1.0 200") {
- return Err(format!(
- "HTTP Error: {}",
- headers_str.lines().next().unwrap_or("Unknown")
- )
- .into());
- }
-
- let content_length = headers_str
- .lines()
- .find(|line| line.to_lowercase().starts_with("content-length:"))
- .and_then(|line| line.split_at(15).1.trim().parse::<u64>().ok())
- .unwrap_or(0);
-
- let body_start = headers_end + 4;
- let body_bytes = &response_buffer[body_start..];
-
- let file_name = Path::new(request_path)
+ let file_name = Path::new(url)
.file_name()
- .ok_or("Could not determine filename from URL path")?
+ .ok_or("Could not determine filename from URL")?
.to_str()
.ok_or("Filename is not valid UTF-8")?;
let cache_dir = &self.config.paths.cache_dir;
let file_path = Path::new(cache_dir).join(file_name);
- Self::download_and_write_file_with_progress(
- body_bytes,
- &file_path,
- content_length,
- file_name,
- )
- .await?;
+ tokio::fs::create_dir_all(&cache_dir).await?;
+
+ Self::download_file_with_progress(&client, url, &file_path, file_name).await?;
log::info!(
"Package '{}' downloaded successfully to {:?}",
package_name,
file_path
);
- Ok(true)
+
+ // Extract the package archive
+ log::info!("Extracting package archive for '{}'...", package_name);
+ Package::extract_archive(&file_path.to_string_lossy())
+ .map_err(|e| format!("Failed to extract package archive: {}", e))?;
+
+ log::info!("Package archive extracted successfully.");
+
+ // 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);
+ Ok(true)
+ }
+ Err(e) => {
+ log::error!("Failed to install package '{}': {}", package_name, e);
+ Err(format!("Installation failed: {}", e).into())
+ }
+ }
+ }
+
+ /// Fetches a specific package identified by `index` (likely the package name).
+ /// Assumes `fetch_index` has been called and `self.index_packages` is populated.
+ pub fn fetch_package_info(
+ &self,
+ package_name: &str,
+ ) -> Result<&Package, Box<dyn std::error::Error>> {
+ let packages = self
+ .index_packages
+ .as_ref()
+ .ok_or("Index not loaded. Call fetch_index first.")?;
+ let pkg_info = packages
+ .get(package_name)
+ .ok_or(format!("Package '{}' not found in index.", package_name))?;
+ Ok(pkg_info)
}
}
diff --git a/src/pkgtoolkit/git_source.rs b/src/pkgtoolkit/git_source.rs
new file mode 100644
index 0000000..2f33c14
--- /dev/null
+++ b/src/pkgtoolkit/git_source.rs
@@ -0,0 +1,86 @@
+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;
+
+impl GitSource {
+ /// Clone a git repository to a local directory
+ pub fn clone_repo(git_url: &str, target_dir: &Path) -> Result<(), git2::Error> {
+ Repository::clone(git_url, target_dir)?;
+ Ok(())
+ }
+
+ /// 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()
+ .ok_or("Package does not have a git repository specified")?;
+
+ let source_dir = Path::new(&config.paths.cache_dir)
+ .join("sources")
+ .join(&package.name)
+ .join(&package.version);
+
+ fs::create_dir_all(&source_dir)?;
+
+ println!("Cloning {} from {}", 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);
+
+ 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
+ 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 package = index.packages.iter()
+ .find(|pkg| pkg.name == pkg_name)
+ .ok_or(format!("Package '{}' not found in index", pkg_name))?;
+
+ Self::get_package_source(package, config)
+ }
+}
diff --git a/src/pkgtoolkit/index.rs b/src/pkgtoolkit/index.rs
index 7b13533..78c37aa 100644
--- a/src/pkgtoolkit/index.rs
+++ b/src/pkgtoolkit/index.rs
@@ -95,6 +95,7 @@ impl IndexOperations for Package {
descr: Some(install_data.package.descr.unwrap_or_default()),
license: Some(install_data.package.license.unwrap_or_default()),
url: install_data.package.url,
+ git_repo: install_data.package.git_repo,
};
all_packages.push(pkg_for_index);
diff --git a/src/pkgtoolkit/mod.rs b/src/pkgtoolkit/mod.rs
index 2fc316a..1cadee3 100644
--- a/src/pkgtoolkit/mod.rs
+++ b/src/pkgtoolkit/mod.rs
@@ -1,6 +1,7 @@
// Core package toolkit modules
pub mod archive;
pub mod build;
+pub mod git_source;
pub mod index;
pub mod install;
pub mod types;
@@ -52,3 +53,7 @@ pub use install::InstallOperations;
// Index operations for package repository management
#[allow(unused_imports)]
pub use index::IndexOperations;
+
+// Git source operations for downloading package source code
+#[allow(unused_imports)]
+pub use git_source::GitSource;
diff --git a/src/pkgtoolkit/types.rs b/src/pkgtoolkit/types.rs
index 01a807a..83f47a3 100644
--- a/src/pkgtoolkit/types.rs
+++ b/src/pkgtoolkit/types.rs
@@ -17,6 +17,7 @@ pub struct Package {
pub descr: Option<String>,
pub license: Option<String>,
pub url: String,
+ pub git_repo: Option<String>,
}
#[derive(Deserialize, Debug, Clone)]
@@ -27,6 +28,8 @@ pub struct InstallMeta {
pub mode: String,
// Cancels the previous fields and installs them using the shell script
pub custom_script: Option<String>,
+ // Git repository URL for source code if needed
+ pub git_repo: Option<String>,
// pub files: Option<Vec<String>>,
}
diff --git a/tests/http_funcs.rs b/tests/http_funcs.rs
index 886da10..5a28a98 100644
--- a/tests/http_funcs.rs
+++ b/tests/http_funcs.rs
@@ -167,6 +167,7 @@ mod http_package_tests {
descr: Some("Test".to_string()),
license: Some("MIT".to_string()),
url: "http://example.com/repo/test-pkg.mesk".to_string(),
+ git_repo: None,
};
packages_map.insert("test-pkg".to_string(), pkg);
http_pkg.index_packages = Some(packages_map);
diff --git a/tests/i2p_functions.rs b/tests/i2p_functions.rs
index b07631a..6146e71 100644
--- a/tests/i2p_functions.rs
+++ b/tests/i2p_functions.rs
@@ -64,6 +64,7 @@ mod i2p_package_tests {
descr: Some("Test".to_string()),
license: Some("MIT".to_string()),
url: "http://example.i2p/repo/test-pkg.mesk".to_string(),
+ git_repo: None,
};
packages_map.insert("test-pkg".to_string(), pkg);
i2p_pkg.index_packages = Some(packages_map);
diff --git a/tests/pkgtoolkit_funcs.rs b/tests/pkgtoolkit_funcs.rs
index 9b23a17..bc9c22a 100644
--- a/tests/pkgtoolkit_funcs.rs
+++ b/tests/pkgtoolkit_funcs.rs
@@ -79,7 +79,10 @@ user = "root"
group = "root"
mode = "755"
"#;
- let install_path = temp_dir.path().join("INSTALL");
+ let pkg_name = "test-pkg"; // Match the name in install_content
+ let temp_pkg_dir = temp_dir.path().join(pkg_name);
+ fs::create_dir(&temp_pkg_dir).unwrap();
+ let install_path = temp_pkg_dir.join("INSTALL");
let mut install_file = fs::File::create(&install_path).unwrap();
install_file.write_all(install_content.as_bytes()).unwrap();
@@ -88,7 +91,7 @@ mode = "755"
let gz_encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
let mut tar_builder = tar::Builder::new(gz_encoder);
tar_builder
- .append_path_with_name(&install_path, "INSTALL")
+ .append_dir_all(pkg_name, &temp_pkg_dir)
.unwrap();
tar_builder.into_inner().unwrap().finish().unwrap();
@@ -110,14 +113,18 @@ mode = "755"
let temp_dir = TempDir::new().unwrap();
let _config = create_test_config(temp_dir.path().to_str().unwrap());
+ let pkg_name = "test_pkg";
+ let temp_pkg_dir = temp_dir.path().join(pkg_name);
+ fs::create_dir(&temp_pkg_dir).unwrap();
+ let dummy_path = temp_pkg_dir.join("dummy.txt");
+ fs::write(&dummy_path, "dummy").unwrap();
+
let archive_path = temp_dir.path().join("test_pkg_without_install.tar.gz");
let file = fs::File::create(&archive_path).unwrap();
let gz_encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
let mut tar_builder = tar::Builder::new(gz_encoder);
- let dummy_path = temp_dir.path().join("dummy.txt");
- fs::write(&dummy_path, "dummy").unwrap();
tar_builder
- .append_path_with_name(&dummy_path, "dummy.txt")
+ .append_dir_all(pkg_name, &temp_pkg_dir)
.unwrap();
tar_builder.into_inner().unwrap().finish().unwrap();
@@ -143,14 +150,18 @@ mode = "755"
let temp_dir = TempDir::new().unwrap();
let _config = create_test_config(temp_dir.path().to_str().unwrap());
- let install_path = temp_dir.path().join("INSTALL");
+ let pkg_name = "test_pkg";
+ let temp_pkg_dir = temp_dir.path().join(pkg_name);
+ fs::create_dir(&temp_pkg_dir).unwrap();
+ let install_path = temp_pkg_dir.join("INSTALL");
fs::write(&install_path, "").unwrap();
+
let archive_path = temp_dir.path().join("test_pkg_with_empty_install.tar.gz");
let file = fs::File::create(&archive_path).unwrap();
let gz_encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
let mut tar_builder = tar::Builder::new(gz_encoder);
tar_builder
- .append_path_with_name(&install_path, "INSTALL")
+ .append_dir_all(pkg_name, &temp_pkg_dir)
.unwrap();
tar_builder.into_inner().unwrap().finish().unwrap();
@@ -197,7 +208,10 @@ mode = "755"
wrong_arch
);
- let install_path = temp_dir.path().join("INSTALL");
+ let pkg_name = "test-pkg";
+ let temp_pkg_dir = temp_dir.path().join(pkg_name);
+ fs::create_dir(&temp_pkg_dir).unwrap();
+ let install_path = temp_pkg_dir.join("INSTALL");
let mut install_file = fs::File::create(&install_path).unwrap();
install_file.write_all(install_content.as_bytes()).unwrap();
@@ -206,7 +220,7 @@ mode = "755"
let gz_encoder = flate2::write::GzEncoder::new(file, flate2::Compression::default());
let mut tar_builder = tar::Builder::new(gz_encoder);
tar_builder
- .append_path_with_name(&install_path, "INSTALL")
+ .append_dir_all(pkg_name, &temp_pkg_dir)
.unwrap();
tar_builder.into_inner().unwrap().finish().unwrap();
diff --git a/tests/shared.rs b/tests/shared.rs
index 574e8cd..3b6ad70 100644
--- a/tests/shared.rs
+++ b/tests/shared.rs
@@ -1,6 +1,11 @@
use mesk::cfg::config::{Config, Log, Loglevel, Paths, Repo};
pub fn create_test_config(temp_dir_path: &str) -> Config {
+ // Create a unique subdirectory for this specific test to avoid parallel execution conflicts
+ let unique_cache_dir = format!("{}/{}", temp_dir_path, uuid::Uuid::new_v4());
+ let unique_build_dir = format!("{}/{}", unique_cache_dir, "build");
+ let unique_installed_db = format!("{}/{}", unique_cache_dir, "pkgdb");
+
let cfg: Config = Config {
repo: Repo {
repo_url: format!(r"http://mesk.anthrill.i2p/repo/{}", std::env::consts::ARCH),
@@ -8,15 +13,16 @@ pub fn create_test_config(temp_dir_path: &str) -> Config {
.into(),
auto_update: true,
destination: (String::from("mesk"), String::from("mesk")),
+ i2p_http_proxy_port: 4444,
},
log: Log {
log_file: String::from("mesk.log"),
log_level: Loglevel::Info,
},
paths: Paths {
- cache_dir: String::from(temp_dir_path),
- build_dir: String::from(format!("{}/build", String::from(temp_dir_path))),
- installed_db: String::from(format!("{}/pkgdb", String::from(temp_dir_path))),
+ cache_dir: String::from(&unique_cache_dir),
+ build_dir: String::from(&unique_build_dir),
+ installed_db: String::from(&unique_installed_db),
},
};