summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cfg/config.rs2
-rw-r--r--src/main.rs87
-rw-r--r--src/net/http_package.rs (renamed from src/net/http_packages.rs)33
-rw-r--r--src/net/i2p_package.rs110
-rw-r--r--src/net/mod.rs2
-rw-r--r--src/pkgtoolkit/pkgtools.rs69
6 files changed, 191 insertions, 112 deletions
diff --git a/src/cfg/config.rs b/src/cfg/config.rs
index 88c98ff..de9901f 100644
--- a/src/cfg/config.rs
+++ b/src/cfg/config.rs
@@ -125,6 +125,6 @@ impl Config {
*/
},
};
- Ok(toml::to_string(&generator)?)
+ toml::to_string(&generator)
}
}
diff --git a/src/main.rs b/src/main.rs
index 8677fdb..37bd70a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,9 +1,10 @@
mod cfg;
-mod net;
+mod net; // This should contain both i2p_package and http_package modules
mod pkgtoolkit;
use crate::cfg::config::Config;
-use crate::net::i2p_package::I2PPackage;
+use crate::net::{i2p_package::I2PPackage,
+ http_package::HTTPPackage};
#[allow(unused_imports)]
use crate::pkgtoolkit::pkgtools::Package;
@@ -12,7 +13,6 @@ use std::fs::File;
use std::fs::create_dir_all;
use std::io::Write;
use std::path::Path;
-use tokio;
#[derive(Parser)]
struct Cli {
@@ -55,19 +55,23 @@ enum Commands {
#[command(about = "Remote install arguments")]
struct RemoteInstallArgs {
#[arg(short = 'b', long = "bin")]
+ #[arg(help = "Install binary package")]
bin: bool,
+
#[arg(short = 'h', long = "http")]
+ #[arg(help = "Use non-i2p mirror")]
http: bool,
+
#[arg(short = 'c', long = "clean")]
+ #[arg(help = "Clean cache before install")]
clean: bool,
}
#[tokio::main]
-async fn main() -> Result<(), std::io::Error> {
+async fn main() -> Result<(), Box<dyn std::error::Error>> {
+ // Changed return type to be more general
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.
match &cli.command {
Commands::Validate { path } => {
println!("Validating {}", path);
@@ -77,13 +81,58 @@ async fn main() -> Result<(), std::io::Error> {
println!("Building {}", pkgname);
return Ok(());
}
-
Commands::Install {
pkgname,
- source,
+ source: _,
args,
} => {
- println!("Installing {}", pkgname);
+ 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);
+ }
+ }
+ } 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);
+ }
+ }
+ }
+ // --- Integration ends here ---
return Ok(());
}
Commands::Uninstall { pkgname } => {
@@ -112,7 +161,7 @@ async fn main() -> Result<(), std::io::Error> {
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())?;
+ file.write_all(config.as_bytes())?;
println!("Config tool ending work.");
} else {
let config = Config::generate(repo, cachedir, buildir).unwrap();
@@ -134,13 +183,21 @@ async fn main() -> Result<(), std::io::Error> {
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;
- println!("Index updated");
+
+ 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);
+ }
+ }
return Ok(());
}
Commands::Upgrade { pkgname } => {
- println!("Upgrading all packages");
+ println!("Upgrading {}", pkgname.as_deref().unwrap_or("all packages"));
return Ok(());
}
Commands::Credits => {
@@ -148,7 +205,7 @@ async fn main() -> Result<(), std::io::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 ");
}
}
diff --git a/src/net/http_packages.rs b/src/net/http_package.rs
index 05b2ac6..ec7c318 100644
--- a/src/net/http_packages.rs
+++ b/src/net/http_package.rs
@@ -1,5 +1,6 @@
use crate::cfg::config::Config;
use crate::pkgtoolkit::pkgtools::Package;
+use futures_util::stream::TryStreamExt;
use indicatif::{ProgressBar, ProgressStyle};
use reqwest;
use serde::Deserialize;
@@ -7,7 +8,6 @@ use std::collections::HashMap;
use std::path::Path;
use tokio::fs::File;
use tokio::io::AsyncWriteExt;
-use futures_util::stream::TryStreamExt;
pub struct HTTPPackage {
config: Config,
@@ -72,7 +72,7 @@ impl HTTPPackage {
let pb = ProgressBar::new_spinner();
pb.set_style(
ProgressStyle::default_spinner()
- .template("{spinner:.green} [{elapsed_precise}] Fetching INDEX.tar.gz...")?
+ .template("{spinner:.green} [{elapsed_precise}] Fetching INDEX.tar.gz...")?,
);
pb
};
@@ -125,7 +125,10 @@ impl HTTPPackage {
}
self.index_packages = Some(package_map.clone());
- log::info!("Index loaded successfully, {} packages found.", package_map.len());
+ log::info!(
+ "Index loaded successfully, {} packages found.",
+ package_map.len()
+ );
Ok(true)
}
@@ -167,10 +170,10 @@ impl HTTPPackage {
pb
} else {
let pb = ProgressBar::new_spinner();
- pb.set_style(
- ProgressStyle::default_spinner()
- .template(&format!("{{spinner:.green}} [{{elapsed_precise}}] {}...", description))?
- );
+ pb.set_style(ProgressStyle::default_spinner().template(&format!(
+ "{{spinner:.green}} [{{elapsed_precise}}] {}...",
+ description
+ ))?);
pb
};
@@ -203,7 +206,10 @@ impl HTTPPackage {
///
/// 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.
- pub async fn fetch_package_http(&self, package_name: &str) -> Result<bool, Box<dyn std::error::Error>> {
+ pub async fn fetch_package_http(
+ &self,
+ package_name: &str,
+ ) -> Result<bool, Box<dyn std::error::Error>> {
let package_info = self.fetch_package_info(package_name)?;
let url = &package_info.url;
@@ -229,12 +235,17 @@ impl HTTPPackage {
/// Fetches a specific package identified by `index` (likely the package name).
/// Assumes `fetch_index_http` 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()
+ 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_http first.")?;
let pkg_info = packages
.get(package_name)
.ok_or(format!("Package '{}' not found in index.", package_name))?;
Ok(pkg_info)
}
-} \ No newline at end of file
+}
diff --git a/src/net/i2p_package.rs b/src/net/i2p_package.rs
index 335dbea..751d561 100644
--- a/src/net/i2p_package.rs
+++ b/src/net/i2p_package.rs
@@ -10,9 +10,9 @@ use emissary_core::runtime::{
};
*/
+use indicatif::{ProgressBar, ProgressStyle};
use std::{collections::HashMap, path::Path};
use tokio::io::{AsyncReadExt, AsyncWriteExt, BufReader};
-use indicatif::{ProgressBar, ProgressStyle};
use url;
use yosemite::Session;
@@ -20,12 +20,12 @@ use yosemite::SessionOptions;
pub struct I2PPackage {
config: Config,
- index_packages: Option<HashMap<String, Package>>,
+ index_packages: Option<HashMap<String, Package>>,
}
#[derive(Deserialize, Debug)]
struct IndexData {
- packages: Vec<Package>,
+ packages: Vec<Package>,
}
impl I2PPackage {
@@ -34,10 +34,10 @@ impl I2PPackage {
/// # 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(config: Config) -> Self {
- I2PPackage {
- config: config,
- index_packages: None
+ pub fn new(cfg: Config) -> Self {
+ I2PPackage {
+ config: cfg,
+ index_packages: None,
}
}
@@ -47,7 +47,7 @@ impl I2PPackage {
/// # 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>> {
+ pub async fn fetch_index(&mut self) -> Result<bool, Box<dyn std::error::Error>> {
let repo_url_str = &self.config.repo.repo_url;
let cache_dir = &self.config.paths.cache_dir;
@@ -85,7 +85,8 @@ impl I2PPackage {
return Err(format!(
"HTTP Error: {}",
headers_str.lines().next().unwrap_or("Unknown")
- ).into());
+ )
+ .into());
}
let content_length = headers_str
@@ -93,12 +94,11 @@ impl I2PPackage {
.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 mut body_reader = std::io::Cursor::new(&response_buffer[body_start..]);
let file_path = Path::new(cache_dir).join("INDEX.tar.gz");
-
let pb = if content_length > 0 {
let pb = ProgressBar::new(content_length);
pb.set_style(ProgressStyle::default_bar()
@@ -107,8 +107,9 @@ impl I2PPackage {
pb
} else {
let pb = ProgressBar::new_spinner();
- pb.set_style(ProgressStyle::default_spinner()
- .template("{spinner:.green} [{elapsed_precise}] Fetching INDEX.tar.gz...")?
+ pb.set_style(
+ ProgressStyle::default_spinner()
+ .template("{spinner:.green} [{elapsed_precise}] Fetching INDEX.tar.gz...")?,
);
pb
};
@@ -119,11 +120,10 @@ impl I2PPackage {
let mut buffer = vec![0; chunk_size as usize];
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()),
+ Ok(n) => n,
+ Err(e) => return Err(e.into()),
};
if bytes_read == 0 {
@@ -141,13 +141,13 @@ impl I2PPackage {
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())?;
+ Package::extract_archive(&file_path.to_string_lossy())?;
- let index_toml_path = Path::new(cache_dir).join("INDEX.toml");
+ let index_toml_path = Path::new(cache_dir).join("INDEX.toml");
if !index_toml_path.exists() {
- log::warn!("INDEX.toml not found in INDEX.tar.gz. Proceeding without index data.");
- self.index_packages = Some(HashMap::new());
- return Ok(true);
+ log::warn!("INDEX.toml not found in INDEX.tar.gz. Proceeding without index data.");
+ self.index_packages = Some(HashMap::new());
+ return Ok(true);
}
let index_content = std::fs::read_to_string(&index_toml_path)?;
@@ -155,23 +155,25 @@ impl I2PPackage {
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();
- pkg_clone.url = full_url.to_string();
-
- package_map.insert(pkg_clone.name.clone(), pkg_clone);
+ // 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();
+ pkg_clone.url = full_url.to_string();
+
+ package_map.insert(pkg_clone.name.clone(), pkg_clone);
}
self.index_packages = Some(package_map.clone());
- log::info!("Index loaded successfully, {} packages found.", package_map.len());
+ log::info!(
+ "Index loaded successfully, {} packages found.",
+ package_map.len()
+ );
Ok(true)
}
-
/// An internal auxiliary function for downloading data and writing it to a file with a progress display.
///
/// # Arguments
@@ -198,9 +200,10 @@ impl I2PPackage {
pb
} else {
let pb = ProgressBar::new_spinner();
- pb.set_style(ProgressStyle::default_spinner()
- .template(&format!("{{spinner:.green}} [{{elapsed_precise}}] {}...", description))?
- );
+ pb.set_style(ProgressStyle::default_spinner().template(&format!(
+ "{{spinner:.green}} [{{elapsed_precise}}] {}...",
+ description
+ ))?);
pb
};
@@ -223,10 +226,16 @@ impl I2PPackage {
/// 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()
+ 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)
+ let pkg_info = packages
+ .get(package_name)
.ok_or(format!("Package '{}' not found in index.", package_name))?;
Ok(pkg_info)
}
@@ -239,9 +248,12 @@ impl I2PPackage {
///
/// 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?
+ /// 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.
- pub async fn fetch_package(&self, package_name: &str) -> Result<bool, Box<dyn std::error::Error>> {
+ 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")?;
@@ -271,7 +283,8 @@ impl I2PPackage {
return Err(format!(
"HTTP Error: {}",
headers_str.lines().next().unwrap_or("Unknown")
- ).into());
+ )
+ .into());
}
let content_length = headers_str
@@ -291,10 +304,19 @@ impl I2PPackage {
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?;
-
- log::info!("Package '{}' downloaded successfully to {:?}", package_name, file_path);
+ Self::download_and_write_file_with_progress(
+ body_bytes,
+ &file_path,
+ content_length,
+ file_name,
+ )
+ .await?;
+
+ log::info!(
+ "Package '{}' downloaded successfully to {:?}",
+ package_name,
+ file_path
+ );
Ok(true)
}
}
-
diff --git a/src/net/mod.rs b/src/net/mod.rs
index 5a5aca0..1a04189 100644
--- a/src/net/mod.rs
+++ b/src/net/mod.rs
@@ -1,2 +1,2 @@
-pub mod http_packages;
+pub mod http_package;
pub mod i2p_package;
diff --git a/src/pkgtoolkit/pkgtools.rs b/src/pkgtoolkit/pkgtools.rs
index 8198624..877c8c8 100644
--- a/src/pkgtoolkit/pkgtools.rs
+++ b/src/pkgtoolkit/pkgtools.rs
@@ -8,7 +8,6 @@ use std::{
path::Path,
process::Command,
str,
- collections::HashMap
};
// use emissary_core::i2np::tunnel::build;
@@ -38,7 +37,7 @@ pub struct Package {
}
#[derive(Deserialize, Debug, Clone)]
-pub struct Install_meta {
+pub struct InstallMeta {
path: String,
user: String,
group: String,
@@ -51,7 +50,7 @@ pub struct Install_meta {
#[derive(Deserialize, Debug, Clone)]
struct Install {
package: Package,
- install: Install_meta,
+ install: InstallMeta,
}
#[allow(dead_code)]
@@ -102,9 +101,8 @@ impl Package {
/// Returns an error if the build command fails.
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));
+ .map_err(|e| std::io::Error::other(e.to_string()))?;
+ 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 => {
@@ -142,16 +140,14 @@ impl Package {
};
let output = cmd.output().map_err(|e| {
- std::io::Error::new(
- std::io::ErrorKind::Other,
+ std::io::Error::other(
format!("Build command failed: {}", e),
)
})?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
- return Err(std::io::Error::new(
- std::io::ErrorKind::Other,
+ return Err(std::io::Error::other(
format!("Build failed:\n{}", stderr),
));
}
@@ -197,6 +193,7 @@ impl Package {
///
/// 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.
+ #[allow(clippy::type_complexity)]
fn loadmeta(
minimal_package_meta: &mut Self,
) -> Result<(Install, Option<Setts>, Option<Build>), Box<dyn std::error::Error>> {
@@ -388,35 +385,35 @@ impl Package {
// BUILD NOT EMPTY. SOURCE: -> BUILD -> INSTALL -> SETTS
// BUILD EMPTY. BIN: -> INSTALL -> SETTS
enum Strategies {
- BIN,
- SOURCE,
+ Bin,
+ Source,
}
let strategy; //default
if build_meta.is_none() {
log::info!("BUILD file is empty. Skipping build, preparing to install");
- strategy = Strategies::BIN;
+ strategy = Strategies::Bin;
} else {
- strategy = Strategies::SOURCE;
+ strategy = Strategies::Source;
log::info!("BUILD file is not empty. Skipping install, preparing to build");
}
match strategy {
- Strategies::BIN => {
+ Strategies::Bin => {
if install_meta.install.custom_script.is_none() {
log::info!("Strategy: BIN; No custom script. Running default install hook.");
} else {
log::info!("Strategy: BIN; Running custom script.");
let script = install_meta.install.custom_script.as_ref().unwrap();
if !script.starts_with("./") {
- let _output = std::process::Command::new(format!("{}", script));
+ let _output = std::process::Command::new(script);
} else {
let _output = std::process::Command::new(format!("/bin/sh '{}'", script));
}
}
}
- Strategies::SOURCE => {
+ Strategies::Source => {
log::info!("Strategy: SOURCE; Running default build hook.");
let _ = self.execute_build(&build_meta.unwrap());
}
@@ -437,9 +434,9 @@ impl Package {
/// 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()))?;
+ .map_err(|e| std::io::Error::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()))?;
+ .map_err(|e| std::io::Error::other(e.to_string()))?;
let is_build_present_and_not_empty = build_meta.is_some();
@@ -460,16 +457,14 @@ impl Package {
.current_dir(&build_dir)
.output()
.map_err(|e| {
- std::io::Error::new(
- std::io::ErrorKind::Other,
+ std::io::Error::other(
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,
+ return Err(std::io::Error::other(
format!("'make install' failed:\n{}", stderr),
));
}
@@ -490,15 +485,13 @@ impl Package {
Command::new(script).status()
}
.map_err(|e| {
- std::io::Error::new(
- std::io::ErrorKind::Other,
+ std::io::Error::other(
format!("Failed to run custom script: {}", e),
)
})?;
if !status.success() {
- return Err(std::io::Error::new(
- std::io::ErrorKind::Other,
+ return Err(std::io::Error::other(
"Custom install script failed",
));
}
@@ -507,27 +500,22 @@ impl Package {
"No custom script. Running default install hook for {}",
install_meta.package.name
);
- // --- Дефолтный хук установки ---
- // 1. Копируем файл из build_dir (предположим, что бинарный файл лежит в корне распакованного архива)
- let source_file_name = &self.name; // Предполагаем имя файла = имя пакета
+ 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.install.path);
- // Убедимся, что целевая директория существует
if let Some(parent) = dest_path.parent() {
create_dir_all(parent).map_err(|e| {
- std::io::Error::new(
- std::io::ErrorKind::Other,
+ std::io::Error::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,
+ std::io::Error::other(
format!("Failed to copy file: {}", e),
)
})?;
@@ -540,19 +528,20 @@ impl Package {
})?;
let perms = PermissionsExt::from_mode(mode);
fs::set_permissions(dest_path, perms).map_err(|e| {
- std::io::Error::new(
- std::io::ErrorKind::Other,
+ std::io::Error::other(
format!("Failed to set permissions: {}", e),
)
})?;
let output = Command::new("chown")
- .arg(&format!("{}:{}", install_meta.install.user, install_meta.install.group))
+ .arg(format!(
+ "{}:{}",
+ install_meta.install.user, install_meta.install.group
+ ))
.arg(dest_path)
.output()
.map_err(|e| {
- std::io::Error::new(
- std::io::ErrorKind::Other,
+ std::io::Error::other(
format!("'chown' command failed: {}", e),
)
})?;