Skip to content

Commit

Permalink
feat(sources): multiple sources + AUR
Browse files Browse the repository at this point in the history
this would probably need a refactor in the future

Resolves #2
  • Loading branch information
adamperkowski committed Nov 17, 2024
1 parent 1201a35 commit 8322ada
Show file tree
Hide file tree
Showing 8 changed files with 134 additions and 37 deletions.
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ categories = ["cli"]
edition = "2021"

[features]
default = ["github"]
github = ["tokio", "reqwest"]
default = ["aur", "github"]
aur = ["reqwest"]
github = ["reqwest"]

[dependencies]
clap = { version = "4.5.21", features = ["derive", "color", "error-context", "help", "std", "usage"], default-features = false }
colored = "2.1.0"
reqwest = { version = "0.12.9", features = ["__tls", "charset", "default-tls", "h2", "http2", "json"], default-features = false, optional = true }
serde = { version = "1.0.215", features = ["derive"] }
serde_json = "1.0.132"
tokio = { version = "1.41.1", features = ["full"] , optional = true }
tokio = { version = "1.41.1", features = ["full"] }
toml = { version = "0.8.19", features = ["parse", "display"], default-features = false }

[profile.release]
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ here's supposed to be a list of features and stuff but i'm too lazy to write all
### Speed
<img src='https://media1.tenor.com/m/mMWXOkCEndoAAAAC/ka-chow-lightning-mcqueen.gif' alt='ka-chow' width=80 height=45>

| command | time per **updated** package | details |
|---------------|------------------------------|--------------------------------------------------------------|
| `nvrs` | ~ 0.1s | **GitHub API request included**<br>depends on internet speed |
| `nvrs --cmp` | ~ 0.0008s | depends on disk speed |
| `nvrs --take` | ~ 0.001s | depends on disk speed |
| command | time per **updated** package | details |
|---------------|------------------------------|--------------------------------------------------------|
| `nvrs` | ~ 0.09s | **API requests included**<br>depends on internet speed |
| `nvrs --cmp` | ~ 0.0008s | depends on disk speed |
| `nvrs --take` | ~ 0.001s | depends on disk speed |

## Credits
- [依云](https://github.com/lilydjwg) | the original [nvchecker](https://github.com/lilydjwg/nvchecker)
Expand Down
5 changes: 5 additions & 0 deletions nvrs.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@ oldver = "oldver.json"
newver = "newver.json"

[hyprgui]
source = "github"
github = "hyprutils/hyprgui"
prefix = "v"

[hyprwall]
source = "aur"
aur = "hyprwall"
37 changes: 37 additions & 0 deletions src/api/aur.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use reqwest::{
header::{HeaderMap, HeaderValue, USER_AGENT},
StatusCode,
};

pub fn get_latest(package: String, _: String) -> crate::api::ReleaseFuture {
Box::pin(async move {
let url = format!("https://aur.archlinux.org/rpc/v5/info/{}", package);
let mut headers = HeaderMap::new();
headers.insert(USER_AGENT, HeaderValue::from_static("nvrs"));
let client = reqwest::Client::new();

let result = client.get(url).headers(headers).send().await.unwrap();

match result.status() {
StatusCode::OK => (),
status => {
crate::custom_error("GET request didn't return 200", format!("\n{}", status));
}
}

let json: serde_json::Value = result.json().await.unwrap();
let first_result = json.get("results").unwrap().get(0).unwrap();

crate::api::Release {
tag_name: first_result
.get("Version")
.unwrap()
.to_string()
.split('-')
.next()
.unwrap_or("")
.to_string(),
html_url: first_result.get("URL").unwrap().to_string(),
}
})
}
49 changes: 22 additions & 27 deletions src/api/github.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,31 @@ use reqwest::{
header::{HeaderMap, HeaderValue, ACCEPT, USER_AGENT},
StatusCode,
};
use serde::Deserialize;

#[derive(Deserialize)]
pub struct Release {
pub tag_name: String,
pub html_url: String,
}

pub async fn get_latest(repo: String) -> Release {
let url = format!("https://api.github.com/repos/{}/releases/latest", repo);
let mut headers = HeaderMap::new();
headers.insert(
ACCEPT,
HeaderValue::from_static("application/vnd.github+json"),
);
headers.insert(USER_AGENT, HeaderValue::from_static("nvrs"));
headers.insert(
"X-GitHub-Api-Version",
HeaderValue::from_static("2022-11-28"),
);
let client = reqwest::Client::new();
pub fn get_latest(_: String, repo: String) -> crate::api::ReleaseFuture {
Box::pin(async move {
let url = format!("https://api.github.com/repos/{}/releases/latest", repo);
let mut headers = HeaderMap::new();
headers.insert(
ACCEPT,
HeaderValue::from_static("application/vnd.github+json"),
);
headers.insert(USER_AGENT, HeaderValue::from_static("nvrs"));
headers.insert(
"X-GitHub-Api-Version",
HeaderValue::from_static("2022-11-28"),
);
let client = reqwest::Client::new();

let result = client.get(url).headers(headers).send().await.unwrap();
let result = client.get(url).headers(headers).send().await.unwrap();

match result.status() {
StatusCode::OK => (),
status => {
crate::custom_error("GET request didn't return 200", format!("\n{}", status));
match result.status() {
StatusCode::OK => (),
status => {
crate::custom_error("GET request didn't return 200", format!("\n{}", status));
}
}
}

result.json().await.unwrap()
result.json().await.unwrap()
})
}
30 changes: 30 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,32 @@
use serde::Deserialize;

#[cfg(feature = "aur")]
pub mod aur;
#[cfg(feature = "github")]
pub mod github;

#[derive(Deserialize)]
pub struct Release {
pub tag_name: String,
pub html_url: String,
}

pub type ReleaseFuture = std::pin::Pin<Box<dyn std::future::Future<Output = Release> + Send>>;

pub struct Api {
pub name: &'static str,
pub func: fn(String, String) -> ReleaseFuture,
}

pub const API_LIST: &[Api] = &[
#[cfg(feature = "aur")]
Api {
name: "aur",
func: aur::get_latest,
},
#[cfg(feature = "github")]
Api {
name: "github",
func: github::get_latest,
},
];
18 changes: 18 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,29 @@ pub struct ConfigTable {

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Package {
pub source: String,
#[cfg(feature = "aur")]
#[serde(default)]
pub aur: String,
#[cfg(feature = "github")]
#[serde(default)]
pub github: String,
#[serde(default)]
pub prefix: String,
}

impl Package {
pub fn get_api_arg(&self, api_name: &str) -> Option<String> {
match api_name {
#[cfg(feature = "aur")]
"aur" => Some(self.aur.clone()),
#[cfg(feature = "github")]
"github" => Some(self.github.clone()),
_ => None,
}
}
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Config {
pub __config__: Option<ConfigTable>,
Expand Down
15 changes: 13 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,9 @@ copies or substantial portions of the Software.",

for package in config_content.packages {
if let Some(pkg) = newver.data.data.iter_mut().find(|p| p.0 == &package.0) {
let latest = api::github::get_latest(package.1.github)
let latest = run_source(package.clone())
.await
.unwrap()
.tag_name
.replacen(&package.1.prefix, "", 1);

Expand All @@ -159,7 +160,7 @@ copies or substantial portions of the Software.",
pkg.1.version = latest;
}
} else {
let latest = api::github::get_latest(package.1.github).await;
let latest = run_source(package.clone()).await.unwrap();

let tag = latest.tag_name.replacen(&package.1.prefix, "", 1);

Expand All @@ -179,6 +180,16 @@ copies or substantial portions of the Software.",
}
}

async fn run_source(package: (String, config::Package)) -> Option<api::Release> {
let source = package.1.source.clone();
if let Some(api_used) = api::API_LIST.iter().find(|a| a.name == source) {
Some((api_used.func)(package.0, package.1.get_api_arg(api_used.name).unwrap()).await)
} else {
custom_error("api not found: ", source);
None
}
}

pub fn custom_error(message: &'static str, message_ext: String) {
custom_error_noexit(message, message_ext);
std::process::exit(1);
Expand Down

0 comments on commit 8322ada

Please sign in to comment.