hyperdb_bootstrap/
scrape.rs1use regex::Regex;
14use std::collections::HashMap;
15
16use crate::platform::Platform;
17use crate::release::PinnedRelease;
18use crate::Error;
19
20const RELEASES_URL: &str = "https://tableau.github.io/hyper-db/docs/releases";
21
22pub fn scrape_latest(platform: Platform) -> Result<PinnedRelease, Error> {
35 tracing::info!(url = RELEASES_URL, "scraping latest release");
36 let client = reqwest::blocking::Client::builder()
37 .user_agent(concat!("hyperd-bootstrap/", env!("CARGO_PKG_VERSION")))
38 .build()
39 .map_err(Error::Http)?;
40 let resp = client.get(RELEASES_URL).send().map_err(Error::Http)?;
41 if !resp.status().is_success() {
42 return Err(Error::http_status(RELEASES_URL, resp.status().as_u16()));
43 }
44 let html = resp.text().map_err(Error::Http)?;
45 parse_latest(&html, platform)
46}
47
48fn parse_latest(html: &str, platform: Platform) -> Result<PinnedRelease, Error> {
49 let h3_re =
52 Regex::new(r"<h3[^>]*>\s*([0-9]+(?:\.[0-9]+){1,3})\s*\[[^\]]+\]").expect("valid regex");
53 let version = h3_re
54 .captures(html)
55 .and_then(|c| c.get(1))
56 .map(|m| m.as_str().to_string())
57 .ok_or(Error::ScrapeFailed(
58 "no <h3>VERSION [DATE]</h3> heading found",
59 ))?;
60
61 let href_re = Regex::new(&format!(
64 r"tableauhyperapi-java-{plat}-release-main\.{ver}\.(rc[a-z0-9]+)\.zip",
65 plat = regex::escape(platform.slug()),
66 ver = regex::escape(&version),
67 ))
68 .expect("valid regex");
69 let build_id = href_re
70 .captures(html)
71 .and_then(|c| c.get(1))
72 .map(|m| m.as_str().to_string())
73 .ok_or(Error::ScrapeFailed(
74 "no matching java zip href for scraped version",
75 ))?;
76
77 Ok(PinnedRelease {
78 version,
79 build_id,
80 sha256: HashMap::new(),
81 })
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn parse_real_page_snippet() {
90 let html = r#"
91 <h3>0.0.24457 [February 12 2026]</h3>
92 <ul><li>Release notes</li></ul>
93 <a href="https://downloads.tableau.com/tssoftware//tableauhyperapi-java-macos-arm64-release-main.0.0.24457.rc36858b6.zip">Java (macOS arm64)</a>
94 <a href="https://downloads.tableau.com/tssoftware//tableauhyperapi-java-linux-x86_64-release-main.0.0.24457.rc36858b6.zip">Java (Linux)</a>
95 <h3>0.0.20000 [January 1 2025]</h3>
96 "#;
97 let release = parse_latest(html, Platform::MacosArm64).unwrap();
98 assert_eq!(release.version, "0.0.24457");
99 assert_eq!(release.build_id, "rc36858b6");
100 }
101
102 #[test]
103 fn parse_errors_when_no_heading() {
104 let html = "<p>nothing here</p>";
105 assert!(matches!(
106 parse_latest(html, Platform::LinuxX86_64),
107 Err(Error::ScrapeFailed(_))
108 ));
109 }
110
111 #[test]
112 fn parse_errors_when_no_matching_href() {
113 let html = r"<h3>0.0.24457 [Feb 12 2026]</h3>";
114 assert!(matches!(
115 parse_latest(html, Platform::WindowsX86_64),
116 Err(Error::ScrapeFailed(_))
117 ));
118 }
119}