summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/args.rs4
-rw-r--r--src/error.rs10
-rw-r--r--src/github.rs73
-rw-r--r--src/lib.rs2
-rw-r--r--src/main.rs6
-rw-r--r--src/manager.rs20
6 files changed, 110 insertions, 5 deletions
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<String>,
+
+ /// 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/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..a37e7b1
--- /dev/null
+++ b/src/github.rs
@@ -0,0 +1,73 @@
+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)
+ .max_length(7)
+ .vim_mode(true)
+ .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<_>>(),
+ )
+ .max_length(7)
+ .vim_mode(true)
+ .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/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..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 {
@@ -26,9 +28,19 @@ 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 {
+ self.downloader
+ .download_with_progress(
+ &get_github_release_url(appimage).await?,
+ &appimage.file_path,
+ )
+ .await?;
+ }
self.index.add(appimage, appname).await?;
self.symlink_manager.create(appimage).await?;