From c5157ee81b64f20c12ac11b7eb79e07bd3af1469 Mon Sep 17 00:00:00 2001 From: Naz Date: Thu, 7 Aug 2025 13:48:53 +0100 Subject: =?UTF-8?q?=E2=9C=A8feat:=20add=20scaffolding=20for=20the=20github?= =?UTF-8?q?=20functionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/args.rs | 4 ++++ src/main.rs | 6 +++++- src/manager.rs | 11 ++++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/args.rs b/src/args.rs index 39354f6..a7aa5c6 100644 --- a/src/args.rs +++ b/src/args.rs @@ -34,6 +34,10 @@ pub struct InstallArgs { /// Name of the executable #[arg(long)] pub executable: Option, + + /// Use --from as repository slug to fetch from GitHub + #[arg(long, default_value_t = false)] + pub github: bool, } #[derive(Debug, Args)] diff --git a/src/main.rs b/src/main.rs index 3eb7e95..e4bc296 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,11 @@ async fn run() -> Result<()> { file_path: PathBuf::new(), executable: args.executable.unwrap_or(args.appname.clone()), source: Source { - identifier: "raw_url".to_string(), + identifier: if args.github { + "git.github".to_string() + } else { + "raw_url".to_string() + }, meta: SourceMetadata { url: args.from }, }, }; diff --git a/src/manager.rs b/src/manager.rs index 6f3cfac..e0fb7ac 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -26,9 +26,14 @@ impl PackageManager { appimage.file_path = self .downloader .prepare_path(&appimage.source.meta.url, &appimage.executable)?; - self.downloader - .download_with_progress(&appimage.source.meta.url, &appimage.file_path) - .await?; + + if appimage.source.identifier != "git.github" { + self.downloader + .download_with_progress(&appimage.source.meta.url, &appimage.file_path) + .await?; + } else { + todo!() + } self.index.add(appimage, appname).await?; self.symlink_manager.create(appimage).await?; -- cgit v1.2.3 From e022abbdcb21f3b093727b68bd832807d7bfc720 Mon Sep 17 00:00:00 2001 From: Naz Date: Thu, 7 Aug 2025 16:30:46 +0100 Subject: =?UTF-8?q?=E2=9C=A8feat:=20add=20the=20github=20functionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/error.rs | 10 +++++++++ src/github.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ src/manager.rs | 11 ++++++++-- 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 src/github.rs (limited to 'src') 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 { + 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 = 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 = 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::>(), + ) + .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?; -- cgit v1.2.3 From 9fd13a4ee0a189f6cf81658370df339a1d4e1868 Mon Sep 17 00:00:00 2001 From: Naz Date: Thu, 7 Aug 2025 16:57:49 +0100 Subject: =?UTF-8?q?=E2=9C=A8feat:=20improve=20fuzzy=20select=20UX=20with?= =?UTF-8?q?=20length=20limit=20and=20vim=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/github.rs | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/github.rs b/src/github.rs index 50812d1..a37e7b1 100644 --- a/src/github.rs +++ b/src/github.rs @@ -35,6 +35,8 @@ pub async fn get_github_release_url(appimage: &AppImage) -> Result { let tag_selection = FuzzySelect::new() .with_prompt("Choose a release") .items(&tags) + .max_length(7) + .vim_mode(true) .interact()?; let mut assets: Vec = vec![]; @@ -60,6 +62,8 @@ pub async fn get_github_release_url(appimage: &AppImage) -> Result { .map(|x| x.name.to_string()) .collect::>(), ) + .max_length(7) + .vim_mode(true) .interact()?; } -- cgit v1.2.3