summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml9
-rw-r--r--Makefile151
-rw-r--r--\49
-rwxr-xr-xbuild-repo.sh201
-rw-r--r--src/main.rs79
-rw-r--r--src/router/mod.rs3
6 files changed, 460 insertions, 32 deletions
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 <namilsk@namilsk.tech>" ]
+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<dyn std::error::Error>> {
let cli: Cli = Cli::parse();
+ /*
// Parse config once at the beginning
let config = Config::parse()?;
@@ -101,6 +106,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Integrated router disabled");
None
};
+ */
let result = {
match &cli.command {
@@ -125,6 +131,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
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<dyn std::error::Error>> {
path,
args,
} => {
+ let config = Config::parse()?;
if *path {
println!("Installing package from local file: {}", pkgname);
@@ -235,17 +244,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
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<dyn std::error::Error>> {
}
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<dyn std::error::Error>> {
} => {
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<dyn std::error::Error>> {
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<dyn std::error::Error>> {
}
}
}
-
+ }
println!("Updating index from {}", config.repo.repo_url);
let mut i2p_client = I2PPackage::new(config);
@@ -404,13 +431,5 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
};
- // 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;