summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNaz <ndpm13@ch-naseem.com>2025-08-07 16:30:46 +0100
committerNaz <ndpm13@ch-naseem.com>2025-08-07 16:30:46 +0100
commite022abbdcb21f3b093727b68bd832807d7bfc720 (patch)
tree7a57274e7f0194e0d798fc194dc486ad348e2602 /src
parentc5157ee81b64f20c12ac11b7eb79e07bd3af1469 (diff)
✨feat: add the github functionality
Diffstat (limited to 'src')
-rw-r--r--src/error.rs10
-rw-r--r--src/github.rs69
-rw-r--r--src/lib.rs2
-rw-r--r--src/manager.rs11
4 files changed, 90 insertions, 2 deletions
diff --git a/src/error.rs b/src/error.rs
index f946f58..85f85f6 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -11,6 +11,7 @@ pub enum Error {
source: reqwest::Error,
},
InvalidAppImage,
+ InvalidSlug(String),
#[from]
Io(std::io::Error),
@@ -26,6 +27,12 @@ pub enum Error {
#[from]
IndicatifTemplate(indicatif::style::TemplateError),
+
+ #[from]
+ Octocrab(octocrab::Error),
+
+ #[from]
+ Dialoguer(dialoguer::Error),
}
impl core::fmt::Display for Error {
@@ -57,6 +64,9 @@ impl core::fmt::Display for Error {
Error::InvalidAppImage => {
write!(fmt, "Invalid AppImage")
}
+ Error::InvalidSlug(slug) => write!(fmt, "Invalid repository slug {slug}"),
+ Error::Octocrab(e) => write!(fmt, "Octocrab error: {e}"),
+ Error::Dialoguer(e) => write!(fmt, "Dialoguer error: {e}"),
}
}
}
diff --git a/src/github.rs b/src/github.rs
new file mode 100644
index 0000000..50812d1
--- /dev/null
+++ b/src/github.rs
@@ -0,0 +1,69 @@
+use dialoguer::FuzzySelect;
+use octocrab::models::repos::Asset;
+
+use crate::{AppImage, Error, Result};
+
+pub async fn get_github_release_url(appimage: &AppImage) -> Result<String> {
+ let octocrab = octocrab::instance();
+
+ let (owner, repo) = appimage
+ .source
+ .meta
+ .url
+ .split_once('/')
+ .ok_or_else(|| Error::InvalidSlug(appimage.source.meta.url.to_string()))?;
+
+ let page = octocrab
+ .repos(owner, repo)
+ .releases()
+ .list()
+ .per_page(100)
+ .send()
+ .await?;
+
+ let mut tags: Vec<String> = vec![];
+
+ for releases in &page {
+ for asset in &releases.assets {
+ if asset.name.to_lowercase().ends_with(".appimage") {
+ tags.push(releases.tag_name.to_string());
+ break;
+ }
+ }
+ }
+
+ let tag_selection = FuzzySelect::new()
+ .with_prompt("Choose a release")
+ .items(&tags)
+ .interact()?;
+
+ let mut assets: Vec<Asset> = vec![];
+
+ for releases in page {
+ if releases.tag_name == tags[tag_selection] {
+ for asset in releases.assets {
+ if asset.name.to_lowercase().ends_with(".appimage") {
+ assets.push(asset);
+ }
+ }
+ }
+ }
+
+ let mut asset_selection: usize = 0;
+
+ if assets.len() > 1 {
+ asset_selection = FuzzySelect::new()
+ .with_prompt("Choose an asset")
+ .items(
+ &assets
+ .iter()
+ .map(|x| x.name.to_string())
+ .collect::<Vec<_>>(),
+ )
+ .interact()?;
+ }
+
+ let url = assets[asset_selection].browser_download_url.to_string();
+
+ Ok(url)
+}
diff --git a/src/lib.rs b/src/lib.rs
index 3e20bde..987f485 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -7,6 +7,7 @@ mod paths;
mod symlink;
mod tui;
mod error;
+mod github;
pub use crate::appimage::*;
pub use crate::args::*;
@@ -17,3 +18,4 @@ pub use crate::paths::*;
pub use crate::symlink::*;
pub use crate::tui::*;
pub use crate::error::*;
+pub use crate::github::*;
diff --git a/src/manager.rs b/src/manager.rs
index e0fb7ac..15f28d9 100644
--- a/src/manager.rs
+++ b/src/manager.rs
@@ -1,6 +1,8 @@
use tokio::fs;
-use crate::{AppImage, Downloader, Index, Result, SymlinkManager, index_dir};
+use crate::{
+ AppImage, Downloader, Index, Result, SymlinkManager, get_github_release_url, index_dir,
+};
#[derive(Debug, Default)]
pub struct PackageManager {
@@ -32,7 +34,12 @@ impl PackageManager {
.download_with_progress(&appimage.source.meta.url, &appimage.file_path)
.await?;
} else {
- todo!()
+ self.downloader
+ .download_with_progress(
+ &get_github_release_url(appimage).await?,
+ &appimage.file_path,
+ )
+ .await?;
}
self.index.add(appimage, appname).await?;