Skip to content

Commit 7915faf

Browse files
authored
feat(crate): init soar-package crate (#120)
1 parent 21070db commit 7915faf

File tree

20 files changed

+462
-130
lines changed

20 files changed

+462
-130
lines changed

Cargo.lock

Lines changed: 15 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ members = [
44
"crates/soar-config",
55
"crates/soar-db",
66
"crates/soar-dl",
7+
"crates/soar-package",
78
"crates/soar-registry",
89
"crates/soar-utils",
910
"soar-cli",
@@ -44,6 +45,7 @@ serial_test = "3.2.0"
4445
soar-config = { path = "crates/soar-config" }
4546
soar-core = { path = "soar-core" }
4647
soar-dl = { path = "crates/soar-dl" }
48+
soar-package = { path = "crates/soar-package" }
4749
soar-registry = { path = "crates/soar-registry" }
4850
soar-utils = { path = "crates/soar-utils" }
4951
tempfile = "3.10.1"

crates/soar-package/Cargo.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[package]
2+
name = "soar-package"
3+
version = "0.1.0"
4+
description = "Package format handling for soar package manager"
5+
authors.workspace = true
6+
edition.workspace = true
7+
readme.workspace = true
8+
repository.workspace = true
9+
license.workspace = true
10+
keywords.workspace = true
11+
categories.workspace = true
12+
13+
[dependencies]
14+
image = { version = "0.25.8", default-features = false, features = ["png"] }
15+
miette = { workspace = true }
16+
regex = { workspace = true }
17+
soar-config = { workspace = true }
18+
soar-utils = { workspace = true }
19+
squishy = { version = "0.3.2", features = ["appimage"] }
20+
thiserror = { workspace = true }

crates/soar-package/src/error.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//! Error types for the package crate.
2+
3+
use miette::Diagnostic;
4+
use thiserror::Error;
5+
6+
/// Errors that can occur during package operations.
7+
#[derive(Error, Diagnostic, Debug)]
8+
pub enum PackageError {
9+
#[error("IO error while {action}: {source}")]
10+
#[diagnostic(code(soar_package::io))]
11+
IoError {
12+
action: String,
13+
source: std::io::Error,
14+
},
15+
16+
#[error("Failed to read magic bytes")]
17+
#[diagnostic(code(soar_package::magic_bytes))]
18+
MagicBytesError,
19+
20+
#[error("Failed to seek in file")]
21+
#[diagnostic(code(soar_package::seek))]
22+
SeekError,
23+
24+
#[error("Image processing error: {0}")]
25+
#[diagnostic(code(soar_package::image))]
26+
ImageError(#[from] image::ImageError),
27+
28+
#[error("AppImage error: {0}")]
29+
#[diagnostic(code(soar_package::appimage))]
30+
AppImageError(#[from] squishy::error::SquishyError),
31+
32+
#[error("Configuration error: {0}")]
33+
#[diagnostic(code(soar_package::config))]
34+
ConfigError(String),
35+
36+
#[error("{0}")]
37+
#[diagnostic(code(soar_package::custom))]
38+
Custom(String),
39+
}
40+
41+
/// A specialized Result type for package operations.
42+
pub type Result<T> = std::result::Result<T, PackageError>;
43+
44+
/// Extension trait for adding context to I/O errors.
45+
pub trait ErrorContext<T> {
46+
/// Adds context to an error, describing what action was being performed.
47+
fn with_context<C>(self, context: C) -> Result<T>
48+
where
49+
C: FnOnce() -> String;
50+
}
51+
52+
impl<T> ErrorContext<T> for std::io::Result<T> {
53+
fn with_context<C>(self, context: C) -> Result<T>
54+
where
55+
C: FnOnce() -> String,
56+
{
57+
self.map_err(|err| {
58+
PackageError::IoError {
59+
action: context(),
60+
source: err,
61+
}
62+
})
63+
}
64+
}
65+
66+
impl From<soar_config::error::ConfigError> for PackageError {
67+
fn from(err: soar_config::error::ConfigError) -> Self {
68+
PackageError::ConfigError(err.to_string())
69+
}
70+
}
71+
72+
impl From<soar_utils::error::FileSystemError> for PackageError {
73+
fn from(err: soar_utils::error::FileSystemError) -> Self {
74+
PackageError::Custom(err.to_string())
75+
}
76+
}

soar-core/src/package/formats/appimage.rs renamed to crates/soar-package/src/formats/appimage.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,42 @@
1+
//! AppImage format handling.
2+
13
use std::{fs, path::Path};
24

35
use soar_utils::fs::read_file_signature;
46
use squishy::{appimage::AppImage, EntryKind};
57

6-
use super::common::{symlink_desktop, symlink_icon};
8+
use super::{
9+
common::{symlink_desktop, symlink_icon},
10+
PNG_MAGIC_BYTES,
11+
};
712
use crate::{
8-
constants::PNG_MAGIC_BYTES, database::models::PackageExt, error::ErrorContext, SoarResult,
13+
error::{ErrorContext, Result},
14+
traits::PackageExt,
915
};
1016

17+
/// Integrates an AppImage by extracting its embedded resources.
18+
///
19+
/// This function extracts icons, desktop files, and AppStream metadata from
20+
/// an AppImage and sets up the appropriate symlinks for desktop integration.
21+
///
22+
/// # Arguments
23+
///
24+
/// * `install_dir` - Directory where the package is installed
25+
/// * `file_path` - Path to the AppImage file
26+
/// * `package` - Package metadata
27+
/// * `has_icon` - Whether an icon was already found in the install directory
28+
/// * `has_desktop` - Whether a desktop file was already found
29+
///
30+
/// # Errors
31+
///
32+
/// Returns [`PackageError`] if extraction or symlink creation fails.
1133
pub async fn integrate_appimage<P: AsRef<Path>, T: PackageExt>(
1234
install_dir: P,
1335
file_path: P,
1436
package: &T,
1537
has_icon: bool,
1638
has_desktop: bool,
17-
) -> SoarResult<()> {
39+
) -> Result<()> {
1840
if has_icon && has_desktop {
1941
return Ok(());
2042
}

0 commit comments

Comments
 (0)