diff --git a/src/build.rs b/src/build.rs
index 9fcb5b3..1e4aa13 100644
--- a/src/build.rs
+++ b/src/build.rs
@@ -57,7 +57,7 @@ async fn background_builder_inner(db: &Db, nightly_cache: &mut NightlyCache) ->
match next {
Some((nightly, mode)) => {
info!(%nightly, %mode, "Building next nightly");
- let result = build_every_target_for_toolchain(&db, &nightly, mode)
+ let result = build_every_target_for_toolchain(db, &nightly, mode)
.await
.wrap_err_with(|| format!("building targets for toolchain {nightly}"));
if let Err(err) = result {
@@ -69,7 +69,7 @@ async fn background_builder_inner(db: &Db, nightly_cache: &mut NightlyCache) ->
}
None => {
info!("No new nightly, waiting for an hour to try again");
- tokio::time::sleep(Duration::from_secs(1 * 60 * 60)).await;
+ tokio::time::sleep(Duration::from_secs(60 * 60)).await;
}
}
Ok(())
@@ -191,7 +191,7 @@ pub async fn build_every_target_for_toolchain(
let results = futures::stream::iter(
targets
.iter()
- .map(|target| build_single_target(&db, nightly, target, mode)),
+ .map(|target| build_single_target(db, nightly, target, mode)),
)
.buffer_unordered(concurrent)
.collect::>>()
@@ -266,7 +266,7 @@ async fn build_target(
BuildMode::Core => {
let init = Command::new("cargo")
.args(["init", "--lib", "--name", "target-test"])
- .current_dir(&tmpdir)
+ .current_dir(tmpdir)
.output()
.await
.wrap_err("spawning cargo init")?;
@@ -282,7 +282,7 @@ async fn build_target(
.arg(format!("+{toolchain}"))
.args(["build", "-Zbuild-std=core", "--release"])
.args(["--target", target])
- .current_dir(&tmpdir)
+ .current_dir(tmpdir)
.output()
.await
.wrap_err("spawning cargo build")?
@@ -291,7 +291,7 @@ async fn build_target(
.arg(format!("+{toolchain}"))
.args(["miri", "setup"])
.args(["--target", target])
- .current_dir(&tmpdir)
+ .current_dir(tmpdir)
.env("MIRI_SYSROOT", tmpdir)
.output()
.await
diff --git a/src/db.rs b/src/db.rs
index 75a87a4..3bc06f5 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -33,7 +33,7 @@ impl Display for BuildMode {
}
}
-#[derive(sqlx::FromRow, Serialize, Deserialize)]
+#[derive(sqlx::FromRow, Serialize, Deserialize, Clone)]
pub struct BuildInfo {
pub nightly: String,
pub target: String,
@@ -81,7 +81,7 @@ impl Db {
let conn = Pool::connect_with(db_opts)
.await
- .wrap_err_with(|| format!("opening db from `{}`", path))?;
+ .wrap_err_with(|| format!("opening db from `{path}`"))?;
Ok(Self { conn })
}
@@ -117,6 +117,16 @@ impl Db {
.wrap_err("getting history for single target")
}
+ pub async fn history_for_nightly(&self, nightly: &str) -> Result> {
+ sqlx::query_as::<_, BuildInfo>(
+ "SELECT nightly, target, status, mode FROM build_info WHERE nightly = ?",
+ )
+ .bind(nightly)
+ .fetch_all(&self.conn)
+ .await
+ .wrap_err("getting history for single nightly")
+ }
+
pub async fn target_list(&self) -> Result> {
#[derive(sqlx::FromRow)]
struct TargetName {
@@ -130,6 +140,21 @@ impl Db {
.map(|elems| elems.into_iter().map(|elem| elem.target).collect())
}
+ pub async fn nightly_list(&self) -> Result> {
+ #[derive(sqlx::FromRow)]
+ struct NightlyName {
+ nightly: String,
+ }
+
+ sqlx::query_as::<_, NightlyName>(
+ "SELECT DISTINCT nightly FROM build_info ORDER BY nightly DESC",
+ )
+ .fetch_all(&self.conn)
+ .await
+ .wrap_err("getting list of all targets")
+ .map(|elems| elems.into_iter().map(|elem| elem.nightly).collect())
+ }
+
pub async fn build_status_full(
&self,
nightly: &str,
diff --git a/src/nightlies.rs b/src/nightlies.rs
index 7493870..28498d8 100644
--- a/src/nightlies.rs
+++ b/src/nightlies.rs
@@ -43,7 +43,7 @@ impl Nightlies {
.last()
.ok_or_eyre("did not find any nightlies in manifests.txt")?;
- for nightly in guess_more_recent_nightlies(&latest)? {
+ for nightly in guess_more_recent_nightlies(latest)? {
if nightly_exists(&nightly, cache)
.await
.wrap_err_with(|| format!("checking whether {nightly} exists"))?
@@ -54,7 +54,10 @@ impl Nightlies {
all.reverse();
- debug!("Loaded {} nightlies from the manifest and manual additions", all.len());
+ debug!(
+ "Loaded {} nightlies from the manifest and manual additions",
+ all.len()
+ );
Ok(Self { all })
}
diff --git a/src/web.rs b/src/web.rs
index c287ce4..ff8db9b 100644
--- a/src/web.rs
+++ b/src/web.rs
@@ -4,7 +4,7 @@ use axum::{
extract::{Query, State},
http::StatusCode,
response::{Html, IntoResponse, Response},
- routing::{get, post},
+ routing::get,
Json, Router,
};
use color_eyre::{eyre::Context, Result};
@@ -23,11 +23,11 @@ pub async fn webserver(db: Db) -> Result<()> {
.route("/", get(web_root))
.route("/build", get(web_build))
.route("/target", get(web_target))
+ .route("/nightly", get(web_nightly))
.route("/full-table", get(web_full_table))
.route("/index.css", get(index_css))
.route("/index.js", get(index_js))
.route("/full-mega-monster", get(full_mega_monster))
- .route("/trigger-build", post(trigger_build))
.with_state(AppState { db });
info!("Serving website on port 3000 (commit {})", crate::VERSION);
@@ -144,24 +144,95 @@ async fn web_target(State(state): State, Query(query): Query, Query(query): Query) -> Response {
+ use askama::Template;
+ #[derive(askama::Template)]
+ #[template(path = "nightly.html")]
+ struct NightlyPage {
+ nightly: String,
+ version: &'static str,
+ builds: Vec<(String, Option, Option)>,
+ core_failures: usize,
+ std_failures: usize,
+ }
+
+ match state.db.history_for_nightly(&query.nightly).await {
+ Ok(builds) => {
+ let mut builds_grouped =
+ HashMap::, Option)>::new();
+ for build in &builds {
+ let v = builds_grouped.entry(build.target.clone()).or_default();
+ match build.mode {
+ BuildMode::Core => v.0 = Some(build.clone()),
+ BuildMode::MiriStd => v.1 = Some(build.clone()),
+ }
+ }
+
+ let mut std_failures = 0;
+ let mut core_failures = 0;
+ for build in builds {
+ if build.status == Status::Error {
+ match build.mode {
+ BuildMode::Core => core_failures += 1,
+ BuildMode::MiriStd => std_failures += 1,
+ }
+ }
+ }
+
+ let mut builds = builds_grouped
+ .into_iter()
+ .map(|(k, (v1, v2))| (k, v1, v2))
+ .collect::>();
+ builds.sort_by_cached_key(|build| build.0.clone());
+
+ let page = NightlyPage {
+ nightly: query.nightly,
+ version: crate::VERSION,
+ builds,
+ std_failures,
+ core_failures,
+ };
+
+ Html(page.render().unwrap()).into_response()
+ }
+ Err(err) => {
+ error!(?err, "Error loading target state");
+ StatusCode::INTERNAL_SERVER_ERROR.into_response()
+ }
+ }
+}
+
async fn web_root(State(state): State) -> impl IntoResponse {
use askama::Template;
#[derive(askama::Template)]
#[template(path = "index.html")]
struct RootPage {
targets: Vec,
+ nightlies: Vec,
version: &'static str,
}
match state.db.target_list().await {
- Ok(targets) => {
- let page = RootPage {
- targets,
- version: crate::VERSION,
- };
+ Ok(targets) => match state.db.nightly_list().await {
+ Ok(nightlies) => {
+ let page = RootPage {
+ targets,
+ nightlies,
+ version: crate::VERSION,
+ };
- Html(page.render().unwrap()).into_response()
- }
+ Html(page.render().unwrap()).into_response()
+ }
+ Err(err) => {
+ error!(?err, "Error loading nightly state");
+ StatusCode::INTERNAL_SERVER_ERROR.into_response()
+ }
+ },
Err(err) => {
error!(?err, "Error loading target state");
StatusCode::INTERNAL_SERVER_ERROR.into_response()
@@ -203,22 +274,6 @@ struct TriggerBuildBody {
nightly: String,
}
-#[axum::debug_handler]
-async fn trigger_build(
- State(_state): State,
- _body: Json,
-) -> StatusCode {
- return StatusCode::BAD_REQUEST;
- // tokio::spawn(async move {
- // let result = build::build_every_target_for_toolchain(&state.db, &body.nightly).await;
- // if let Err(err) = result {
- // error!(?err, "Error while building");
- // }
- // });
- //
- // StatusCode::ACCEPTED
-}
-
impl Status {
fn to_emoji(&self) -> &'static str {
match self {
diff --git a/static/build.html b/static/build.html
index 31af71d..db0ada4 100644
--- a/static/build.html
+++ b/static/build.html
@@ -1,4 +1,4 @@
-
+
@@ -19,6 +19,12 @@
{{stderr}}
+
+ Build history for target {{target}}
+
+
+ Build state for nightly {{nightly}}
+
-
+ Nightlies
+
+
+ To view a list of all nightlies, check
+ the list at the end.
+
+
+ Targets
+
+
{% for target in targets %}
-
{{ target }}
@@ -30,6 +39,18 @@
{% endfor %}
+
+ All Nightlies
+
+
+ {% for nightly in nightlies %}
+ -
+ {{ nightly }}
+
+ {% endfor %}
+
+
+