From 3271dfc977cc5841731594c308e19aae575c685d Mon Sep 17 00:00:00 2001 From: namilsk Date: Wed, 11 Feb 2026 11:38:48 +0300 Subject: Added build features which allows you remove integrated router, code refactoring coming soon --- Cargo.toml | 9 ++- Makefile | 151 ++++++++++++++++++++++++++++++++++++++++ "\\" | 49 +++++++++++++ build-repo.sh | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 79 +++++++++++++-------- src/router/mod.rs | 3 + 6 files changed, 460 insertions(+), 32 deletions(-) create mode 100644 Makefile create mode 100644 "\\" create mode 100755 build-repo.sh diff --git a/Cargo.toml b/Cargo.toml index 2748af4..9e90acc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,8 +15,8 @@ toml = { version = "0.9.8", features = ["serde"] } serde = { version = "1.0.228", features = ["derive"] } tokio = { version = "1.48.0", features = ["full"] } reqwest = { version = "0.12.24", features = ["stream"] } -emissary-util = { version = "0.3.0", features = ["tokio"] } -emissary-core = "0.3.0" +emissary-util = { version = "0.3.0", features = ["tokio"], optional = true } +emissary-core = { version = "0.3.0", optional = true } flate2 = "1.1.5" tar = "0.4.44" url = "2.5.7" @@ -37,6 +37,11 @@ tempfile = "3.23.0" tokio-test = "0.4.4" uuid = { version = "1.19.0", features = ["v4"] } +[feature] +minimal = [] +integrated-router = ["dep:emissary-util", "dep:emissary-core"] +default = ["minimal"] + [profile.release] strip = true lto = true diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c39a47c --- /dev/null +++ b/Makefile @@ -0,0 +1,151 @@ +# Makefile for Mesk Repository Management + +# Configuration +REPO_DIR ?= ./repo +PACKAGES_DIR ?= ./packages +MESK_BIN ?= ./target/release/mesk +BUILD_DIR ?= ./build + +# Detect if mesk is available in PATH +ifeq (, $(shell which mesk 2>/dev/null)) + ifneq (, $(wildcard $(MESK_BIN))) + MESK := $(MESK_BIN) + else + MESK := mesk_not_found + endif +else + MESK := $(shell which mesk) +endif + +.PHONY: all build clean validate info help + +# Default target +all: build + +# Build the repository +build: check-mesk + @echo "Building repository in $(REPO_DIR) from packages in $(PACKAGES_DIR)" + @mkdir -p $(REPO_DIR) $(PACKAGES_DIR) + @# Find all .mesk files and copy them to repo + @for pkg in $$(find $(PACKAGES_DIR) -name "*.mesk" 2>/dev/null); do \ + echo "Processing package: $$pkg"; \ + if [ -x "$(MESK)" ]; then \ + if $(MESK) validate "$$pkg" 2>/dev/null; then \ + cp "$$pkg" $(REPO_DIR)/; \ + echo " - Validated and copied $$pkg"; \ + else \ + echo " - ERROR: $$pkg failed validation"; \ + fi; \ + else \ + cp "$$pkg" $(REPO_DIR)/; \ + echo " - Copied $$pkg (validation skipped - mesk not available)"; \ + fi; \ + done + @echo "Generating repository index..." + @if [ -x "$(MESK)" ]; then \ + $(MESK) gen-index $(REPO_DIR); \ + echo "Repository index generated successfully"; \ + else \ + echo "ERROR: Mesk binary not found. Cannot generate index."; \ + exit 1; \ + fi + @echo "Repository built successfully in $(REPO_DIR)" + +# Check if mesk is available +check-mesk: + @if [ "$(MESK)" = "mesk_not_found" ]; then \ + echo "ERROR: mesk binary not found in PATH or $(MESK_BIN)"; \ + echo "Please build mesk first with: cargo build --release"; \ + exit 1; \ + fi + @echo "Using mesk binary: $(MESK)" + +# Validate all packages in the source directory +validate: check-mesk + @echo "Validating all packages in $(PACKAGES_DIR)" + @for pkg in $$(find $(PACKAGES_DIR) -name "*.mesk" 2>/dev/null); do \ + echo "Validating: $$pkg"; \ + if $(MESK) validate "$$pkg"; then \ + echo " OK: $$pkg is valid"; \ + else \ + echo " ERROR: $$pkg is invalid"; \ + fi; \ + done + +# Clean the repository directory +clean: + @echo "Cleaning repository directory: $(REPO_DIR)" + @rm -rf $(REPO_DIR)/* + @mkdir -p $(REPO_DIR) + @echo "Repository cleaned" + +# Clean everything including build artifacts +distclean: clean + @echo "Removing build artifacts" + @rm -rf target/ + +# Build mesk if needed +build-mesk: + @if [ ! -x "$(MESK_BIN)" ]; then \ + echo "Building mesk..."; \ + cargo build --release; \ + else \ + echo "Mesk already built"; \ + fi + +# Initialize a new repository structure +init: build-mesk + @echo "Initializing mesk repository structure..." + @mkdir -p $(PACKAGES_DIR) $(REPO_DIR) + @echo "Created directories: $(PACKAGES_DIR), $(REPO_DIR)" + @touch $(PACKAGES_DIR)/.gitkeep $(REPO_DIR)/.gitkeep + @echo "Repository structure initialized" + +# Show repository information +info: check-mesk + @echo "=== Repository Info ===" + @echo "Repository directory: $(REPO_DIR)" + @echo "Packages source: $(PACKAGES_DIR)" + @echo "Mesk binary: $(MESK)" + @echo "" + @echo "Package count: $$(find $(PACKAGES_DIR) -name '*.mesk' 2>/dev/null | wc -l)" + @if [ -f "$(REPO_DIR)/INDEX.toml" ]; then \ + echo "Index exists with packages:"; \ + grep -c "\[\[packages\]\]" $(REPO_DIR)/INDEX.toml 2>/dev/null || echo "0 packages"; \ + else \ + echo "Index does not exist"; \ + fi + @echo "" + +# Install packages to system (DANGEROUS - for testing only) +# install: build +# @echo "Installing repository packages (DANGEROUS - for testing only)" +# @for pkg in $$(find $(REPO_DIR) -name "*.mesk"); do \ +# echo "Installing: $$pkg"; \ +# $(MESK) install "$$pkg" -p; \ +# done + +help: + @echo "Makefile for Mesk Repository Management" + @echo "" + @echo "Available targets:" + @echo " all - Build repository (default)" + @echo " build - Build repository from packages in PACKAGES_DIR" + @echo " validate - Validate all packages in PACKAGES_DIR" + @echo " clean - Clean repository directory" + @echo " distclean - Clean everything including build artifacts" + @echo " build-mesk - Build mesk binary if not present" + @echo " init - Initialize repository structure" + @echo " info - Show repository information" + @echo " help - Show this help" + @echo "" + @echo "Variables:" + @echo " REPO_DIR - Repository directory (default: ./repo)" + @echo " PACKAGES_DIR - Directory with .mesk files (default: ./packages)" + @echo " MESK_BIN - Path to mesk binary (default: ./target/release/mesk)" + @echo "" + @echo "Examples:" + @echo " make init # Initialize repository structure" + @echo " make # Build repository with defaults" + @echo " make REPO_DIR=/tmp/myrepo # Build with custom repo directory" + @echo " make validate # Validate all packages" \ No newline at end of file diff --git "a/\\" "b/\\" new file mode 100644 index 0000000..9e90acc --- /dev/null +++ "b/\\" @@ -0,0 +1,49 @@ +[package] +name = "mesk" +version = "0.0.1" +edition = "2024" +license = "GPL-3.0" +authors = [ "namilsk " ] +description = "An i2p-based package manager developed by Anthrill project" +categories = ["command-line-utilities"] +repository = "https://codeberg.org/Anthrill/mesk.git" +# or git.community.i2p/Namilsk/mesk + +[dependencies] +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 = ["full"] } +reqwest = { version = "0.12.24", features = ["stream"] } +emissary-util = { version = "0.3.0", features = ["tokio"], optional = true } +emissary-core = { version = "0.3.0", optional = true } +flate2 = "1.1.5" +tar = "0.4.44" +url = "2.5.7" +indicatif = "0.18.3" +futures-util = "0.3.31" +num_cpus = "1.17.0" +git2 = "0.19.0" +gpgme = "0.11.0" +glob = "0.3.3" +lazy_static = "1.5.0" +log = "0.4.28" + +[dev-dependencies] +env_logger = "0.11.8" +log = "0.4.28" +mockito = "1.7.1" +tempfile = "3.23.0" +tokio-test = "0.4.4" +uuid = { version = "1.19.0", features = ["v4"] } + +[feature] +minimal = [] +integrated-router = ["dep:emissary-util", "dep:emissary-core"] +default = ["minimal"] + +[profile.release] +strip = true +lto = true +opt-level = 3 +codegen-units = 1 diff --git a/build-repo.sh b/build-repo.sh new file mode 100755 index 0000000..3a17d2e --- /dev/null +++ b/build-repo.sh @@ -0,0 +1,201 @@ +#!/usr/bin/env bash + +# Script to build and maintain a Mesk repository +# Automatically discovers, validates, and indexes .mesk packages + +set -e # Exit on any error + +# Configuration +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_DIR="${1:-$SCRIPT_DIR/repo}" # Use first argument or default to 'repo' +SOURCE_DIR="${2:-$SCRIPT_DIR/packages}" # Directory to scan for .mesk files +MESK_BIN="${MESK_BIN:-$SCRIPT_DIR/target/release/mesk}" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Logging functions +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# Check if mesk binary exists +if [ ! -f "$MESK_BIN" ]; then + log_error "Mesk binary not found at: $MESK_BIN" + log_info "Looking for mesk in PATH..." + MESK_BIN=$(which mesk 2>/dev/null || echo "") + if [ -z "$MESK_BIN" ]; then + log_error "Mesk binary not found in PATH either." + log_info "Please build mesk first with: cargo build --release" + exit 1 + else + log_info "Found mesk at: $MESK_BIN" + fi +else + log_info "Using mesk binary: $MESK_BIN" +fi + +# Create directories if they don't exist +mkdir -p "$REPO_DIR" +mkdir -p "$SOURCE_DIR" + +# Function to validate a .mesk package +validate_package() { + local package="$1" + log_info "Validating package: $(basename "$package")" + + if "$MESK_BIN" validate "$package" >/dev/null 2>&1; then + log_success "Package $(basename "$package") is valid" + return 0 + else + log_error "Package $(basename "$package") is invalid" + return 1 + fi +} + +# Main function to build repository +build_repository() { + log_info "Starting repository build process..." + log_info "Repository directory: $REPO_DIR" + log_info "Source directory: $SOURCE_DIR" + + # Find all .mesk files in source directory (recursively) + local package_files=() + while IFS= read -r -d '' file; do + package_files+=("$file") + done < <(find "$SOURCE_DIR" -name "*.mesk" -type f -print0) + + if [ ${#package_files[@]} -eq 0 ]; then + log_warning "No .mesk packages found in $SOURCE_DIR" + log_info "Place your .mesk files in the source directory and run again" + + # Still generate index even if no packages + log_info "Generating empty repository index..." + if "$MESK_BIN" gen-index "$REPO_DIR"; then + log_success "Empty repository index generated" + else + log_error "Failed to generate empty repository index" + exit 1 + fi + + return 0 + fi + + log_info "Found ${#package_files[@]} .mesk package(s) to process" + + # Validate packages first + local valid_packages=() + local invalid_count=0 + + for package in "${package_files[@]}"; do + if validate_package "$package"; then + valid_packages+=("$package") + else + ((invalid_count++)) + fi + done + + if [ $invalid_count -ne 0 ]; then + log_warning "$invalid_count package(s) failed validation" + log_info "Only processing valid packages" + fi + + if [ ${#valid_packages[@]} -eq 0 ]; then + log_error "No valid packages to process" + log_info "Repository build failed" + exit 1 + fi + + # Copy valid packages to repository directory + log_info "Copying valid packages to repository..." + for package in "${valid_packages[@]}"; do + local package_name=$(basename "$package") + local dest_path="$REPO_DIR/$package_name" + + # Compare timestamps to avoid unnecessary copies + if [ ! -f "$dest_path" ] || [ "$package" -nt "$dest_path" ]; then + cp "$package" "$REPO_DIR/" + log_info "Copied $(basename "$package") to repository" + else + log_info "Package $(basename "$package") already exists and is up to date" + fi + done + + # Generate repository index + log_info "Generating repository index..." + if "$MESK_BIN" gen-index "$REPO_DIR"; then + log_success "Repository index generated successfully" + else + log_error "Failed to generate repository index" + exit 1 + fi + + # Create/update repository info file + local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + cat > "$REPO_DIR/REPO_INFO" << EOF +# Repository Information +Generated At: $timestamp +Total Packages: ${#valid_packages[@]} +Invalid Packages: $invalid_count +Source Directory: $SOURCE_DIR +Repository Directory: $REPO_DIR + +Valid Packages: +EOF + + for package in "${valid_packages[@]}"; do + echo "- $(basename "$package")" >> "$REPO_DIR/REPO_INFO" + done + + log_success "Repository build completed successfully!" + log_info "Repository location: $REPO_DIR" + log_info "Packages processed: ${#valid_packages[@]}" + if [ $invalid_count -ne 0 ]; then + log_info "Invalid packages: $invalid_count" + fi +} + +# Function to show help +show_help() { + echo "Usage: $0 [REPO_DIR] [SOURCE_DIR]" + echo "" + echo "Automatically builds a Mesk repository from .mesk packages." + echo "" + echo "Arguments:" + echo " REPO_DIR Directory to create/build repository (default: ./repo)" + echo " SOURCE_DIR Directory containing .mesk files to add (default: ./packages)" + echo "" + echo "Environment:" + echo " MESK_BIN Path to mesk binary (default: ./target/release/mesk or in PATH)" + echo "" + echo "Example:" + echo " $0 /path/to/repo /path/to/packages" + echo " $0" # will use defaults +} + +# Parse command line options +case "${1:-}" in + -h|--help) + show_help + exit 0 + ;; + *) + build_repository + ;; +esac \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 0f6b6c6..88d9240 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,14 +6,18 @@ mod router; use crate::cfg::config::Config; use crate::net::{http_package::HTTPPackage, i2p_package::I2PPackage}; -use crate::pkgtoolkit::Package; 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 crate::pkgtoolkit::Package; + +#[cfg(feature = "integrated-router")] use crate::router::manager::RouterManager; + use clap::{Args, Parser, Subcommand}; +use mesk::cfg::config; use std::io::Write; use std::path::Path; @@ -81,6 +85,7 @@ struct RemoteInstallArgs { async fn main() -> Result<(), Box> { let cli: Cli = Cli::parse(); + /* // Parse config once at the beginning let config = Config::parse()?; @@ -101,6 +106,7 @@ async fn main() -> Result<(), Box> { println!("Integrated router disabled"); None }; + */ let result = { match &cli.command { @@ -125,6 +131,8 @@ async fn main() -> Result<(), Box> { Commands::Build { pkgname } => { println!("Building package from archive: {}", pkgname); + let config = Config::parse()?; + let path = Path::new(&pkgname); if !path.exists() { return Err(std::io::Error::other(format!( @@ -192,6 +200,7 @@ async fn main() -> Result<(), Box> { path, args, } => { + let config = Config::parse()?; if *path { println!("Installing package from local file: {}", pkgname); @@ -235,17 +244,18 @@ async fn main() -> Result<(), Box> { pkg.install()?; println!("Package '{}' installed successfully.", pkg.name); } else { - // Initialize router if it's needed for I2P connections and is enabled - if !args.http && config.router.integrated_router { - // Wait for router to be fully started - if let Some(ref manager) = router_manager { - println!("Waiting for router to be ready..."); - tokio::time::sleep(std::time::Duration::from_secs(3)).await; // Give router time to start - if !manager.is_running() { - eprintln!( + #[cfg(feature = "integrated-router")] + { + if !args.http && config.router.integrated_router { + if let Some(ref manager) = router_manager { + println!("Waiting for router to be ready..."); + tokio::time::sleep(std::time::Duration::from_secs(3)).await; + if !manager.is_running() { + eprintln!( "Router is not running, cannot proceed with I2P installation" ); - return Err(std::io::Error::other("Router not running").into()); + return Err(std::io::Error::other("Router not running").into()); + } } } } @@ -308,20 +318,34 @@ async fn main() -> Result<(), Box> { } Commands::GetSource { pkgname } => { // Initialize router for I2P connections if enabled - if config.router.integrated_router { - if let Some(ref manager) = router_manager { - println!("Waiting for router to be ready..."); - tokio::time::sleep(std::time::Duration::from_secs(2)).await; - if !manager.is_running() { - eprintln!("Router is not running, cannot proceed with I2P operation"); - return Err(std::io::Error::other("Router not running").into()); + let config = Config::parse()?; + #[cfg(feature = "integrated-router")] + { + if config.router.integrated_router { + if let Some(ref manager) = router_manager { + println!("Waiting for router to be ready..."); + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + if !manager.is_running() { + eprintln!( + "Router is not running, cannot proceed with I2P operation" + ); + return Err(std::io::Error::other("Router not running").into()); + } } } + + let source_path = GitSource::get_source_by_name(pkgname, &config)?; } + + #[cfg(feature = "minimal")] + { + let package = I2PPackage::new(); + let package_fetch = package.fetch_package(pkgname); + } + println!("Getting source of {}", pkgname); - let source_path = GitSource::get_source_by_name(pkgname, &config)?; - println!("Source code successfully downloaded to: {}", source_path); + println!("Source code successfully downloaded to cachedir"); return Ok(()); } Commands::DefaultConfig { @@ -332,7 +356,7 @@ async fn main() -> Result<(), Box> { } => { println!("Generating config file"); if cachedir.is_none() && repo.is_none() && buildir.is_none() { - let config = Config::default().unwrap(); + let config = Config::default()?; println!("---- Start of generated config ----"); println!("{}", config); @@ -363,7 +387,10 @@ async fn main() -> Result<(), Box> { return Ok(()); } Commands::Update => { - // Initialize router for I2P connections if enabled + let config = Config::parse()?; + + #[cfg(feature = "integrated-router")] + { if config.router.integrated_router { if let Some(ref manager) = router_manager { println!("Waiting for router to be ready..."); @@ -374,7 +401,7 @@ async fn main() -> Result<(), Box> { } } } - + } println!("Updating index from {}", config.repo.repo_url); let mut i2p_client = I2PPackage::new(config); @@ -404,13 +431,5 @@ async fn main() -> Result<(), Box> { } }; - // Shutdown router if it was initialized - if let Some(ref manager) = router_manager { - println!("Shutting down integrated router..."); - if let Err(e) = manager.stop().await { - eprintln!("Error stopping router: {}", e); - } - } - result } diff --git a/src/router/mod.rs b/src/router/mod.rs index 91da2e5..6426c2e 100644 --- a/src/router/mod.rs +++ b/src/router/mod.rs @@ -1,2 +1,5 @@ + +#[cfg(feature = "integrated-router")] pub mod manager; +#[cfg(feature = "integrated-router")] pub mod router; -- cgit v1.2.3