diff --git a/.gitignore b/.gitignore index 54e7505..173b3ff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ /target /targets /results -/db.sqlite* +/db.sqlite diff --git a/build.rs b/build.rs index ba68507..232ad4d 100644 --- a/build.rs +++ b/build.rs @@ -31,10 +31,6 @@ fn try_get_commit() -> color_eyre::Result { } fn has_no_changes() -> color_eyre::Result { - if std::env::var("DOES_IT_BUILD_OVERRIDE_VERSION").is_ok() { - return Ok(true); - } - Ok(std::process::Command::new("git") .args(["diff", "--no-ext-diff", "--quiet", "--exit-code"]) .output()? diff --git a/migrations/20250704160556_reset-missing-target-cpu.sql b/migrations/20250704160556_reset-missing-target-cpu.sql deleted file mode 100644 index 76d96a5..0000000 --- a/migrations/20250704160556_reset-missing-target-cpu.sql +++ /dev/null @@ -1,8 +0,0 @@ --- Add migration script here - -ALTER TABLE build_info - ADD COLUMN rustflags VARCHAR; - -DELETE FROM build_info WHERE target IN ('avr-none', 'amdgcn-amd-amdhsa') AND mode = 'core'; - -DELETE FROM finished_nightly WHERE nightly > '2025-02-11'; diff --git a/src/build.rs b/src/build.rs index e2d35f2..32fa1e1 100644 --- a/src/build.rs +++ b/src/build.rs @@ -15,25 +15,9 @@ use tracing::{debug, error, info}; use crate::{ db::{BuildMode, Db, FullBuildInfo, Status}, - nightlies::Nightlies, + nightlies::{Nightlies, NightlyCache}, }; -struct CustomBuildFlags { - target: &'static str, - flags: &'static [&'static str], -} - -const CUSTOM_CORE_FLAGS: &[CustomBuildFlags] = &[ - CustomBuildFlags { - target: "avr-none", - flags: &["-Ctarget-cpu=atmega328p"], - }, - CustomBuildFlags { - target: "amdgcn-amd-amdhsa", - flags: &["-Ctarget-cpu=gfx1100"], - }, -]; - pub struct Toolchain(String); impl Toolchain { pub fn from_nightly(nightly: &str) -> Self { @@ -52,15 +36,18 @@ impl Display for Toolchain { } pub async fn background_builder(db: Db) -> Result<()> { + let mut nightly_cache = NightlyCache::default(); loop { - if let Err(err) = background_builder_inner(&db).await { + if let Err(err) = background_builder_inner(&db, &mut nightly_cache).await { error!("error in background builder: {err}"); } } } -async fn background_builder_inner(db: &Db) -> Result<()> { - let nightlies = Nightlies::fetch().await.wrap_err("fetching nightlies")?; +async fn background_builder_inner(db: &Db, nightly_cache: &mut NightlyCache) -> Result<()> { + let nightlies = Nightlies::fetch(nightly_cache) + .await + .wrap_err("fetching nightlies")?; let already_finished = db .finished_nightlies() .await @@ -257,7 +244,6 @@ async fn build_single_target(db: &Db, nightly: &str, target: &str, mode: BuildMo status: result.status, stderr: result.stderr, mode, - rustflags: result.rustflags, }) .await?; @@ -267,7 +253,6 @@ async fn build_single_target(db: &Db, nightly: &str, target: &str, mode: BuildMo struct BuildResult { status: Status, stderr: String, - rustflags: Option, } /// Build a target core in a temporary directory and see whether it passes or not. @@ -277,8 +262,6 @@ async fn build_target( target: &str, mode: BuildMode, ) -> Result { - let mut rustflags = None; - let output = match mode { BuildMode::Core => { let init = Command::new("cargo") @@ -295,22 +278,11 @@ async fn build_target( std::fs::write(&librs, "#![no_std]\n") .wrap_err_with(|| format!("writing to {}", librs.display()))?; - let mut cmd = Command::new("cargo"); - cmd.arg(format!("+{toolchain}")) + Command::new("cargo") + .arg(format!("+{toolchain}")) .args(["build", "-Zbuild-std=core", "--release"]) - .args(["--target", target]); - - let extra_flags = CUSTOM_CORE_FLAGS - .iter() - .find(|flags| flags.target == target); - - if let Some(extra_flags) = extra_flags { - let flags = extra_flags.flags.join(" "); - cmd.env("RUSTFLAGS", &flags); - rustflags = Some(flags); - } - - cmd.current_dir(tmpdir) + .args(["--target", target]) + .current_dir(tmpdir) .output() .await .wrap_err("spawning cargo build")? @@ -336,9 +308,5 @@ async fn build_target( info!("Finished build"); - Ok(BuildResult { - status, - stderr, - rustflags, - }) + Ok(BuildResult { status, stderr }) } diff --git a/src/db.rs b/src/db.rs index 73aa95f..42c1811 100644 --- a/src/db.rs +++ b/src/db.rs @@ -48,7 +48,6 @@ pub struct FullBuildInfo { pub status: Status, pub stderr: String, pub mode: BuildMode, - pub rustflags: Option, } #[derive(Debug, PartialEq, Clone, Copy, sqlx::Type, Serialize, Deserialize)] @@ -96,14 +95,13 @@ impl Db { pub async fn insert(&self, info: FullBuildInfo) -> Result<()> { sqlx::query( - "INSERT INTO build_info (nightly, target, status, stderr, mode, rustflags) VALUES (?, ?, ?, ?, ?, ?);", + "INSERT INTO build_info (nightly, target, status, stderr, mode) VALUES (?, ?, ?, ?, ?);", ) .bind(info.nightly) .bind(info.target) .bind(info.status) .bind(info.stderr) .bind(info.mode) - .bind(info.rustflags) .execute(&self.conn) .await .wrap_err("inserting build info into database")?; @@ -175,7 +173,7 @@ impl Db { mode: BuildMode, ) -> Result> { let result = sqlx::query_as::<_, FullBuildInfo>( - "SELECT nightly, target, status, stderr, mode, rustflags FROM build_info + "SELECT nightly, target, status, stderr, mode FROM build_info WHERE nightly = ? AND target = ? AND mode = ?", ) .bind(nightly) diff --git a/src/nightlies.rs b/src/nightlies.rs index cf67977..f6675dd 100644 --- a/src/nightlies.rs +++ b/src/nightlies.rs @@ -1,13 +1,21 @@ use std::collections::HashSet; use std::hash::RandomState; -use color_eyre::eyre::Context; +use color_eyre::eyre::{Context, OptionExt}; use color_eyre::Result; +use reqwest::StatusCode; +use time::Duration; use tracing::debug; use crate::db::{BuildMode, FinishedNightly}; -const EARLIEST_CUTOFF_DATE: &str = "2023-01-01"; +const EARLIEST_CUTOFF_DATE: &str = "2022-01-01"; + +#[derive(Default)] +pub struct NightlyCache { + /// Nightlies that exist. + exists: HashSet, +} /// All nightlies that exist. pub struct Nightlies { @@ -15,7 +23,7 @@ pub struct Nightlies { } impl Nightlies { - pub async fn fetch() -> Result { + pub async fn fetch(cache: &mut NightlyCache) -> Result { let manifests = reqwest::get("https://static.rust-lang.org/manifests.txt") .await .wrap_err("fetching https://static.rust-lang.org/manifests.txt")? @@ -27,7 +35,24 @@ impl Nightlies { .filter(|date| date.as_str() > EARLIEST_CUTOFF_DATE) .collect::>(); - all.sort_by(|a, b| b.cmp(a)); // Reverse sort. + all.sort(); + + // The manifests is only updated weekly, which means new nightlies won't be contained. + // We probe for their existence. + let latest = all + .last() + .ok_or_eyre("did not find any nightlies in manifests.txt")?; + + for nightly in guess_more_recent_nightlies(latest)? { + if nightly_exists(&nightly, cache) + .await + .wrap_err_with(|| format!("checking whether {nightly} exists"))? + { + all.push(nightly); + } + } + + all.reverse(); debug!( "Loaded {} nightlies from the manifest and manual additions", @@ -67,6 +92,31 @@ fn nightlies_from_manifest(manifest: &str) -> Vec { .collect() } +fn guess_more_recent_nightlies(latest: &str) -> Result> { + let format = time::macros::format_description!("[year]-[month]-[day]"); + let latest = time::Date::parse(latest, format).wrap_err("latest nightly has invalid format")?; + + // manifests.txt is updated weekly, so let's try 8 just in case. + Ok((1..=8) + .filter_map(|offset| latest.checked_add(Duration::days(offset))) + .map(|date| date.format(format).unwrap()) + .collect()) +} + +async fn nightly_exists(nightly: &str, cache: &mut NightlyCache) -> Result { + if cache.exists.contains(nightly) { + return Ok(true); + } + let url = format!("https://static.rust-lang.org/dist/{nightly}/channel-rust-nightly.toml"); + let resp = reqwest::get(&url).await.wrap_err("fetching channel")?; + debug!(%nightly, %url, status = %resp.status(), "Checked whether a recent nightly exists"); + let exists = resp.status() == StatusCode::OK; + if exists { + cache.exists.insert(nightly.to_owned()); + } + Ok(exists) +} + #[cfg(test)] mod tests { #[test] @@ -79,4 +129,22 @@ static.rust-lang.org/dist/2024-08-23/channel-rust-nightly.toml"; let nightlies = super::nightlies_from_manifest(&test_manifest); assert_eq!(nightlies, vec!["2024-08-22", "2024-08-23"]); } + + #[test] + fn guess() { + let nightlies = super::guess_more_recent_nightlies("2024-08-28").unwrap(); + assert_eq!( + nightlies, + [ + "2024-08-29", + "2024-08-30", + "2024-08-31", + "2024-09-01", + "2024-09-02", + "2024-09-03", + "2024-09-04", + "2024-09-05", + ] + ); + } } diff --git a/src/web.rs b/src/web.rs index 0866c46..4bb4221 100644 --- a/src/web.rs +++ b/src/web.rs @@ -41,19 +41,6 @@ struct BuildQuery { } async fn web_build(State(state): State, Query(query): Query) -> Response { - use askama::Template; - #[derive(askama::Template)] - #[template(path = "build.html")] - struct BuildPage { - nightly: String, - target: String, - stderr: String, - mode: BuildMode, - rustflags: Option, - version: &'static str, - status: Status, - } - match state .db .build_status_full( @@ -64,16 +51,15 @@ async fn web_build(State(state): State, Query(query): Query { - let page = BuildPage { - nightly: query.nightly, - target: query.target, - stderr: build.stderr, - mode: build.mode, - rustflags: build.rustflags, - version: crate::VERSION, - status: build.status, - }; - Html(page.render().unwrap()).into_response() + let page = include_str!("../static/build.html") + .replace("{{nightly}}", &query.nightly) + .replace("{{target}}", &query.target) + .replace("{{stderr}}", &build.stderr) + .replace("{{mode}}", &build.mode.to_string()) + .replace("{{version}}", crate::VERSION) + .replace("{{status}}", &build.status.to_string()); + + Html(page).into_response() } Ok(None) => StatusCode::NOT_FOUND.into_response(), Err(err) => { @@ -86,7 +72,6 @@ async fn web_build(State(state): State, Query(query): Query, } async fn web_target(State(state): State, Query(query): Query) -> Response { @@ -98,11 +83,8 @@ async fn web_target(State(state): State, Query(query): Query, Option)>, - showing_failures: bool, } - let filter_failures = query.failures.unwrap_or(false); - match state.db.history_for_target(&query.target).await { Ok(builds) => { let latest_core = builds @@ -140,10 +122,6 @@ async fn web_target(State(state): State, Query(query): Query>(); builds.sort_by_cached_key(|build| Reverse(build.0.clone())); @@ -152,7 +130,6 @@ async fn web_target(State(state): State, Query(query): Query, Query(query): Query, } async fn web_nightly(State(state): State, Query(query): Query) -> Response { @@ -182,11 +158,8 @@ async fn web_nightly(State(state): State, Query(query): Query, std_broken: Option, - showing_failures: bool, } - let filter_failures = query.failures.unwrap_or(false); - match state.db.history_for_nightly(&query.nightly).await { Ok(builds) => match state.db.nightly_info(&query.nightly).await { Ok(info) => { @@ -214,10 +187,6 @@ async fn web_nightly(State(state): State, Query(query): Query>(); builds.sort_by_cached_key(|build| build.0.clone()); @@ -238,7 +207,6 @@ async fn web_nightly(State(state): State, Query(query): Query) -> bool { - !filter_failures - || build - .as_ref() - .is_some_and(|build| build.status == Status::Error) -} diff --git a/templates/build.html b/static/build.html similarity index 81% rename from templates/build.html rename to static/build.html index 4e28ced..db0ada4 100644 --- a/templates/build.html +++ b/static/build.html @@ -13,27 +13,17 @@

Build results for nightly-{{nightly}} target {{target}} {{mode}}

- Home
{{status}}
- {% if let Some(rustflags) = rustflags %} -

- Using rustflags: {{rustflags}} -

- {% endif %}
 {{stderr}}
     

- Build history for target {{target}} + Build history for target {{target}}

- Build state for nightly {{nightly}} + Build state for nightly {{nightly}}