From fa12ce9691adbdcf51990eb8416aedf4fdc7d36b Mon Sep 17 00:00:00 2001 From: Veronika <36178216+pisquaredover6@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:10:35 +0100 Subject: [PATCH] feat(sources): add regex (#13) Add source type regex Search through a webpage for the version string that fits a given regex. The first match of the regex is returned. --------- Co-authored-by: Adam Perkowski --- Cargo.lock | 1 + Cargo.toml | 4 +++- README.md | 3 +++ nvrs.toml | 12 ++++++++++++ src/api/mod.rs | 7 +++++++ src/api/regex.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ src/config.rs | 17 +++++++++++++++++ src/tui.rs | 1 + 8 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/api/regex.rs create mode 100644 src/tui.rs diff --git a/Cargo.lock b/Cargo.lock index 86eade3..fd3aa8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -992,6 +992,7 @@ dependencies = [ "colored", "criterion", "futures", + "regex", "reqwest", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index e5eaed9..7a99662 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,10 +21,11 @@ include = [ [features] nvrs_cli = ["clap", "colored", "futures"] -default = ["aur", "github", "gitlab"] +default = ["aur", "github", "gitlab", "regex"] aur = [] github = [] gitlab = [] +regex = ["dep:regex"] [[bin]] name = "nvrs" @@ -40,6 +41,7 @@ required-features = ["nvrs_tui"] clap = { version = "4.5.22", features = ["derive", "color", "error-context", "help", "std", "usage"], default-features = false , optional = true } colored = { version = "2.1.0", optional = true } futures = { version = "0.3.31", optional = true } +regex = { version = "1.11.1", optional = true } reqwest = { version = "0.12.9", features = ["__tls", "charset", "default-tls", "h2", "http2", "json"], default-features = false } serde = { version = "1.0.215", features = ["derive"], default-features = false } serde_json = "1.0.132" diff --git a/README.md b/README.md index 3b1f8bf..9523b45 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ check the [release notes](https://github.com/adamperkowski/nvrs/releases) for co - `aur` - `github` - `gitlab` (with custom hosts) +- `website` (regex) ### QOL improvements - `ALL` argument for the `--take` command @@ -143,6 +144,8 @@ package entries are custom entries in the main config file. they contain values | `host` | domain name the source is hosted on | string | ❌ | ❌ | | `prefix` | the prefix used in releases / tags
example: `v` for tags like `v0.1.0` | string | ❌ | ❌ | | `use_max_tag` | use max git tag instead of the latest release | bool | ❌ | ❌ | +| `url` | url to check for source type `regex` | string | ❌ | ❌ | +| `regex` | regex to search url for source type `regex` | bool | ❌ | ❌ | ### Keyfile structure this file contains API keys for various [sources](#sources). example can be found [here](/n_keyfile.toml). diff --git a/nvrs.toml b/nvrs.toml index 62394c1..2c31a62 100644 --- a/nvrs.toml +++ b/nvrs.toml @@ -28,3 +28,15 @@ prefix = "v" source = "github" github = "rust-lang/rustup" use_max_tag = true + +[rustrover] +source = 'regex' +url = 'https://data.services.jetbrains.com/products?code=RR&release.type=release' +encoding = 'utf8' +regex = 'RustRover-([\d.]+).tar.gz' + +[linux] +source = 'regex' +url = 'https://www.kernel.org/' +encoding = 'utf8' +regex = '([\d.]+)' diff --git a/src/api/mod.rs b/src/api/mod.rs index a328feb..12328f4 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -6,6 +6,8 @@ mod aur; mod github; #[cfg(feature = "gitlab")] mod gitlab; +#[cfg(feature = "regex")] +mod regex; /// struct containing the API name & a pointer to API's `get_latest` function pub struct Api { @@ -78,6 +80,11 @@ pub const API_LIST: &[Api] = &[ name: "gitlab", func: gitlab::get_latest, }, + #[cfg(feature = "regex")] + Api { + name: "regex", + func: regex::get_latest, + }, ]; #[test] diff --git a/src/api/regex.rs b/src/api/regex.rs new file mode 100644 index 0000000..e532874 --- /dev/null +++ b/src/api/regex.rs @@ -0,0 +1,47 @@ +use crate::{api, error}; +use regex::Regex; + +/// get a version string from a webpage +pub fn get_latest(args: api::ApiArgs) -> api::ReleaseFuture { + Box::pin(async move { + let url = args.args[0].clone(); + let client = args.request_client; + + let result = client + .get(&url) + .headers(api::setup_headers()) + .send() + .await?; + api::match_statuscode(&result.status(), args.package.clone())?; + + let body = result.text().await?; + + let re = Regex::new(&args.args[1]).unwrap(); + if let Some(caps) = re.captures(&body) { + Ok(api::Release { + name: caps.get(1).unwrap().as_str().to_owned(), + tag: None, + url, + }) + } else { + Err(error::Error::NoVersion(args.package)) + } + }) +} + +#[tokio::test] +async fn request_test() { + let package = "rustrover".to_string(); + let args = api::ApiArgs { + request_client: reqwest::Client::new(), + package: package.clone(), + use_max_tag: None, + args: vec![ + "https://data.services.jetbrains.com/products?code=RR&release.type=release".to_string(), + r"RustRover-([\d.]+).tar.gz".to_string(), + ], + api_key: String::new(), + }; + + assert!(crate::api::regex::get_latest(args).await.is_ok()); +} diff --git a/src/config.rs b/src/config.rs index 3e80c21..0332a51 100644 --- a/src/config.rs +++ b/src/config.rs @@ -59,6 +59,12 @@ pub struct Package { #[serde(default)] #[serde(skip_serializing_if = "is_empty_string")] gitlab: String, + #[cfg(feature = "regex")] + #[serde(default)] + url: String, + #[cfg(feature = "regex")] + #[serde(default)] + regex: String, /// whether to use the latest tag instead of the latest release #[serde(default)] @@ -95,6 +101,11 @@ impl Package { package.gitlab = target; Ok(()) } + #[cfg(feature = "regex")] + "regex" => { + package.url = target; + Ok(()) + } _ => Err(error::Error::SourceNotFound(source.clone())), }?; @@ -115,6 +126,10 @@ impl Package { github: String::new(), #[cfg(feature = "gitlab")] gitlab: String::new(), + #[cfg(feature = "regex")] + url: String::new(), + #[cfg(feature = "regex")] + regex: String::new(), use_max_tag: None, prefix: String::new(), } @@ -137,6 +152,8 @@ impl Package { "github" => vec![self.github.clone()], #[cfg(feature = "gitlab")] "gitlab" => vec![self.gitlab.clone(), self.host.clone()], + #[cfg(feature = "regex")] + "regex" => vec![self.url.clone(), self.regex.clone()], _ => vec![], }; diff --git a/src/tui.rs b/src/tui.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/tui.rs @@ -0,0 +1 @@ +