From 11626bfde188d865f56cf9b71e86241bfddbea1f Mon Sep 17 00:00:00 2001 From: Naz Date: Fri, 8 Aug 2025 08:09:34 +0100 Subject: =?UTF-8?q?=F0=9F=93=9Adocs:=20update=20install=20instructions=20t?= =?UTF-8?q?o=20use=20published=20crate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a7db689..56b523d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ AppImage package manager inspired by [zap](https://github.com/srevinsaju/zap), b ## Install ```bash -cargo install --git https://github.com/ndpm13/zap-rs +cargo install zap-rs ``` ## Usage -- cgit v1.2.3 From 32bda21c93754359335f8826b5edf931d551d2e8 Mon Sep 17 00:00:00 2001 From: Naz Date: Fri, 8 Aug 2025 15:48:59 +0100 Subject: =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8Fchore:=20update=20deps?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7ee3b05..e33e701 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -152,9 +152,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "cc" -version = "1.2.31" +version = "1.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a42d84bb6b69d3a8b3eaacf0d88f179e1929695e1ad012b6cf64d9caaa5fd2" +checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" dependencies = [ "shlex", ] @@ -564,9 +564,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" [[package]] name = "heck" @@ -1507,9 +1507,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" -- cgit v1.2.3 From b0d4e60e525e2438e02fa3e3b5ffaba374a03a71 Mon Sep 17 00:00:00 2001 From: Naz Date: Fri, 8 Aug 2025 15:52:51 +0100 Subject: =?UTF-8?q?=F0=9F=94=A7refactor:=20move=20AppImage=20construction?= =?UTF-8?q?=20logic=20to=20new()=20method?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/appimage.rs | 25 +++++++++++++++++++++++++ src/main.rs | 18 +++--------------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/appimage.rs b/src/appimage.rs index 5d0f8e5..c3f61b1 100644 --- a/src/appimage.rs +++ b/src/appimage.rs @@ -1,6 +1,8 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; +use crate::InstallArgs; + #[derive(Debug, Serialize, Deserialize)] pub struct AppImage { pub file_path: PathBuf, @@ -18,3 +20,26 @@ pub struct Source { pub struct SourceMetadata { pub url: String, } + +impl AppImage { + pub fn new(options: &InstallArgs) -> Self { + Self { + file_path: PathBuf::new(), + executable: options + .executable + .as_ref() + .unwrap_or(&options.appname) + .to_string(), + source: Source { + identifier: if options.github { + "git.github".to_string() + } else { + "raw_url".to_string() + }, + meta: SourceMetadata { + url: options.from.clone(), + }, + }, + } + } +} diff --git a/src/main.rs b/src/main.rs index e4bc296..3081598 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,7 @@ use clap::Parser; use colored::Colorize; -use std::path::PathBuf; -use zap_rs::{AppImage, Cli, Command, PackageManager, Result, Source, SourceMetadata}; +use zap_rs::{AppImage, Cli, Command, PackageManager, Result}; async fn run() -> Result<()> { let args = Cli::parse(); @@ -10,20 +9,9 @@ async fn run() -> Result<()> { match args.command { Command::Install(args) => { - let mut options = AppImage { - file_path: PathBuf::new(), - executable: args.executable.unwrap_or(args.appname.clone()), - source: Source { - identifier: if args.github { - "git.github".to_string() - } else { - "raw_url".to_string() - }, - meta: SourceMetadata { url: args.from }, - }, - }; + let mut appimage = AppImage::new(&args); - pm.install(&mut options, &args.appname).await?; + pm.install(&mut appimage, &args.appname).await?; } Command::Remove(args) => { pm.remove(&args.appname).await?; -- cgit v1.2.3 From e961fad84734ba750386ed463057bacedf24bc17 Mon Sep 17 00:00:00 2001 From: Naz Date: Fri, 8 Aug 2025 17:18:43 +0100 Subject: =?UTF-8?q?=E2=9C=A8feat:=20add=20desktop=20integration=20logic=20?= =?UTF-8?q?to=20AppImage=20and=20utilize=20it=20in=20PackageManager?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/appimage.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/manager.rs | 38 +++++++++++++++++++- src/paths.rs | 8 +++++ 3 files changed, 153 insertions(+), 3 deletions(-) diff --git a/src/appimage.rs b/src/appimage.rs index c3f61b1..bf0de6d 100644 --- a/src/appimage.rs +++ b/src/appimage.rs @@ -1,7 +1,8 @@ use serde::{Deserialize, Serialize}; -use std::path::PathBuf; +use std::{path::PathBuf, process::Command}; +use tokio::fs; -use crate::InstallArgs; +use crate::{Error, InstallArgs, Result, desktops_dir, icons_dir}; #[derive(Debug, Serialize, Deserialize)] pub struct AppImage { @@ -42,4 +43,109 @@ impl AppImage { }, } } + async fn extract_assets(&self) -> Result { + let temp_dir = std::env::temp_dir().join("zap-rs"); + + fs::create_dir_all(&temp_dir).await?; + + // Extract desktop file + Command::new(&self.file_path) + .arg("--appimage-extract") + .arg("*.desktop") + .current_dir(&temp_dir) + .spawn()? + .wait()?; + + // Extract icon + Command::new(&self.file_path) + .arg("--appimage-extract") + .arg("usr/share/icons/hicolor/512x512/apps/*.png") + .current_dir(&temp_dir) + .spawn()? + .wait()?; + + Ok(temp_dir) + } + async fn fix_desktop(&self, desktop_file_path: &PathBuf) -> Result<()> { + let file_content = fs::read_to_string(&desktop_file_path).await?; + + let appimage_path = self.file_path.to_str().ok_or(Error::InvalidPath)?; + + let icon_path = icons_dir()? + .join(format!("{}.png", self.executable)) + .to_str() + .ok_or(Error::InvalidPath)? + .to_string(); + + let fixed_file_content: Vec = file_content + .lines() + .map(|line| { + if line.contains("Exec=") { + if let Some(exec_line) = line.split_once(" ") { + if let Some(exec_arg) = exec_line.0.split_once("=") { + format!("{}={} {}", exec_arg.0, appimage_path, exec_line.1) + } else { + line.to_string() + } + } else if let Some(exec_arg) = line.split_once("=") { + format!("{}={}", exec_arg.0, appimage_path) + } else { + line.to_string() + } + } else if line.contains("Icon=") { + if let Some(exec_arg) = line.split_once("=") { + format!("{}={}", exec_arg.0, icon_path) + } else { + line.to_string() + } + } else { + line.to_string() + } + }) + .collect(); + + fs::write(desktop_file_path, fixed_file_content.join("\n")).await?; + + Ok(()) + } + pub async fn integrate_desktop(&self) -> Result<()> { + let temp_dir = self.extract_assets().await?; + let squashfs = &temp_dir.join("squashfs-root"); + + fs::create_dir_all(desktops_dir()?).await?; + fs::create_dir_all(icons_dir()?).await?; + + let icon_path = icons_dir()?.join(format!("{}.png", self.executable)); + let desktop_file_paths = ( + desktops_dir()?.join(format!("{}.desktop", self.executable)), + PathBuf::from(std::env::var("HOME")?).join(format!( + ".local/share/applications/{}.desktop", + self.executable + )), + ); + + let mut squashfs_entries = fs::read_dir(&squashfs).await?; + while let Some(entry) = squashfs_entries.next_entry().await? { + if entry.path().extension() == Some("desktop".as_ref()) { + fs::copy(entry.path(), &desktop_file_paths.0).await?; + + self.fix_desktop(&desktop_file_paths.0).await?; + + fs::copy(&desktop_file_paths.0, &desktop_file_paths.1).await?; + } + } + + let mut squashfs_icon_entries = + fs::read_dir(&squashfs.join("usr/share/icons/hicolor/512x512/apps")).await?; + while let Some(entry) = squashfs_icon_entries.next_entry().await? { + if entry.path().extension() == Some("png".as_ref()) { + fs::copy(entry.path(), &icon_path).await?; + } + } + + // Clean up + fs::remove_dir_all(temp_dir).await?; + + Ok(()) + } } diff --git a/src/manager.rs b/src/manager.rs index 15f28d9..bdb152a 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -1,7 +1,12 @@ +use std::{ + io::{self, Write}, + path::PathBuf, +}; use tokio::fs; use crate::{ - AppImage, Downloader, Index, Result, SymlinkManager, get_github_release_url, index_dir, + AppImage, Downloader, Index, Result, SymlinkManager, desktops_dir, get_github_release_url, + icons_dir, index_dir, }; #[derive(Debug, Default)] @@ -44,6 +49,17 @@ impl PackageManager { self.index.add(appimage, appname).await?; self.symlink_manager.create(appimage).await?; + + print!("Do you want to integrate this appimage? (y/N) "); + io::stdout().flush()?; + + let mut input = String::new(); + io::stdin().read_line(&mut input)?; + + if input.to_lowercase().trim() == "y" || input.to_lowercase().trim() == "yes" { + appimage.integrate_desktop().await?; + } + Ok(()) } pub async fn remove(&self, appname: &str) -> Result<()> { @@ -53,6 +69,26 @@ impl PackageManager { self.symlink_manager.remove(&appimage.executable).await?; self.index.remove(appname).await?; + if fs::try_exists(desktops_dir()?.join(format!("{}.desktop", appimage.executable))).await? { + fs::remove_file(desktops_dir()?.join(format!("{}.desktop", appimage.executable))) + .await?; + } + if fs::try_exists(PathBuf::from(std::env::var("HOME")?).join(format!( + ".local/share/applications/{}.desktop", + appimage.executable + ))) + .await? + { + fs::remove_file(PathBuf::from(std::env::var("HOME")?).join(format!( + ".local/share/applications/{}.desktop", + appimage.executable + ))) + .await?; + } + if fs::try_exists(icons_dir()?.join(format!("{}.png", appimage.executable))).await? { + fs::remove_file(icons_dir()?.join(format!("{}.png", appimage.executable))).await?; + } + Ok(()) } pub async fn list(&self) -> Result<()> { diff --git a/src/paths.rs b/src/paths.rs index 7bbc8f8..c52a84e 100644 --- a/src/paths.rs +++ b/src/paths.rs @@ -14,3 +14,11 @@ pub fn index_dir() -> Result { pub fn appimages_dir() -> Result { Ok(zap_rs_home()?.join("appimages")) } + +pub fn desktops_dir() -> Result { + Ok(zap_rs_home()?.join("desktops")) +} + +pub fn icons_dir() -> Result { + Ok(zap_rs_home()?.join("icons")) +} -- cgit v1.2.3