Skip to content

Commit

Permalink
feat(provides): add provides support
Browse files Browse the repository at this point in the history
  • Loading branch information
QaidVoid committed Jan 20, 2025
1 parent 82b20b9 commit 937a447
Show file tree
Hide file tree
Showing 13 changed files with 256 additions and 90 deletions.
2 changes: 2 additions & 0 deletions soar-cli/src/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ where
} else {
select_asset(&assets)?
};

info!("Downloading asset from {}", selected_asset.download_url());
handler.download(&selected_asset, options.clone()).await?;
Ok(())
}
Expand Down
67 changes: 41 additions & 26 deletions soar-cli/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use soar_core::{
config::get_config,
database::{
models::{InstalledPackage, Package},
packages::{get_installed_packages, get_packages, FilterOp, QueryOptions},
packages::{get_installed_packages, get_packages, FilterOp, ProvideStrategy, QueryOptions},
},
error::SoarError,
package::{
Expand Down Expand Up @@ -301,21 +301,18 @@ async fn install_single_package(
progress_callback: Arc<dyn Fn(DownloadState) + Send + Sync>,
core_db: Arc<Mutex<Connection>>,
) -> SoarResult<()> {
let (install_dir, real_bin, bin_name) = if let Some(ref existing) = target.existing_install {
let bin_dir = get_config().get_bin_path()?;
let (install_dir, real_bin, def_bin_path) = if let Some(ref existing) = target.existing_install
{
let install_dir = PathBuf::from(&existing.installed_path);
let real_bin = install_dir.join(&target.package.pkg_name);
let bin_name = existing
let def_bin_path = existing
.bin_path
.as_ref()
.map(PathBuf::from)
.unwrap_or_else(|| {
get_config()
.get_bin_path()
.unwrap()
.join(&target.package.pkg_name)
});
.unwrap_or_else(|| bin_dir.join(&target.package.pkg_name));

(install_dir, real_bin, bin_name)
(install_dir, real_bin, def_bin_path)
} else {
let rand_str: String = rand::thread_rng()
.sample_iter(&Alphanumeric)
Expand All @@ -328,23 +325,11 @@ async fn install_single_package(
target.package.pkg, target.package.pkg_id, rand_str
));
let real_bin = install_dir.join(&target.package.pkg_name);
let bin_name = get_config()
.get_bin_path()
.unwrap()
.join(&target.package.pkg_name);
let def_bin_path = bin_dir.join(&target.package.pkg_name);

(install_dir, real_bin, bin_name)
(install_dir, real_bin, def_bin_path)
};

if bin_name.exists() {
if let Err(err) = std::fs::remove_file(&bin_name) {
return Err(SoarError::Custom(format!(
"Failed to remove existing symlink: {}",
err
)));
}
}

if install_dir.exists() {
if let Err(err) = std::fs::remove_dir_all(&install_dir) {
return Err(SoarError::Custom(format!(
Expand All @@ -367,7 +352,37 @@ async fn install_single_package(
installer.install().await?;

let final_checksum = calculate_checksum(&real_bin)?;
fs::symlink(&real_bin, &bin_name)?;

if target.package.should_create_original_symlink() {
if def_bin_path.is_symlink() || def_bin_path.exists() {
if let Err(err) = std::fs::remove_file(&def_bin_path) {
return Err(SoarError::Custom(format!(
"Failed to remove existing symlink: {}",
err
)));
}
}
fs::symlink(&real_bin, &def_bin_path)?;
}

if let Some(provides) = &target.package.provides {
for provide in provides {
if let Some(ref target) = provide.target_name {
let real_path = install_dir.join(provide.name.clone());
let is_symlink = match provide.strategy {
ProvideStrategy::KeepTargetOnly | ProvideStrategy::KeepBoth => true,
_ => false,
};
if is_symlink {
let target_name = bin_dir.join(&target);
if target_name.is_symlink() || target_name.exists() {
std::fs::remove_file(&target_name)?;
}
fs::symlink(&real_path, &target_name)?;
}
}
}
}

let (icon_path, desktop_path) = integrate_package(
&install_dir,
Expand All @@ -379,7 +394,7 @@ async fn install_single_package(
.await?;

installer
.record(&final_checksum, &bin_name, icon_path, desktop_path)
.record(&final_checksum, &bin_dir, icon_path, desktop_path)
.await?;

Ok(())
Expand Down
101 changes: 50 additions & 51 deletions soar-cli/src/list.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,61 @@
use std::collections::HashMap;
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};

use indicatif::HumanBytes;
use nu_ansi_term::Color::{Blue, Cyan, Green, Magenta, Red, Yellow};
use rusqlite::Connection;
use soar_core::{
config::get_config,
database::packages::{
get_installed_packages, get_packages, FilterOp, PaginatedIterator, QueryOptions, SortOrder,
database::{
models::Package,
packages::{
get_installed_packages, get_packages, Filter, FilterOp, PaginatedIterator,
QueryOptions, SortOrder,
},
},
SoarResult,
};
use tracing::info;

use crate::state::AppState;

fn get_package_install_state(
core_db: &Arc<Mutex<Connection>>,
filters: &HashMap<String, Filter>,
package: &Package,
) -> SoarResult<String> {
let mut filters = filters.clone();
filters.insert(
"repo_name".to_string(),
(FilterOp::Eq, package.repo_name.clone().into()).into(),
);
filters.insert(
"pkg_id".to_string(),
(FilterOp::Eq, package.pkg_id.clone().into()).into(),
);
filters.insert(
"pkg_name".to_string(),
(FilterOp::Eq, package.pkg_name.clone().into()).into(),
);
let options = QueryOptions {
limit: 1,
filters,
..Default::default()
};

let installed_pkgs = get_installed_packages(core_db.clone(), options)?.items;

let install_status = match installed_pkgs {
_ if installed_pkgs.is_empty() => "-",
_ if installed_pkgs.first().unwrap().is_installed => "+",
_ => "?",
};

Ok(install_status.to_string())
}

pub async fn search_packages(
query: String,
case_sensitive: bool,
Expand Down Expand Up @@ -45,31 +88,7 @@ pub async fn search_packages(
)?;

for package in packages.items {
let mut filters = filters.clone();
filters.insert(
"repo_name".to_string(),
(FilterOp::Eq, package.repo_name.clone().into()).into(),
);
filters.insert(
"pkg_name".to_string(),
(FilterOp::Eq, package.pkg_name.clone().into()).into(),
);
let options = QueryOptions {
limit: 1,
filters,
..Default::default()
};

let installed_pkgs = get_installed_packages(core_db.clone(), options)?.items;

let mut install_status = "-";
if !installed_pkgs.is_empty() {
if installed_pkgs.first().unwrap().is_installed {
install_status = "+";
} else {
install_status = "?";
}
}
let install_state = get_package_install_state(&core_db, &filters, &package)?;

info!(
pkg_name = %package.pkg_name,
Expand All @@ -78,7 +97,7 @@ pub async fn search_packages(
version = %package.version,
repo_name = %package.repo_name,
"[{}] {}#{}-{}:{} - {} ({})",
install_status,
install_state,
Blue.paint(package.pkg_name.clone()),
Cyan.paint(package.pkg_id.clone()),
Magenta.paint(package.version.clone()),
Expand Down Expand Up @@ -202,33 +221,13 @@ pub async fn list_packages(repo_name: Option<String>) -> SoarResult<()> {
for result in package_iterator {
let packages = result?;
for package in packages {
let mut filters = filters.clone();
filters.insert(
"repo_name".to_string(),
(FilterOp::Eq, package.repo_name.clone().into()).into(),
);
let options = QueryOptions {
filters,
..Default::default()
};

let installed_pkgs = get_installed_packages(core_db.clone(), options)?.items;

let mut install_status = "-";
if !installed_pkgs.is_empty() {
if installed_pkgs.first().unwrap().is_installed {
install_status = "+";
} else {
install_status = "?";
}
}

let install_state = get_package_install_state(&core_db, &filters, &package)?;
info!(
pkg_name = %package.pkg_name,
version = %package.version,
repo_name = %package.repo_name,
"[{}] {}-{}:{}",
install_status,
install_state,
Red.paint(package.pkg_name.clone()),
package.version,
package.repo_name
Expand Down
9 changes: 7 additions & 2 deletions soar-cli/src/update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,13 @@ pub async fn update_packages(packages: Option<Vec<String>>) -> SoarResult<()> {
}
}
} else {
let installed_pkgs =
get_installed_packages(core_db.clone(), QueryOptions::default())?.items;
let mut filters = HashMap::new();
filters.insert("pinned".to_string(), (FilterOp::Eq, false.into()).into());
let options = QueryOptions {
filters: filters.clone(),
..Default::default()
};
let installed_pkgs = get_installed_packages(core_db.clone(), options)?.items;
for pkg in installed_pkgs {
let mut filters = HashMap::new();

Expand Down
3 changes: 2 additions & 1 deletion soar-core/migrations/core/V1_initial.sql
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ CREATE TABLE packages (
profile TEXT NOT NULL,
pinned BOOLEAN NOT NULL DEFAULT false,
is_installed BOOLEAN NOT NULL DEFAULT false,
installed_with_family BOOLEAN NOT NULL DEFAULT false
installed_with_family BOOLEAN NOT NULL DEFAULT false,
provides JSONB
);
4 changes: 3 additions & 1 deletion soar-core/migrations/metadata/V1_initial.sql
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,7 @@ CREATE TABLE packages (
build_id TEXT,
build_date TEXT,
build_script TEXT,
build_log TEXT
build_log TEXT,
provides JSONB,
UNIQUE (pkg_id, pkg_name)
);
19 changes: 18 additions & 1 deletion soar-core/src/database/models.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use rusqlite::types::Value;
use serde::{Deserialize, Serialize};

use super::packages::{PackageProvide, ProvideStrategy};

#[derive(Debug, Clone)]
pub struct Package {
pub id: u64,
Expand Down Expand Up @@ -31,6 +33,7 @@ pub struct Package {
pub build_date: Option<String>,
pub build_script: Option<String>,
pub build_log: Option<String>,
pub provides: Option<Vec<PackageProvide>>,
}

#[derive(Debug, Clone)]
Expand All @@ -53,6 +56,7 @@ pub struct InstalledPackage {
pub pinned: bool,
pub is_installed: bool,
pub installed_with_family: bool,
pub provides: Option<Vec<PackageProvide>>,
}

#[derive(Debug, Default, Clone, Deserialize, Serialize)]
Expand Down Expand Up @@ -102,8 +106,21 @@ pub struct RemotePackage {
#[serde(alias = "category")]
pub categories: Vec<String>,

pub provides: Vec<String>,
pub provides: Option<Vec<String>>,
pub icon: Option<String>,
pub desktop: Option<String>,
pub app_id: Option<String>,
}

impl Package {
pub fn should_create_original_symlink(&self) -> bool {
self.provides
.as_ref()
.map(|links| {
!links
.iter()
.any(|link| matches!(link.strategy, ProvideStrategy::KeepTargetOnly))
})
.unwrap_or(true)
}
}
Loading

0 comments on commit 937a447

Please sign in to comment.