Skip to content

Commit 01379fc

Browse files
committed
Move ExtractIf and version parsing to utils module
1 parent 611d8e0 commit 01379fc

File tree

2 files changed

+160
-152
lines changed

2 files changed

+160
-152
lines changed

site/src/job_queue/mod.rs

Lines changed: 6 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
use std::{
2-
path::Path,
3-
str::FromStr,
4-
sync::{Arc, LazyLock},
5-
};
1+
mod utils;
62

3+
use std::{str::FromStr, sync::Arc};
4+
5+
use crate::job_queue::utils::{parse_release_string, ExtractIf};
76
use crate::load::{partition_in_place, SiteCtxt};
8-
use chrono::{DateTime, NaiveDate, Utc};
7+
use chrono::Utc;
98
use database::{BenchmarkRequest, BenchmarkRequestIndex, BenchmarkRequestStatus};
109
use hashbrown::HashSet;
1110
use parking_lot::RwLock;
12-
use regex::Regex;
1311
use tokio::time::{self, Duration};
1412

1513
pub fn run_new_queue() -> bool {
@@ -48,60 +46,6 @@ async fn create_benchmark_request_master_commits(
4846
Ok(())
4947
}
5048

51-
/// Parses strings in the following formats extracting the Date & release tag
52-
/// `static.rust-lang.org/dist/2016-05-24/channel-rust-1.9.0.toml`
53-
/// `static.rust-lang.org/dist/2016-05-31/channel-rust-nightly.toml`
54-
/// `static.rust-lang.org/dist/2016-06-01/channel-rust-beta.toml`
55-
/// `static.rust-lang.org/dist/2025-06-26/channel-rust-1.89-beta.toml`
56-
/// `static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.toml`
57-
/// `static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.2.toml`
58-
fn parse_release_string(url: &str) -> Option<(String, DateTime<Utc>)> {
59-
static VERSION_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(\d+\.\d+\.\d+)").unwrap());
60-
61-
// Grab ".../YYYY-MM-DD/FILE.toml" components with Path helpers.
62-
let file = Path::new(url).file_name().and_then(|n| n.to_str())?;
63-
64-
let date_str = Path::new(url)
65-
.parent()
66-
.and_then(Path::file_name)
67-
.and_then(|n| n.to_str())?;
68-
69-
// No other beta releases are recognized as toolchains.
70-
//
71-
// We also have names like this:
72-
//
73-
// * channel-rust-1.75-beta.toml
74-
// * channel-rust-1.75.0-beta.toml
75-
// * channel-rust-1.75.0-beta.1.toml
76-
//
77-
// Which should get ignored for now, they're not consumable via rustup yet.
78-
if file.contains("beta") && file != "channel-rust-beta.toml" {
79-
return None;
80-
}
81-
82-
// Parse the YYYY-MM-DD segment and stamp it with *current* UTC time.
83-
if let Ok(naive) = NaiveDate::parse_from_str(date_str, "%Y-%m-%d") {
84-
let published = naive
85-
.and_hms_opt(0, 0, 0)
86-
.expect("valid HMS")
87-
.and_local_timezone(Utc)
88-
.single()
89-
.unwrap();
90-
91-
// Special-case the rolling beta channel.
92-
if file == "channel-rust-beta.toml" {
93-
return Some((format!("beta-{date_str}"), published));
94-
}
95-
96-
// Otherwise pull out a semver like "1.70.0" and return it.
97-
if let Some(cap) = VERSION_RE.captures(file).and_then(|m| m.get(1)) {
98-
return Some((cap.as_str().to_owned(), published));
99-
}
100-
}
101-
102-
None
103-
}
104-
10549
/// Store the latest release commits or do nothing if all of them are
10650
/// already in the database
10751
async fn create_benchmark_request_releases(
@@ -193,33 +137,6 @@ fn sort_benchmark_requests(index: &BenchmarkRequestIndex, request_queue: &mut [B
193137
}
194138
}
195139

196-
pub trait ExtractIf<T> {
197-
fn extract_if_stable<F>(&mut self, predicate: F) -> Vec<T>
198-
where
199-
F: FnMut(&T) -> bool;
200-
}
201-
202-
/// Vec method `extract_if` is unstable, this very simple implementation
203-
/// can be deleted once it is stable
204-
impl<T> ExtractIf<T> for Vec<T> {
205-
fn extract_if_stable<F>(&mut self, mut predicate: F) -> Vec<T>
206-
where
207-
F: FnMut(&T) -> bool,
208-
{
209-
let mut extracted = Vec::new();
210-
let mut i = 0;
211-
212-
while i < self.len() {
213-
if predicate(&self[i]) {
214-
extracted.push(self.remove(i));
215-
} else {
216-
i += 1;
217-
}
218-
}
219-
extracted
220-
}
221-
}
222-
223140
/// Creates a benchmark request queue that determines in what order will
224141
/// the requests be benchmarked. The ordering should be created in such a way that
225142
/// after an in-progress request is finished, the ordering of the rest of the queue does not
@@ -301,21 +218,9 @@ pub async fn cron_main(site_ctxt: Arc<RwLock<Option<Arc<SiteCtxt>>>>, seconds: u
301218
#[cfg(test)]
302219
mod tests {
303220
use super::*;
304-
use chrono::{Datelike, Duration, NaiveDate, TimeZone, Utc};
221+
use chrono::{Datelike, Duration, TimeZone, Utc};
305222
use database::tests::run_postgres_test;
306223

307-
/// Helper: unwrap the Option, panic otherwise.
308-
fn tag(url: &str) -> String {
309-
parse_release_string(url)
310-
.expect("Some") // Option<_>
311-
.0 // take the tag
312-
}
313-
314-
/// Helper: unwrap the DateTime and keep only the YYYY-MM-DD part
315-
fn day(url: &str) -> NaiveDate {
316-
parse_release_string(url).expect("Some").1.date_naive()
317-
}
318-
319224
fn days_ago(day_str: &str) -> chrono::DateTime<Utc> {
320225
// Walk backwards until the first non-digit, then slice
321226
let days = day_str
@@ -488,55 +393,4 @@ mod tests {
488393
})
489394
.await;
490395
}
491-
492-
#[test]
493-
fn parses_stable_versions() {
494-
assert_eq!(
495-
tag("static.rust-lang.org/dist/2016-05-24/channel-rust-1.9.0.toml"),
496-
"1.9.0"
497-
);
498-
assert_eq!(
499-
day("static.rust-lang.org/dist/2016-05-24/channel-rust-1.9.0.toml"),
500-
NaiveDate::from_ymd_opt(2016, 5, 24).unwrap()
501-
);
502-
503-
assert_eq!(
504-
tag("static.rust-lang.org/dist/2025-06-26/channel-rust-1.88.0.toml"),
505-
"1.88.0"
506-
);
507-
assert_eq!(
508-
day("static.rust-lang.org/dist/2025-06-26/channel-rust-1.88.0.toml"),
509-
NaiveDate::from_ymd_opt(2025, 6, 26).unwrap()
510-
);
511-
}
512-
513-
#[test]
514-
fn parses_plain_beta_channel() {
515-
let want = "beta-2016-06-01";
516-
let url = "static.rust-lang.org/dist/2016-06-01/channel-rust-beta.toml";
517-
518-
assert_eq!(tag(url), want);
519-
assert_eq!(day(url), NaiveDate::from_ymd_opt(2016, 6, 1).unwrap());
520-
}
521-
522-
#[test]
523-
fn skips_unconsumable_channels() {
524-
// nightly never returns Anything
525-
assert!(parse_release_string(
526-
"static.rust-lang.org/dist/2016-05-31/channel-rust-nightly.toml"
527-
)
528-
.is_none());
529-
530-
// versioned-beta artefacts are skipped too
531-
for should_ignore in [
532-
"static.rust-lang.org/dist/2025-06-26/channel-rust-1.89-beta.toml",
533-
"static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.toml",
534-
"static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.2.toml",
535-
] {
536-
assert!(
537-
parse_release_string(should_ignore).is_none(),
538-
"{should_ignore} should be ignored"
539-
);
540-
}
541-
}
542396
}

site/src/job_queue/utils.rs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
use chrono::{DateTime, NaiveDate, Utc};
2+
use regex::Regex;
3+
use std::path::Path;
4+
use std::sync::LazyLock;
5+
6+
pub trait ExtractIf<T> {
7+
fn extract_if_stable<F>(&mut self, predicate: F) -> Vec<T>
8+
where
9+
F: FnMut(&T) -> bool;
10+
}
11+
12+
/// Vec method `extract_if` is unstable, this very simple implementation
13+
/// can be deleted once it is stable
14+
impl<T> ExtractIf<T> for Vec<T> {
15+
fn extract_if_stable<F>(&mut self, mut predicate: F) -> Vec<T>
16+
where
17+
F: FnMut(&T) -> bool,
18+
{
19+
let mut extracted = Vec::new();
20+
let mut i = 0;
21+
22+
while i < self.len() {
23+
if predicate(&self[i]) {
24+
extracted.push(self.remove(i));
25+
} else {
26+
i += 1;
27+
}
28+
}
29+
extracted
30+
}
31+
}
32+
33+
/// Parses strings in the following formats extracting the Date & release tag
34+
/// `static.rust-lang.org/dist/2016-05-24/channel-rust-1.9.0.toml`
35+
/// `static.rust-lang.org/dist/2016-05-31/channel-rust-nightly.toml`
36+
/// `static.rust-lang.org/dist/2016-06-01/channel-rust-beta.toml`
37+
/// `static.rust-lang.org/dist/2025-06-26/channel-rust-1.89-beta.toml`
38+
/// `static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.toml`
39+
/// `static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.2.toml`
40+
pub fn parse_release_string(url: &str) -> Option<(String, DateTime<Utc>)> {
41+
static VERSION_RE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"(\d+\.\d+\.\d+)").unwrap());
42+
43+
// Grab ".../YYYY-MM-DD/FILE.toml" components with Path helpers.
44+
let file = Path::new(url).file_name().and_then(|n| n.to_str())?;
45+
46+
let date_str = Path::new(url)
47+
.parent()
48+
.and_then(Path::file_name)
49+
.and_then(|n| n.to_str())?;
50+
51+
// No other beta releases are recognized as toolchains.
52+
//
53+
// We also have names like this:
54+
//
55+
// * channel-rust-1.75-beta.toml
56+
// * channel-rust-1.75.0-beta.toml
57+
// * channel-rust-1.75.0-beta.1.toml
58+
//
59+
// Which should get ignored for now, they're not consumable via rustup yet.
60+
if file.contains("beta") && file != "channel-rust-beta.toml" {
61+
return None;
62+
}
63+
64+
// Parse the YYYY-MM-DD segment and stamp it with *current* UTC time.
65+
if let Ok(naive) = NaiveDate::parse_from_str(date_str, "%Y-%m-%d") {
66+
let published = naive
67+
.and_hms_opt(0, 0, 0)
68+
.expect("valid HMS")
69+
.and_local_timezone(Utc)
70+
.single()
71+
.unwrap();
72+
73+
// Special-case the rolling beta channel.
74+
if file == "channel-rust-beta.toml" {
75+
return Some((format!("beta-{date_str}"), published));
76+
}
77+
78+
// Otherwise pull out a semver like "1.70.0" and return it.
79+
if let Some(cap) = VERSION_RE.captures(file).and_then(|m| m.get(1)) {
80+
return Some((cap.as_str().to_owned(), published));
81+
}
82+
}
83+
84+
None
85+
}
86+
87+
#[cfg(test)]
88+
mod tests {
89+
use super::*;
90+
use chrono::NaiveDate;
91+
92+
/// Helper: unwrap the Option, panic otherwise.
93+
fn tag(url: &str) -> String {
94+
parse_release_string(url)
95+
.expect("Some") // Option<_>
96+
.0 // take the tag
97+
}
98+
99+
/// Helper: unwrap the DateTime and keep only the YYYY-MM-DD part
100+
fn day(url: &str) -> NaiveDate {
101+
parse_release_string(url).expect("Some").1.date_naive()
102+
}
103+
104+
#[test]
105+
fn parses_stable_versions() {
106+
assert_eq!(
107+
tag("static.rust-lang.org/dist/2016-05-24/channel-rust-1.9.0.toml"),
108+
"1.9.0"
109+
);
110+
assert_eq!(
111+
day("static.rust-lang.org/dist/2016-05-24/channel-rust-1.9.0.toml"),
112+
NaiveDate::from_ymd_opt(2016, 5, 24).unwrap()
113+
);
114+
115+
assert_eq!(
116+
tag("static.rust-lang.org/dist/2025-06-26/channel-rust-1.88.0.toml"),
117+
"1.88.0"
118+
);
119+
assert_eq!(
120+
day("static.rust-lang.org/dist/2025-06-26/channel-rust-1.88.0.toml"),
121+
NaiveDate::from_ymd_opt(2025, 6, 26).unwrap()
122+
);
123+
}
124+
125+
#[test]
126+
fn parses_plain_beta_channel() {
127+
let want = "beta-2016-06-01";
128+
let url = "static.rust-lang.org/dist/2016-06-01/channel-rust-beta.toml";
129+
130+
assert_eq!(tag(url), want);
131+
assert_eq!(day(url), NaiveDate::from_ymd_opt(2016, 6, 1).unwrap());
132+
}
133+
134+
#[test]
135+
fn skips_unconsumable_channels() {
136+
// nightly never returns Anything
137+
assert!(parse_release_string(
138+
"static.rust-lang.org/dist/2016-05-31/channel-rust-nightly.toml"
139+
)
140+
.is_none());
141+
142+
// versioned-beta artefacts are skipped too
143+
for should_ignore in [
144+
"static.rust-lang.org/dist/2025-06-26/channel-rust-1.89-beta.toml",
145+
"static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.toml",
146+
"static.rust-lang.org/dist/2025-06-26/channel-rust-1.89.0-beta.2.toml",
147+
] {
148+
assert!(
149+
parse_release_string(should_ignore).is_none(),
150+
"{should_ignore} should be ignored"
151+
);
152+
}
153+
}
154+
}

0 commit comments

Comments
 (0)