Skip to content

Commit

Permalink
feat(self): add self update
Browse files Browse the repository at this point in the history
  • Loading branch information
QaidVoid committed Nov 25, 2024
1 parent 58f5a17 commit e4ba2af
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 31 deletions.
16 changes: 16 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ pub struct Args {
pub command: Commands,
}

#[derive(Subcommand)]
pub enum SelfAction {
/// Update soar
Update,
/// Uninstall soar
Uninstall,
}

#[derive(Subcommand)]
pub enum Commands {
/// Install packages
Expand Down Expand Up @@ -208,4 +216,12 @@ pub enum Commands {
/// Build
#[clap(name = "build")]
Build { files: Vec<String> },

/// Modify the soar installation
#[command(arg_required_else_help = true)]
#[clap(name = "self")]
SelfCmd {
#[clap(subcommand)]
action: SelfAction,
},
}
65 changes: 61 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use anyhow::Result;
use clap::Parser;
use cli::{Args, Commands};
use misc::{download::download_and_save, health::check_health};
use cli::{Args, Commands, SelfAction};
use misc::{
download::{download, download_and_save, github::fetch_github_releases, ApiType},
health::check_health,
};
use package::build;
use registry::PackageRegistry;
use tracing::{debug, error, trace, warn};
use tokio::fs;
use tracing::{debug, error, info, trace, warn};

use core::{
color::{Color, ColorExt},
Expand All @@ -13,7 +17,11 @@ use core::{
log::setup_logging,
util::{cleanup, print_env, setup_required_paths},
};
use std::{env, io::Read, path::Path};
use std::{
env::{self, consts::ARCH},
io::Read,
path::Path,
};

mod cli;
pub mod core;
Expand All @@ -23,6 +31,8 @@ mod registry;

async fn handle_cli() -> Result<()> {
let mut args = env::args().collect::<Vec<_>>();
let self_bin = args.get(0).unwrap().clone();
let self_version = env!("CARGO_PKG_VERSION");

let mut i = 0;
while i < args.len() {
Expand Down Expand Up @@ -173,6 +183,53 @@ async fn handle_cli() -> Result<()> {
build::init(&file).await?;
}
}
Commands::SelfCmd { action } => {
match action {
SelfAction::Update => {
let is_nightly = self_version.starts_with("nightly");
let gh_releases =
fetch_github_releases(&ApiType::PkgForge, "pkgforge/soar").await?;

let release = gh_releases.iter().find(|rel| {
if is_nightly {
return rel.name.starts_with("nightly") && rel.name != self_version;
} else {
rel.tag_name
.trim_start_matches('v')
.parse::<f32>()
.map(|v| v > self_version.parse::<f32>().unwrap())
.unwrap_or(false)
}
});
if let Some(release) = release {
let asset = release
.assets
.iter()
.find(|a| {
a.name.contains(ARCH)
&& !a.name.contains("tar")
&& !a.name.contains("sum")
})
.unwrap();
download(&asset.browser_download_url, Some(self_bin)).await?;
println!("Soar updated to {}", release.tag_name);
} else {
eprintln!("No updates found.");
}
}
SelfAction::Uninstall => {
match fs::remove_file(self_bin).await {
Ok(_) => {
info!("Soar has been uninstalled successfully.");
info!("You should remove soar config and data files manually.");
}
Err(err) => {
error!("{}\nFailed to uninstall soar.", err.to_string());
}
};
}
};
}
};

Ok(())
Expand Down
26 changes: 15 additions & 11 deletions src/misc/download/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,20 @@ use crate::{
use super::{should_fallback, ApiType};

#[derive(Clone, Debug, Deserialize, Serialize)]
struct GithubAsset {
name: String,
size: u64,
browser_download_url: String,
pub struct GithubAsset {
pub name: String,
pub size: u64,
pub browser_download_url: String,
}

#[derive(Debug, Deserialize, Serialize)]
struct GithubRelease {
tag_name: String,
draft: bool,
prerelease: bool,
published_at: String,
assets: Vec<GithubAsset>,
pub struct GithubRelease {
pub name: String,
pub tag_name: String,
pub draft: bool,
pub prerelease: bool,
pub published_at: String,
pub assets: Vec<GithubAsset>,
}

pub static GITHUB_URL_REGEX: &str =
Expand Down Expand Up @@ -64,7 +65,10 @@ async fn call_github_api(gh_api: &ApiType, user_repo: &str) -> Result<Response>
.context("Failed to fetch GitHub releases")
}

async fn fetch_github_releases(gh_api: &ApiType, user_repo: &str) -> Result<Vec<GithubRelease>> {
pub async fn fetch_github_releases(
gh_api: &ApiType,
user_repo: &str,
) -> Result<Vec<GithubRelease>> {
let response = match call_github_api(gh_api, user_repo).await {
Ok(resp) => {
let status = resp.status();
Expand Down
24 changes: 9 additions & 15 deletions src/misc/download/gitlab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{
misc::download::download,
};

use super::should_fallback;
use super::{should_fallback, ApiType};

#[derive(Clone, Debug, Deserialize, Serialize)]
struct GitlabAsset {
Expand All @@ -41,25 +41,19 @@ struct GitlabRelease {
pub static GITLAB_URL_REGEX: &str =
r"^(?i)(?:https?://)?(?:gitlab(?:\.com)?[:/])([^/@]+/[^/@]+)(?:@([^/\s]*)?)?$";

#[derive(Debug)]
enum GitlabApi {
PkgForge,
Gitlab,
}

async fn call_gitlab_api(gh_api: &GitlabApi, user_repo: &str) -> Result<Response> {
async fn call_gitlab_api(gh_api: &ApiType, user_repo: &str) -> Result<Response> {
let client = reqwest::Client::new();
let url = format!(
"{}/api/v4/projects/{}/releases",
match gh_api {
GitlabApi::PkgForge => "https://api.gl.pkgforge.dev",
GitlabApi::Gitlab => "https://gitlab.com",
ApiType::PkgForge => "https://api.gl.pkgforge.dev",
ApiType::Primary => "https://gitlab.com",
},
user_repo.replace("/", "%2F")
);
let mut headers = HeaderMap::new();
headers.insert(USER_AGENT, "pkgforge/soar".parse()?);
if matches!(gh_api, GitlabApi::Gitlab) {
if matches!(gh_api, ApiType::Primary) {
if let Ok(token) = env::var("GITLAB_TOKEN") {
trace!("Using Gitlab token: {}", token);
headers.insert(AUTHORIZATION, format!("Bearer {}", token).parse()?);
Expand All @@ -73,13 +67,13 @@ async fn call_gitlab_api(gh_api: &GitlabApi, user_repo: &str) -> Result<Response
.context("Failed to fetch Gitlab releases")
}

async fn fetch_gitlab_releases(gh_api: &GitlabApi, user_repo: &str) -> Result<Vec<GitlabRelease>> {
async fn fetch_gitlab_releases(gh_api: &ApiType, user_repo: &str) -> Result<Vec<GitlabRelease>> {
let response = match call_gitlab_api(gh_api, user_repo).await {
Ok(resp) => {
let status = resp.status();
if should_fallback(status) && matches!(gh_api, GitlabApi::PkgForge) {
if should_fallback(status) && matches!(gh_api, ApiType::PkgForge) {
debug!("Failed to fetch Gitlab asset using pkgforge API. Retrying request using Gitlab API.");
call_gitlab_api(&GitlabApi::Gitlab, user_repo).await?
call_gitlab_api(&ApiType::Primary, user_repo).await?
} else {
resp
}
Expand Down Expand Up @@ -138,7 +132,7 @@ pub async fn handle_gitlab_download(
.filter(|&tag| !tag.is_empty());
info!("Fetching releases for {}...", user_repo);

let releases = fetch_gitlab_releases(&GitlabApi::PkgForge, user_repo).await?;
let releases = fetch_gitlab_releases(&ApiType::PkgForge, user_repo).await?;

let release = if let Some(tag_name) = tag {
releases
Expand Down
2 changes: 1 addition & 1 deletion src/misc/download/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use tokio::{
};
use tracing::{error, info};

mod github;
pub mod github;
mod gitlab;

use crate::{
Expand Down

0 comments on commit e4ba2af

Please sign in to comment.