summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.codeberg/actions.yml96
-rw-r--r--src/cfg/config.rs63
-rw-r--r--src/cfg/mod.rs2
-rw-r--r--src/main.rs131
-rw-r--r--src/net/http_packages.rs49
-rw-r--r--src/net/i2p_package.rs121
-rw-r--r--src/net/mod.rs4
-rw-r--r--src/pkgtoolkit/mod.rs2
-rw-r--r--src/pkgtoolkit/pkgtools.rs385
9 files changed, 526 insertions, 327 deletions
diff --git a/.codeberg/actions.yml b/.codeberg/actions.yml
new file mode 100644
index 0000000..85f4d2d
--- /dev/null
+++ b/.codeberg/actions.yml
@@ -0,0 +1,96 @@
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+
+jobs:
+
+ test-and-check:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ rust: [ "stable", "beta" ]
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Install Rust (${{ matrix.rust }})
+ uses: dtolnay/rust-toolchain@stable
+ with:
+ toolchain: ${{ matrix.rust }}
+ components: rustfmt, clippy
+
+ - name: Cache Cargo registry and index
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/.cargo/registry
+ ~/.cargo/git
+ target
+ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+
+ - name: Check formatting
+ run: cargo fmt --all -- --check
+
+ # - name: Lint with clippy
+ # run: cargo clippy -- -D warnings
+
+ - name: Build
+ run: cargo build --verbose
+
+ - name: Run tests
+ run: cargo test --verbose
+
+ build-cross:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ target: [ x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu ]
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Install Rust stable
+ uses: dtolnay/rust-toolchain@stable
+ with:
+ toolchain: stable
+ targets: ${{ matrix.target }}
+
+ - name: Cache Cargo registry and index
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/.cargo/registry
+ ~/.cargo/git
+ target
+ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-target-${{ matrix.target }}
+
+ - name: Install cross-compilation tools
+ if: matrix.target == 'aarch64-unknown-linux-gnu'
+ run: |
+ sudo apt update
+ sudo apt install -y gcc-aarch64-linux-gnu
+
+ - name: Set up environment for cross-compilation
+ run: |
+ echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
+ if: matrix.target == 'aarch64-unknown-linux-gnu'
+
+ - name: Build for ${{ matrix.target }}
+ run: cargo build --target ${{ matrix.target }} --release --verbose
+
+# release:
+# runs-on: ubuntu-latest
+# needs: [test-and-check, build-cross] # Запускается только если предыдущие задания прошли успешно
+# if: startsWith(github.ref, 'refs/tags/') # Запускается только при создании тега
+# steps:
+# - name: Checkout code
+# uses: actions/checkout@v4
+# - name: Install Rust stable
+# uses: dtolnay/rust-toolchain@stable
+# with:
+# toolchain: stable
+# - name: Build release
+# run: cargo build --release --verbose
diff --git a/src/cfg/config.rs b/src/cfg/config.rs
index ffccbad..cf6188e 100644
--- a/src/cfg/config.rs
+++ b/src/cfg/config.rs
@@ -1,5 +1,5 @@
-use std::fs;
use serde::{Deserialize, Serialize};
+use std::fs;
use toml;
#[derive(Debug, Deserialize, Serialize)]
@@ -9,16 +9,15 @@ pub enum Loglevel {
Debug,
Info,
Warn,
- Error
+ Error,
}
-
/// `mesk.toml` configuration fields here
#[derive(Deserialize, Debug, Serialize)]
pub struct Config {
- pub repo: Repo,
- pub log: Log,
- pub paths: Paths,
+ pub repo: Repo,
+ pub log: Log,
+ pub paths: Paths,
}
#[derive(Deserialize, Debug, Serialize)]
@@ -29,29 +28,28 @@ pub struct Log {
pub log_level: Loglevel,
}
-// Rename needed for editing mesk.toml file fields but dont touch code.
+// Rename needed for editing mesk.toml file fields but dont touch code.
#[derive(Deserialize, Debug, Serialize)]
pub struct Repo {
- #[serde(rename = "repo_url")]
+ #[serde(rename = "repo_url")]
pub repo_url: String,
- #[serde(rename = "auto_update")]
+ #[serde(rename = "auto_update")]
pub auto_update: bool,
#[serde(rename = "destination")]
pub destination: (String, String),
-// #[serde(rename = "arch")]
-// pub arch = arch;
+ // #[serde(rename = "arch")]
+ // pub arch = arch;
}
#[derive(Deserialize, Debug, Serialize)]
pub struct Paths {
- #[serde(rename = "cache_dir")]
+ #[serde(rename = "cache_dir")]
pub cache_dir: String,
- #[serde(rename = "build_dir")]
+ #[serde(rename = "build_dir")]
pub build_dir: String,
}
impl Config {
-
/// Parse the /etc/mesk.toml file and return the Config object.
///
/// This function reads the /etc/mesk.toml file, parses it and returns the Config object.
@@ -61,17 +59,15 @@ impl Config {
Ok(result)
}
-
/// Return the default configuration as a toml string.
///
/// This function returns the default configuration as a toml string.
pub fn default() -> Result<String, toml::ser::Error> {
let default: Config = Config {
repo: Repo {
- repo_url: format!("https://mesk.anthrill.i2p/repo/{}/",
- std::env::consts::ARCH),
+ repo_url: format!("https://mesk.anthrill.i2p/repo/{}/", std::env::consts::ARCH),
auto_update: true,
- destination: (String::from("mesk"), String::from("mesk")),
+ destination: (String::from("mesk"), String::from("mesk")),
// 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
},
@@ -89,25 +85,40 @@ impl Config {
Ok(toml_str)
}
- pub fn generate(repo: &Option<String>, cachedir: &Option<String>, buildir: &Option<String>) -> Result<String, toml::ser::Error> {
+ pub fn generate(
+ repo: &Option<String>,
+ cachedir: &Option<String>,
+ buildir: &Option<String>,
+ ) -> Result<String, toml::ser::Error> {
let generator: Config = Config {
repo: Repo {
- repo_url: if repo.is_none() { format!("https://mesk.anthrill.i2p/repo/{}/", std::env::consts::ARCH ) } else { repo.clone().unwrap() },
+ repo_url: if repo.is_none() {
+ format!("https://mesk.anthrill.i2p/repo/{}/", std::env::consts::ARCH)
+ } else {
+ repo.clone().unwrap()
+ },
auto_update: true,
- destination: (String::from("mesk"), String::from("mesk")),
+ destination: (String::from("mesk"), String::from("mesk")),
},
log: Log {
log_file: String::from("/var/log/mesk.log"),
log_level: Loglevel::Info,
},
paths: Paths {
- cache_dir: if cachedir.is_none() { String::from("/var/cache/mesk") } else { cachedir.clone().unwrap() },
- build_dir: if buildir.is_none() { String::from("/var/cache/mesk/build") } else { buildir.clone().unwrap() },
-
- /*
+ cache_dir: if cachedir.is_none() {
+ String::from("/var/cache/mesk")
+ } else {
+ cachedir.clone().unwrap()
+ },
+ build_dir: if buildir.is_none() {
+ String::from("/var/cache/mesk/build")
+ } else {
+ buildir.clone().unwrap()
+ },
+ /*
FIXME: I can leave this parameter, but I think it would be better to make the build
path in the /var/cache/mesk/$pkgname-$pkgver/BUILD/
- */
+ */
},
};
Ok(toml::to_string(&generator)?)
diff --git a/src/cfg/mod.rs b/src/cfg/mod.rs
index b1ca24c..ef68c36 100644
--- a/src/cfg/mod.rs
+++ b/src/cfg/mod.rs
@@ -1 +1 @@
-pub mod config; \ No newline at end of file
+pub mod config;
diff --git a/src/main.rs b/src/main.rs
index 463bd24..e295722 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,15 +3,15 @@ mod net;
mod pkgtoolkit;
use crate::cfg::config::Config;
+use crate::net::i2p_package::I2PPackage;
#[allow(unused_imports)]
use crate::pkgtoolkit::pkgtools::Package;
-use crate::net::i2p_package::I2PPackage;
-use clap::{Args, Command, Parser, Subcommand};
+use clap::{Args, Parser, Subcommand};
+use std::fs::File;
+use std::fs::create_dir_all;
use std::io::Write;
use std::path::Path;
-use std::fs::create_dir_all;
-use std::fs::File;
use tokio;
#[derive(Parser)]
@@ -23,54 +23,43 @@ struct Cli {
#[derive(Subcommand)]
enum Commands {
#[command(about = "Validate .mesk package archive")]
- Validate {
- path: String,
- },
+ Validate { path: String },
#[command(about = "Update all repositories index")]
- Update,
+ Update,
#[command(about = "Upgrade all packages or a specific package")]
- Upgrade {
- pkgname: Option<String>,
- },
+ Upgrade { pkgname: Option<String> },
#[command(about = "Build package from .mesk ")]
- Build{
- pkgname: String,
- },
+ Build { pkgname: String },
#[command(about = "Install package from remote or local sources")]
- Install{
- pkgname: String,
+ Install {
+ pkgname: String,
source: Option<String>,
#[command(flatten)]
- args: RemoteInstallArgs
-
+ args: RemoteInstallArgs,
},
#[command(about = "Uninstall package")]
- Uninstall{
- pkgname: String,
- },
+ Uninstall { pkgname: String },
#[command(about = "Get package source")]
- GetSource{
- pkgname: String
- },
+ GetSource { pkgname: String },
#[command(about = "Generator of config file")]
DefaultConfig {
- repo: Option<String>,
+ repo: Option<String>,
cachedir: Option<String>,
- buildir: Option<String>,
+ buildir: Option<String>,
},
#[command(about = "Maintaners, links, developers and more info")]
- Credits
+ Credits,
}
-#[derive(Args, Clone)]
+#[derive(Args, Clone)]
#[command(about = "Remote install arguments")]
-struct RemoteInstallArgs {
- #[arg(short = 'b', long = "bin" )]
- bin: bool,
- #[arg(short = 'h', long = "http" )]
- http: bool,
- #[arg(short = 'c', long = "clean" )]
- clean: bool
+struct RemoteInstallArgs {
+ #[arg(short = 'b', long = "bin")]
+ bin: bool,
+ #[arg(short = 'h', long = "http")]
+ http: bool,
+ #[arg(short = 'c', long = "clean")]
+ clean: bool,
}
#[tokio::main]
@@ -78,82 +67,90 @@ async fn main() -> Result<(), std::io::Error> {
let cli: Cli = Cli::parse();
// Plug in these functions only until the backend is ready for testing (Aplha versions)
- // It is necessary for me to understand the I/O model of the future mesk.
+ // It is necessary for me to understand the I/O model of the future mesk.
match &cli.command {
Commands::Validate { path } => {
println!("Validating {}", path);
- return Ok(())
- },
+ return Ok(());
+ }
Commands::Build { pkgname } => {
println!("Building {}", pkgname);
- return Ok(())
- },
- Commands::Install { pkgname, source, args} => {
+ return Ok(());
+ }
+
+ Commands::Install {
+ pkgname,
+ source,
+ args,
+ } => {
println!("Installing {}", pkgname);
- return Ok(())
- },
+ return Ok(());
+ }
Commands::Uninstall { pkgname } => {
println!("Uninstalling {}", pkgname);
- return Ok(())
- },
+ return Ok(());
+ }
Commands::GetSource { pkgname } => {
println!("Getting source of {}", pkgname);
- return Ok(())
- },
- Commands::DefaultConfig { repo, cachedir, buildir } => {
+ return Ok(());
+ }
+ Commands::DefaultConfig {
+ repo,
+ cachedir,
+ buildir,
+ } => {
println!("Generating config file");
if cachedir.is_none() && repo.is_none() && buildir.is_none() {
let config = Config::default().unwrap();
println!("---- Start of generated config ----");
- println!("{}", config);
+ println!("{}", config);
println!("---- End of generated config ----");
-
+
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(config.as_bytes())?;
println!("Config tool ending work.");
-
} else {
- let config = Config::generate(repo, cachedir, buildir).unwrap();
+ let config = Config::generate(repo, cachedir, buildir).unwrap();
println!("---- Start of generated config ----");
- println!("{:?}", config);
+ println!("{:?}", config);
println!("---- End of generated config ----");
-
+
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())?;
println!("Config tool ending work.");
-
}
- return Ok(())
- },
+ return Ok(());
+ }
Commands::Update => {
let config = Config::parse().unwrap();
println!("Updating index from {}", config.repo.repo_url);
let mut i2pd = I2PPackage::new(config);
- let _index= I2PPackage::fetch_index(&mut i2pd).await?;
+ let _index = I2PPackage::fetch_index(&mut i2pd).await?;
println!("Index updated");
- return Ok(())
- },
+ return Ok(());
+ }
Commands::Upgrade { pkgname } => {
println!("Upgrading all packages");
- return Ok(())
- },
+ return Ok(());
+ }
Commands::Credits => {
- println!("CREATED BY: Asya and Namilsk as part of the Anthrill independent Global network distribution project");
+ println!(
+ "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");
}
}
Ok(())
-
-} \ No newline at end of file
+}
diff --git a/src/net/http_packages.rs b/src/net/http_packages.rs
index 1e3c6ad..fe1833d 100644
--- a/src/net/http_packages.rs
+++ b/src/net/http_packages.rs
@@ -1,19 +1,21 @@
+use crate::cfg::config::Config;
use reqwest;
use std::fs::File;
use std::io::Write;
use std::path::Path;
-use crate::cfg::config::Config;
+#[allow(dead_code)]
pub struct HTTPPackage {
config: Config,
}
+#[allow(dead_code)]
impl HTTPPackage {
/// Creates a new Downloader object with the given configuration.
///
/// # Arguments
///
- /// * `config` - The full mesk
+ /// * `config` - The full mesk
///
/// # Returns
///
@@ -33,12 +35,11 @@ impl HTTPPackage {
/// # Returns
///
/// A new Config object with the parsed configuration. If there's an error while reading or parsing the file, returns an Err containing a Box<dyn std::error::Error>.
- pub fn parse_config(config_path: &str) -> Result<Config, Box<dyn std::error::Error>> {
+ pub fn parse_config() -> Result<Config, Box<dyn std::error::Error>> {
let config = Config::parse()?;
Ok(config)
}
-
/// Downloads the INDEX.tar.gz file from the configured repository
/// and stores it in the configured cache directory.
///
@@ -58,11 +59,9 @@ impl HTTPPackage {
let client = reqwest::Client::new();
- let response = client
- .get(&index_url)
- .send()
- .await
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Request failed: {}", e)))?;
+ let response = client.get(&index_url).send().await.map_err(|e| {
+ std::io::Error::new(std::io::ErrorKind::Other, format!("Request failed: {}", e))
+ })?;
if !response.status().is_success() {
return Err(std::io::Error::new(
@@ -74,19 +73,35 @@ impl HTTPPackage {
let index_data = response
.bytes()
.await
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to read response body: {}", e)))?
+ .map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to read response body: {}", e),
+ )
+ })?
.to_vec();
let file_path = Path::new(cache_dir).join("INDEX.tar.gz");
- let mut file = File::create(&file_path)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to create file: {}", e)))?;
- file.write_all(&index_data)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to write file: {}", e)))?;
- file.flush()
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to flush file: {}", e)))?;
+ let mut file = File::create(&file_path).map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to create file: {}", e),
+ )
+ })?;
+ file.write_all(&index_data).map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to write file: {}", e),
+ )
+ })?;
+ file.flush().map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to flush file: {}", e),
+ )
+ })?;
Ok(true)
}
}
-
diff --git a/src/net/i2p_package.rs b/src/net/i2p_package.rs
index 2776eea..d149454 100644
--- a/src/net/i2p_package.rs
+++ b/src/net/i2p_package.rs
@@ -1,33 +1,26 @@
-
-use crate::cfg::config::Config;
+use crate::cfg::config::Config;
use tokio;
-/*
+/*
use emissary_core::runtime::{
- AsyncRead,
- AsyncWrite,
+ AsyncRead,
+ AsyncWrite,
};
*/
-use std::{fs::File,
- path::Path,
- io::Write};
-// use emissary_core::Profile;
+use std::{fs::File, io::Write, path::Path};
+// use emissary_core::Profile;
// use emissary_core::i2np::Message;
-use tokio::io::{AsyncReadExt,
- AsyncWriteExt,
- BufReader};
+use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader};
+use url;
+use yosemite::Session;
use yosemite::SessionOptions;
-use yosemite::{Session, style::Stream};
-use url;
pub struct I2PPackage {
config: Config,
-
}
-
impl I2PPackage {
/// Creates a new I2P object with the given configuration.
///
@@ -35,13 +28,9 @@ impl I2PPackage {
///
/// 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(config: Config) -> Self {
- I2PPackage{
-
- config: config,
- }
+ I2PPackage { config: config }
}
-
/// Downloads the INDEX.tar.gz file from the configured repository
/// and stores it in the configured cache directory.
///
@@ -52,11 +41,13 @@ impl I2PPackage {
let repo_url_str = &self.config.repo.repo_url;
let cache_dir = &self.config.paths.cache_dir;
- let url = url::Url::parse(repo_url_str)
- .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidInput, "Invalid repo URL"))?;
+ let url = url::Url::parse(repo_url_str).map_err(|_| {
+ std::io::Error::new(std::io::ErrorKind::InvalidInput, "Invalid repo URL")
+ })?;
- let host = url.host_str()
- .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::InvalidInput, "No host in URL"))?;
+ let host = url.host_str().ok_or_else(|| {
+ std::io::Error::new(std::io::ErrorKind::InvalidInput, "No host in URL")
+ })?;
let request_path = url.path();
let request_path = if request_path.ends_with(".tar.gz") {
@@ -65,55 +56,91 @@ impl I2PPackage {
format!("{}/INDEX.tar.gz", request_path.trim_end_matches('/'))
};
- let sam_host = "127.0.0.1";
- let sam_port = 7656;
let session_options = SessionOptions::default();
- let mut session = Session::new(session_options).await
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to create SAM session: {}", e)))?;
+ let mut session = Session::new(session_options).await.map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to create SAM session: {}", e),
+ )
+ })?;
- let mut stream = session.connect(host).await
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::ConnectionAborted, format!("Failed to connect: {}", e)))?;
+ let mut stream = session.connect(host).await.map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::ConnectionAborted,
+ format!("Failed to connect: {}", e),
+ )
+ })?;
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
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to write request: {}", e)))?;
+ stream.write_all(request.as_bytes()).await.map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to write request: {}", e),
+ )
+ })?;
let mut reader = BufReader::new(stream);
let mut response_buffer = Vec::new();
- reader.read_to_end(&mut response_buffer).await
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to read response: {}", e)))?;
-
+ reader
+ .read_to_end(&mut response_buffer)
+ .await
+ .map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to read response: {}", e),
+ )
+ })?;
let headers_end = response_buffer
.windows(4)
.position(|window| window == b"\r\n\r\n")
- .ok_or_else(|| std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid response: no headers end"))?;
+ .ok_or_else(|| {
+ std::io::Error::new(
+ std::io::ErrorKind::InvalidData,
+ "Invalid response: no headers end",
+ )
+ })?;
- let headers_str = std::str::from_utf8(&response_buffer[..headers_end])
- .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid header encoding"))?;
+ let headers_str = std::str::from_utf8(&response_buffer[..headers_end]).map_err(|_| {
+ std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid header encoding")
+ })?;
if !headers_str.starts_with("HTTP/1.1 200") && !headers_str.starts_with("HTTP/1.0 200") {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
- format!("HTTP Error: {}", headers_str.lines().next().unwrap_or("Unknown")),
+ format!(
+ "HTTP Error: {}",
+ headers_str.lines().next().unwrap_or("Unknown")
+ ),
));
}
let body_start = headers_end + 4;
let file_path = Path::new(cache_dir).join("INDEX.tar.gz");
-
- let mut file = File::create(&file_path)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to create file: {}", e)))?;
+ let mut file = File::create(&file_path).map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to create file: {}", e),
+ )
+ })?;
file.write_all(&response_buffer[body_start..])
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to write file: {}", e)))?;
- file.flush()
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to flush file: {}", e)))?;
+ .map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to write file: {}", e),
+ )
+ })?;
+ file.flush().map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to flush file: {}", e),
+ )
+ })?;
Ok(true)
}
diff --git a/src/net/mod.rs b/src/net/mod.rs
index 54f5e7f..5a5aca0 100644
--- a/src/net/mod.rs
+++ b/src/net/mod.rs
@@ -1,2 +1,2 @@
-pub mod i2p_package;
-pub mod http_packages; \ No newline at end of file
+pub mod http_packages;
+pub mod i2p_package;
diff --git a/src/pkgtoolkit/mod.rs b/src/pkgtoolkit/mod.rs
index 4741892..63c952a 100644
--- a/src/pkgtoolkit/mod.rs
+++ b/src/pkgtoolkit/mod.rs
@@ -1 +1 @@
-pub mod pkgtools; \ No newline at end of file
+pub mod pkgtools;
diff --git a/src/pkgtoolkit/pkgtools.rs b/src/pkgtoolkit/pkgtools.rs
index cfd3d59..6c37595 100644
--- a/src/pkgtoolkit/pkgtools.rs
+++ b/src/pkgtoolkit/pkgtools.rs
@@ -2,23 +2,23 @@
use crate::cfg::config::Config;
use std::{
- fs::{self, File, create_dir_all},
+ fs::{self, File, create_dir_all},
io,
- path::Path,
- process::Command,
- str,
- os::unix::fs::PermissionsExt};
+ os::unix::fs::PermissionsExt,
+ path::Path,
+ process::Command,
+ str,
+};
+
+// use emissary_core::i2np::tunnel::build;
- use emissary_core::i2np::tunnel::build;
- // use emissary_core::i2np::tunnel::build;
use flate2::read::GzDecoder;
use serde::{Deserialize, Serialize};
use tar::Archive;
-use toml;
-use cc;
+use toml;
#[derive(Serialize, Debug, Deserialize, Clone)]
-pub enum archs {
+pub enum Archs {
X86_64,
Aarch64,
X86,
@@ -28,9 +28,9 @@ pub enum archs {
#[derive(Serialize, Debug, Deserialize, Clone)]
pub struct Package {
- name: String,
- version: String,
- arch: archs,
+ name: String,
+ version: String,
+ arch: Archs,
descr: Option<String>,
}
@@ -38,9 +38,9 @@ pub struct Package {
#[derive(Deserialize, Debug, Clone)]
struct Install {
package: Package,
- path: String,
- user: String,
- group: String,
+ path: String,
+ user: String,
+ group: String,
mode: String,
//. Cancels the previous fields and installs them using the shell script
custom_script: Option<String>,
@@ -49,7 +49,7 @@ struct Install {
#[allow(dead_code)]
#[derive(Deserialize, Debug)]
struct Setts {
- env: Option<String>, // Export environment variables if this needed
+ env: Option<String>, // Export environment variables if this needed
test: Option<String>, // Test the package after installation
}
@@ -57,32 +57,32 @@ struct Setts {
pub enum BuildSystems {
Make,
CMake,
- Meson,
- Cargo
+ Meson,
+ Cargo,
}
#[allow(dead_code)]
#[derive(Deserialize)]
struct Build {
- build_system: BuildSystems,
+ build_system: BuildSystems,
env: Option<String>,
script: Option<String>,
}
-impl archs {
+impl Archs {
fn as_str(&self) -> &'static str {
match self {
- archs::X86_64 => "x86_64",
- archs::Aarch64 => "aarch64",
- archs::X86 => "x86",
- archs::ArmV7 => "armv7",
- archs::ArmV8 => "armv8"
+ Archs::X86_64 => "x86_64",
+ Archs::Aarch64 => "aarch64",
+ Archs::X86 => "x86",
+ Archs::ArmV7 => "armv7",
+ Archs::ArmV8 => "armv8",
}
}
}
#[allow(dead_code)]
-impl Package {
+impl Package {
/// Execute the build script for the package.
///
/// This function takes the `Build` meta information as an argument and
@@ -95,8 +95,8 @@ impl Package {
fn execute_build(&self, build_meta: &Build) -> Result<(), std::io::Error> {
let config = Config::parse()
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
- let build_dir = Path::new(&config.paths.cache_dir)
- .join(format!("{}-{}", self.name, self.version));
+ let build_dir =
+ Path::new(&config.paths.cache_dir).join(format!("{}-{}", self.name, self.version));
let mut cmd = match build_meta.build_system {
BuildSystems::Make => {
@@ -105,33 +105,31 @@ impl Package {
if build_meta.script.is_some() {
c.arg("-f").arg(build_meta.script.as_ref().unwrap());
}
- c.arg("all");
- c
+ c.arg("all");
+ c
}
BuildSystems::CMake => {
let build_dir_build = build_dir.join("build");
create_dir_all(&build_dir_build)?;
let mut c = Command::new("cmake");
- c.arg("-S").arg(&build_dir)
- .arg("-B").arg(&build_dir_build)
- .current_dir(&build_dir);
- c
+ c.arg("-S")
+ .arg(&build_dir)
+ .arg("-B")
+ .arg(&build_dir_build)
+ .current_dir(&build_dir);
+ c
}
BuildSystems::Meson => {
let build_dir_build = build_dir.join("build");
create_dir_all(&build_dir_build)?;
let mut c = Command::new("meson");
- c.arg("setup")
- .arg(&build_dir_build)
- .current_dir(&build_dir);
- c
+ c.arg("setup").arg(&build_dir_build).current_dir(&build_dir);
+ c
}
BuildSystems::Cargo => {
let mut c = Command::new("cargo");
- c.arg("build")
- .arg("--release")
- .current_dir(&build_dir);
- c
+ c.arg("build").arg("--release").current_dir(&build_dir);
+ c
}
};
@@ -154,13 +152,13 @@ impl Package {
}
/// Extracts a .tar.gz archive to the cache directory specified in Config.
- ///
+ ///
/// This function handles opening the archive file, decompressing it with GzDecoder,
/// and unpacking the contents into the configured cache directory.
- ///
+ ///
/// # Arguments
/// * `path_to_archive` - A string representing the path to the .tar.gz file.
- ///
+ ///
/// # Returns
/// * `Ok(())` if the archive is successfully unpacked.
/// * `Err(std::io::Error)` if there's an issue opening, reading, or unpacking the archive.
@@ -181,19 +179,22 @@ impl Package {
///
/// This function parses the meta information from the .mesk archive,
/// which includes the package name, version, architecture, description,
- /// installation path, user, group, mode, and custom installation script
+ /// installation path, user, group, mode, and custom installation script
/// and deserializing this information. Returns (Install, Option<Setts>, Option<Build>)
- ///
+ ///
/// The function expects the 'INSTALL', 'SETTS', and 'BUILD' files to be present
/// in the `config.paths.cache_dir`. It specifically requires the 'INSTALL' file.
- ///
+ ///
/// # Errors
///
/// Returns an error if the `cache_dir` cannot be created, if the required 'INSTALL' file
/// is not found, or if the 'INSTALL' file is empty.
- fn loadmeta(minimal_package_meta: &mut Self) -> Result<(Install, Option<Setts>, Option<Build>), Box<dyn std::error::Error>> { // Changed return type for more flexibility
- /*
- Example INSTALL format:
+ fn loadmeta(
+ minimal_package_meta: &mut Self,
+ ) -> Result<(Install, Option<Setts>, Option<Build>), Box<dyn std::error::Error>> {
+ // Changed return type for more flexibility
+ /*
+ Example INSTALL format:
[package]
name = "my-package"
version = "1.0.0"
@@ -206,27 +207,26 @@ impl 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
# """
*/
-
let config = Config::parse()?; // Propagate error if parsing fails
// Ensure the cache directory exists
fs::create_dir_all(&config.paths.cache_dir)?;
-
let cache_dir = &config.paths.cache_dir;
- let install_path = Path::new(cache_dir).join(format!("{}/INSTALL", minimal_package_meta.name));
+ let install_path =
+ Path::new(cache_dir).join(format!("{}/INSTALL", minimal_package_meta.name));
let setts_path = Path::new(cache_dir).join(format!("{}/SETTS", minimal_package_meta.name));
let build_path = Path::new(cache_dir).join(format!("{}/BUILD", minimal_package_meta.name));
@@ -234,8 +234,9 @@ impl Package {
if !install_path.exists() {
return Err(io::Error::new(
io::ErrorKind::NotFound,
- "File INSTALL not found in cache directory"
- ).into()); // Convert to Box<dyn Error>
+ "File INSTALL not found in cache directory",
+ )
+ .into()); // Convert to Box<dyn Error>
}
// Read and deserialize the INSTALL file
@@ -259,29 +260,33 @@ impl Package {
}
// Log if custom script is present
- if let Some(ref script) = install_meta.custom_script {
- println!("Custom script found for package: {}", install_meta.package.name);
+ if let Some(ref _script) = install_meta.custom_script {
+ println!(
+ "Custom script found for package: {}",
+ install_meta.package.name
+ );
// Consider logging the script content or just its presence based on verbosity
// e.g., log::debug!("Custom script content: {}", script);
} else {
- println!("No custom script for package: {}", install_meta.package.name);
+ println!(
+ "No custom script for package: {}",
+ install_meta.package.name
+ );
}
Ok((install_meta, setts_meta, build_meta))
}
-
-
/// Checks if the archive contains INSTALL, SETTS and BUILD files.
///
/// Checks if INSTALL file exists and is not empty. If it does not exist or is empty, returns an error.
///
/// Checks if SETTS and BUILD files exist and are not empty. If they do not exist or are empty, logs a warning.
- /// # Errors
+ /// # Errors
/// * Returns an error if INSTALL file does not exist or is empty.
/// * Returns an error if INSTALL file is empty.
///
- // TODO: Add meta-files validation here.
+ // TODO: Add meta-files validation here.
pub fn check(path_to_archive: String) -> Result<bool, std::io::Error> {
// Call the new extraction function
Self::extract_archive(&path_to_archive)?;
@@ -325,27 +330,35 @@ impl Package {
}
}
- let content = std::fs::read_to_string(&install_path)
- .map_err(|e| {
+ let content = std::fs::read_to_string(&install_path).map_err(|e| {
log::warn!("Failed to read file: {}", e);
e
})?;
let install_content: Result<Install, toml::de::Error> = toml::from_str(&content);
- log::info!("Validating arch...");
- if std::env::consts::ARCH != install_content.as_ref().map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))?.package.arch.as_str() {
+ log::info!("Validating arch...");
+ if std::env::consts::ARCH
+ != install_content
+ .as_ref()
+ .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))?
+ .package
+ .arch
+ .as_str()
+ {
let pkg_arch = &install_content.unwrap().package.arch; // Safe because of previous check/unwrap
- log::error!("Arch mismatch. Package arch: {:?}, Host arch: {}", pkg_arch, std::env::consts::ARCH);
+ log::error!(
+ "Arch mismatch. Package arch: {:?}, Host arch: {}",
+ pkg_arch,
+ std::env::consts::ARCH
+ );
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"Arch mismatch",
));
}
-
+
Ok(true)
}
-
-
/// Builds the package according to the BUILD file in the archive.
///
@@ -354,21 +367,21 @@ impl Package {
/// If the BUILD file is empty and the INSTALL file contains a custom script, the custom script is run instead of the default install hook.
/// If the BUILD file is not empty and the INSTALL file contains a custom script, the custom script is ignored.
///
- ///
+ ///
/// # Errors
///
/// Returns an error if the BUILD file is invalid or if the build or install hook fails.
pub fn build(&mut self) -> Result<bool, std::io::Error> {
let meta = Self::loadmeta(self).unwrap();
let install_meta = meta.0;
- let setts_meta = meta.1;
+ // let setts_meta = meta.1;
let build_meta = meta.2;
// BUILD NOT EMPTY. SOURCE: -> BUILD -> INSTALL -> SETTS
// BUILD EMPTY. BIN: -> INSTALL -> SETTS
enum Strategies {
- BIN,
- SOURCE
+ BIN,
+ SOURCE,
}
let strategy; //default
@@ -380,7 +393,7 @@ impl Package {
strategy = Strategies::SOURCE;
log::info!("BUILD file is not empty. Skipping install, preparing to build");
}
-
+
match strategy {
Strategies::BIN => {
if install_meta.custom_script.is_none() {
@@ -389,11 +402,10 @@ impl Package {
log::info!("Strategy: BIN; Running custom script.");
let script = install_meta.custom_script.as_ref().unwrap();
if !script.starts_with("./") {
- let _output = std::process::Command::new(format!("{}", script));
+ let _output = std::process::Command::new(format!("{}", script));
} else {
let _output = std::process::Command::new(format!("/bin/sh '{}'", script));
}
-
}
}
Strategies::SOURCE => {
@@ -405,111 +417,152 @@ impl Package {
Ok(true)
}
-
/// Installs the package according to the INSTALL file in the archive.
///
/// There are two strategies for installing the package. If the BUILD file is empty, the package is assumed to be a binary package and the default install hook is skipped. If the BUILD file is not empty, the package is assumed to be a source package and the default build hook is skipped.
///
/// If the BUILD file is empty and the INSTALL file contains a custom script, the custom script is run instead of the default install hook.
/// If the BUILD file is not empty and the INSTALL file contains a custom script, the custom script is ignored.
- ///
+ ///
/// # Errors
///
/// Returns an error if the BUILD file is invalid or if the build or install hook fails.
pub fn install(&mut self) -> Result<bool, std::io::Error> {
- let config = Config::parse()
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
- let (install_meta, _setts_meta, build_meta) = Self::loadmeta(self)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
-
-
- let is_build_present_and_not_empty = build_meta.is_some();
-
- if is_build_present_and_not_empty {
- log::info!("Found BUILD file, preparing to build and install package: {}", self.name);
- let build_meta_ref = build_meta.as_ref().unwrap();
- self.execute_build(build_meta_ref);
-
-
- if matches!(build_meta_ref.build_system, BuildSystems::Make) {
- log::info!("Running 'make install' for package: {}", self.name);
- let build_dir = Path::new(&config.paths.cache_dir)
- .join(format!("{}-{}", self.name, self.version));
- let output = Command::new("make")
- .arg("install")
- .current_dir(&build_dir)
- .output()
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("'make install' failed: {}", e)))?;
-
- if !output.status.success() {
- let stderr = String::from_utf8_lossy(&output.stderr);
- return Err(std::io::Error::new(
+ let config = Config::parse()
+ .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
+ let (install_meta, _setts_meta, build_meta) = Self::loadmeta(self)
+ .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))?;
+
+ let is_build_present_and_not_empty = build_meta.is_some();
+
+ if is_build_present_and_not_empty {
+ log::info!(
+ "Found BUILD file, preparing to build and install package: {}",
+ self.name
+ );
+ let build_meta_ref = build_meta.as_ref().unwrap();
+ let _ = self.execute_build(build_meta_ref);
+
+ if matches!(build_meta_ref.build_system, BuildSystems::Make) {
+ log::info!("Running 'make install' for package: {}", self.name);
+ let build_dir = Path::new(&config.paths.cache_dir)
+ .join(format!("{}-{}", self.name, self.version));
+ let output = Command::new("make")
+ .arg("install")
+ .current_dir(&build_dir)
+ .output()
+ .map_err(|e| {
+ std::io::Error::new(
std::io::ErrorKind::Other,
- format!("'make install' failed:\n{}", stderr),
- ));
- }
+ format!("'make install' failed: {}", e),
+ )
+ })?;
+
+ if !output.status.success() {
+ let stderr = String::from_utf8_lossy(&output.stderr);
+ return Err(std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("'make install' failed:\n{}", stderr),
+ ));
+ }
+ }
+ } else {
+ log::info!(
+ "No BUILD file or it's empty. Treating as binary package. Installing via INSTALL config or custom script."
+ );
+ // Установка бинарного пакета
+ if let Some(ref script) = install_meta.custom_script {
+ log::info!(
+ "Executing custom install script for {}",
+ install_meta.package.name
+ );
+ let status = if script.starts_with("./") || script.contains('/') {
+ Command::new("/bin/sh").arg("-c").arg(script).status()
+ } else {
+ Command::new(script).status()
+ }
+ .map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to run custom script: {}", e),
+ )
+ })?;
+
+ if !status.success() {
+ return Err(std::io::Error::new(
+ std::io::ErrorKind::Other,
+ "Custom install script failed",
+ ));
}
} else {
- log::info!("No BUILD file or it's empty. Treating as binary package. Installing via INSTALL config or custom script.");
- // Установка бинарного пакета
- if let Some(ref script) = install_meta.custom_script {
- log::info!("Executing custom install script for {}", install_meta.package.name);
- let status = if script.starts_with("./") || script.contains('/') {
- Command::new("/bin/sh").arg("-c").arg(script).status()
- } else {
- Command::new(script).status()
- }
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to run custom script: {}", e)))?;
-
- if !status.success() {
- return Err(std::io::Error::new(
+ log::info!(
+ "No custom script. Running default install hook for {}",
+ install_meta.package.name
+ );
+ // --- Дефолтный хук установки ---
+ // 1. Копируем файл из build_dir (предположим, что бинарный файл лежит в корне распакованного архива)
+ let source_file_name = &self.name; // Предполагаем имя файла = имя пакета
+ 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.path);
+
+ // Убедимся, что целевая директория существует
+ if let Some(parent) = dest_path.parent() {
+ create_dir_all(parent).map_err(|e| {
+ std::io::Error::new(
std::io::ErrorKind::Other,
- "Custom install script failed",
- ));
- }
- } else {
- log::info!("No custom script. Running default install hook for {}", install_meta.package.name);
- // --- Дефолтный хук установки ---
- // 1. Копируем файл из build_dir (предположим, что бинарный файл лежит в корне распакованного архива)
- let source_file_name = &self.name; // Предполагаем имя файла = имя пакета
- 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.path);
-
- // Убедимся, что целевая директория существует
- if let Some(parent) = dest_path.parent() {
- create_dir_all(parent)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to create parent dir: {}", e)))?;
- }
-
- fs::copy(&src_path, dest_path)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to copy file: {}", e)))?;
-
- let mode = u32::from_str_radix(&install_meta.mode, 8)
- .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid mode string in INSTALL"))?;
- let perms = PermissionsExt::from_mode(mode);
- fs::set_permissions(dest_path, perms)
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("Failed to set permissions: {}", e)))?;
-
- let output = Command::new("chown")
- .arg(&format!("{}:{}", install_meta.user, install_meta.group))
- .arg(dest_path)
- .output()
- .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, format!("'chown' command failed: {}", e)))?;
+ format!("Failed to create parent dir: {}", e),
+ )
+ })?;
+ }
- if !output.status.success() {
- let stderr = String::from_utf8_lossy(&output.stderr);
- log::warn!("Warning: 'chown' command failed (requires root?):\n{}", stderr);
- }
+ fs::copy(&src_path, dest_path).map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to copy file: {}", e),
+ )
+ })?;
+
+ let mode = u32::from_str_radix(&install_meta.mode, 8).map_err(|_| {
+ std::io::Error::new(
+ std::io::ErrorKind::InvalidData,
+ "Invalid mode string in INSTALL",
+ )
+ })?;
+ let perms = PermissionsExt::from_mode(mode);
+ fs::set_permissions(dest_path, perms).map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::Other,
+ format!("Failed to set permissions: {}", e),
+ )
+ })?;
+
+ let output = Command::new("chown")
+ .arg(&format!("{}:{}", install_meta.user, install_meta.group))
+ .arg(dest_path)
+ .output()
+ .map_err(|e| {
+ std::io::Error::new(
+ std::io::ErrorKind::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
+ );
}
}
+ }
log::info!("Package {} installed successfully.", self.name);
Ok(true)
}
- pub fn gen_index() -> Result<bool, std::io::Error> {
+ pub fn gen_index() -> Result<bool, std::io::Error> {
todo!();
-
}
-} \ No newline at end of file
+}