diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index bb3a502..42afc12 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -54,6 +54,4 @@ jobs: - uses: actions/checkout@v4 - name: Test lib & docs - run: | - cargo test --lib --all-features - cargo test --doc --all-features + run: cargo test --all-features --no-fail-fast diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aff2b4..55978ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,16 @@ All notable changes to nvrs will be documented in this file. - `--list-sources` command ([442c06f](https://github.com/adamperkowski/nvrs/commit/442c06f0e56f4adcc0c2ad44d042997cb088a930)) +### 🚀 Features + +- `--list-sources` command ([442c06f](https://github.com/adamperkowski/nvrs/commit/442c06f0e56f4adcc0c2ad44d042997cb088a930)) +- (*sources*) add regex ([#13](https://github.com/adamperkowski/nvrs/issues/13)) ([fa12ce9](https://github.com/adamperkowski/nvrs/commit/fa12ce9691adbdcf51990eb8416aedf4fdc7d36b)) + +### 🐛 Bug Fixes + +- incorrect `--compare` colors ([ef1f78f](https://github.com/adamperkowski/nvrs/commit/ef1f78fed76f883986734b7e3220b2f56508a5f0)) +- (*io*) not shutting down file streams after writing ([a8a42fd](https://github.com/adamperkowski/nvrs/commit/a8a42fdf03bfde7aeee563fbd6f9d7af832bc70e)) + ### ⚙️ Refactoring - (*verfiles, config*) saving & loading improvements ([81d7efd](https://github.com/adamperkowski/nvrs/commit/81d7efd24b9b425f59bec1cdbb588bc25ed433cb)) @@ -16,6 +26,11 @@ All notable changes to nvrs will be documented in this file. ### 📚 Documentation - more details & improvements ([9f02405](https://github.com/adamperkowski/nvrs/commit/9f02405339c3520340899313365f0de2fb3d65c5)) +- (*README*) update cargo install instructions ([88f0fdc](https://github.com/adamperkowski/nvrs/commit/88f0fdce435c50df44c3ae2cfd5d1087df4376fc)) + +### ⚙️ Miscellaneous Tasks + +- (*repo*) fix dependabot ([432b10f](https://github.com/adamperkowski/nvrs/commit/432b10f32199ecd7a33c2d9643a5e1f512db862c)) ### Other (unconventional) diff --git a/Cargo.lock b/Cargo.lock index 9ed972f..02e7d27 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1190,6 +1190,7 @@ dependencies = [ "crossterm", "futures", "ratatui", + "regex", "reqwest", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 4d58525..28ef67e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,10 +22,11 @@ include = [ [features] nvrs_cli = ["clap", "colored", "futures"] nvrs_tui = ["ratatui", "crossterm", "anyhow", "tachyonfx", "futures"] -default = ["aur", "github", "gitlab"] +default = ["aur", "github", "gitlab", "regex"] aur = [] github = [] gitlab = [] +regex = ["dep:regex"] [[bin]] name = "nvrs" @@ -44,6 +45,7 @@ colored = { version = "2.1.0", optional = true } crossterm = { version = "0.28.1", features = ["events", "event-stream"], default-features = false, optional = true } futures = { version = "0.3.31", optional = true } ratatui = { version = "0.29.0", 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 60c9bd2..71bd127 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,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 @@ -145,6 +146,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 ab10a0a..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![], }; @@ -187,6 +204,8 @@ pub async fn save(config_content: Config, path: PathBuf) -> error::Result<()> { let mut file = fs::File::create(path).await?; let content = format!("{}\n", toml::to_string(&config_content)?); file.write_all(content.as_bytes()).await?; + file.shutdown().await?; + Ok(()) } diff --git a/src/main.rs b/src/main.rs index 928a125..b918bb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -57,7 +57,7 @@ async fn compare(core: Core) -> error::Result<()> { "*".white().on_black(), new_pkg.0.blue(), old_pkg.1.version.red(), - new_pkg.1.version.blue() + new_pkg.1.version.green() ); } } else { diff --git a/src/verfiles.rs b/src/verfiles.rs index dd40fae..589c589 100644 --- a/src/verfiles.rs +++ b/src/verfiles.rs @@ -76,6 +76,8 @@ pub async fn save( let content = format!("{}\n", serde_json::to_string_pretty(&verfile)?); file.write_all(content.as_bytes()).await?; + file.shutdown().await?; + Ok(()) } @@ -83,6 +85,7 @@ async fn load_file(path: &Path) -> error::Result { if !path.exists() { let mut file = fs::File::create(path).await?; file.write_all(TEMPLATE.as_bytes()).await?; + file.shutdown().await?; } let content = fs::read_to_string(path).await?;