time and error handling

This commit is contained in:
nora 2022-09-29 21:52:56 +02:00
parent 41396f19c7
commit ae9f992ef8
No known key found for this signature in database
5 changed files with 88 additions and 42 deletions

1
Cargo.lock generated
View file

@ -748,6 +748,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"chrono",
"fallible-iterator", "fallible-iterator",
"fallible-streaming-iterator", "fallible-streaming-iterator",
"hashlink", "hashlink",

View file

@ -7,9 +7,9 @@ edition = "2021"
[dependencies] [dependencies]
axum = "0.5.16" axum = "0.5.16"
chrono = { version = "0.4.22", features = ["serde"] } chrono = { version = "0.4.22", features = ["serde", "clock"] }
color-eyre = "0.6.2" color-eyre = "0.6.2"
rusqlite = { version = "0.28.0", features = ["bundled", "uuid"] } rusqlite = { version = "0.28.0", features = ["bundled", "uuid", "chrono"] }
serde = { version = "1.0.145", features = ["derive"] } serde = { version = "1.0.145", features = ["derive"] }
tempdir = "0.3.7" tempdir = "0.3.7"
tokio = { version = "1.21.2", features = ["full"] } tokio = { version = "1.21.2", features = ["full"] }

View file

@ -19,6 +19,10 @@
columns: 100; columns: 100;
} }
.error {
color: red;
}
.bisect-btn { .bisect-btn {
width: 200px; width: 200px;
height: 50px; height: 50px;
@ -76,44 +80,55 @@ impl<T> Struct<T> {
<script> <script>
const BASE_URL = `${document.location}`; const BASE_URL = `${document.location}`;
const code = document.getElementById("code"); const htmlCode = document.getElementById("code");
const status = document.getElementById("status"); const htmlStatus = document.getElementById("status");
const result = document.getElementById("result"); const htmlResult = document.getElementById("result");
const start = document.getElementById("start"); const htmlStart = document.getElementById("start");
const end = document.getElementById("end"); const htmlEnd = document.getElementById("end");
const kind = document.getElementById("kind"); const htmlKind = document.getElementById("kind");
let bisecting = false; let bisecting = false;
function fatal(err, ...extra) {
console.error(err, ...(extra || []));
htmlStatus.innerHTML = `ERROR: ${err}`;
htmlStatus.classList.remove("hidden");
htmlStatus.classList.add("error");
bisecting = false;
}
async function bisect() { async function bisect() {
if (bisecting) { if (bisecting) {
return; return;
} }
if (!start.value.trim()) { if (!htmlStart.value.trim()) {
alert("Must provide a start"); fatal("Must provide a start");
return; return;
} }
bisecting = true; bisecting = true;
status.classList.remove("hidden"); htmlStatus.classList.remove("error");
result.classList.add("hidden"); htmlStatus.classList.remove("hidden");
status.innerText = "Sending request..."; htmlResult.classList.add("hidden");
htmlStatus.innerText = "Sending request...";
const params = new URLSearchParams(); const params = new URLSearchParams();
params.append("start", start.value.trim()); params.append("start", htmlStart.value.trim());
params.append("kind", kind.value); params.append("kind", htmlKind.value);
if (end.value.trim()) { if (htmlEnd.value.trim()) {
params.append("end", end.value.trim()); params.append("end", htmlEnd.value.trim());
} }
const body = code.value; const body = htmlCode.value;
console.log("Bisecting", body); console.log("Bisecting", body);
let jobId;
try {
const fetched = await fetch(`${BASE_URL}bisect?${params}`, { const fetched = await fetch(`${BASE_URL}bisect?${params}`, {
method: "POST", method: "POST",
body, body,
@ -121,21 +136,45 @@ impl&lt;T&gt; Struct&lt;T&gt; {
"Content-Type": "application/text", "Content-Type": "application/text",
}, },
}); });
const { job_id } = await fetched.json(); if (!fetched.ok) {
console.error(fetched);
fatal("Failed to fetch", fetched);
return;
}
const data = await fetched.json();
jobId = data?.job_id;
if (!jobId) {
fatal("Received invalid response", data);
return;
}
} catch (err) {
fatal(err);
return;
}
async function tryFetch() { async function tryFetch() {
const fetched = await fetch(`${BASE_URL}bisect/${job_id}`); let response;
const response = await fetched.json(); try {
const fetched = await fetch(`${BASE_URL}bisect/${jobId}`);
if (!fetched.ok) {
fatal("Failed to fetch", fetched);
return;
}
response = await fetched.json();
} catch (e) {
fatal(e);
return;
}
if (response.status.status !== "InProgress") { if (response.status.status !== "InProgress") {
bisecting = false; bisecting = false;
console.log(response.status.output); console.log(response.status.output);
status.classList.add("hidden"); htmlStatus.classList.add("hidden");
result.classList.remove("hidden"); htmlResult.classList.remove("hidden");
result.value = response.status.output; htmlResult.value = response.status.output;
status.innerHTML = `Bisected job ${job_id}`; htmlStatus.innerHTML = `Bisected job ${jobId}`;
} else { } else {
console.log("Waiting for bisection", response.status.status); console.log("Waiting for bisection", response.status.status);
setTimeout(tryFetch, 3000); setTimeout(tryFetch, 3000);
@ -144,7 +183,7 @@ impl&lt;T&gt; Struct&lt;T&gt; {
tryFetch(); tryFetch();
status.innerHTML = `Waiting for result, job id=${job_id}`; htmlStatus.innerHTML = `Waiting for result, job id=${jobId}`;
} }
</script> </script>
</body> </body>

View file

@ -1,6 +1,7 @@
use std::process::Output; use std::process::Output;
use std::{fs, process::Command, sync::mpsc}; use std::{fs, process::Command, sync::mpsc};
use chrono::{DateTime, Utc};
use color_eyre::eyre::{Context, ContextCompat}; use color_eyre::eyre::{Context, ContextCompat};
use color_eyre::Result; use color_eyre::Result;
use rusqlite::Connection; use rusqlite::Connection;
@ -22,6 +23,7 @@ pub enum BisectStatus {
pub struct Bisection { pub struct Bisection {
pub id: Uuid, pub id: Uuid,
pub code: String, pub code: String,
pub time: DateTime<Utc>,
pub status: BisectStatus, pub status: BisectStatus,
} }
@ -83,6 +85,7 @@ pub fn process_job(job: Job, conn: &Connection) -> Result<()> {
let mut bisect = Bisection { let mut bisect = Bisection {
id: job.id, id: job.id,
code: job.code.clone(), code: job.code.clone(),
time: Utc::now(),
status: BisectStatus::InProgress, status: BisectStatus::InProgress,
}; };
@ -169,7 +172,7 @@ fn run_bisect_for_file(input: String, options: &Options) -> Result<(Output, JobS
bisect bisect
.arg("--regress") .arg("--regress")
.arg(options.kind.as_deref().unwrap_or("ice")); // FIXME Make this configurable .arg(options.kind.as_deref().unwrap_or("ice"));
bisect.env("RUST_LOG", "error"); // overwrite RUST_LOG bisect.env("RUST_LOG", "error"); // overwrite RUST_LOG

View file

@ -11,6 +11,7 @@ pub fn setup(conn: &Connection) -> color_eyre::Result<()> {
job_id STRING PRIMARY KEY, job_id STRING PRIMARY KEY,
code STRING NOT NULL, code STRING NOT NULL,
status INTEGER NOT NULL DEFAULT 0, status INTEGER NOT NULL DEFAULT 0,
time TIME NOT NULL,
stdout_stderr STRING -- stdout or stderr depending on the status stdout_stderr STRING -- stdout or stderr depending on the status
)", )",
(), (),
@ -34,8 +35,8 @@ pub fn add_bisection(conn: &Connection, bisect: &Bisection) -> color_eyre::Resul
let (status, stdout_stderr) = status_to_sql(&bisect.status); let (status, stdout_stderr) = status_to_sql(&bisect.status);
conn.execute( conn.execute(
"INSERT INTO bisect (job_id, code, status, stdout_stderr) VALUES (?1, ?2, ?3, ?4)", "INSERT INTO bisect (job_id, code, status, time, stdout_stderr) VALUES (?1, ?2, ?3, ?4, ?5)",
(bisect.id, &bisect.code, status, stdout_stderr), (bisect.id, &bisect.code, status, &bisect.time, stdout_stderr),
) )
.wrap_err("insert into database") .wrap_err("insert into database")
.map(drop) .map(drop)
@ -54,7 +55,7 @@ pub fn update_bisection_status(conn: &Connection, bisect: &Bisection) -> color_e
pub fn get_bisections(conn: &Connection) -> color_eyre::Result<Vec<Bisection>> { pub fn get_bisections(conn: &Connection) -> color_eyre::Result<Vec<Bisection>> {
let mut select = conn let mut select = conn
.prepare("SELECT job_id, code, status, stdout_stderr FROM bisect") .prepare("SELECT job_id, code, status, time, stdout_stderr FROM bisect")
.wrap_err("preparing select")?; .wrap_err("preparing select")?;
let iter = select let iter = select
@ -65,13 +66,14 @@ pub fn get_bisections(conn: &Connection) -> color_eyre::Result<Vec<Bisection>> {
status: match row.get(2)? { status: match row.get(2)? {
0 => BisectStatus::InProgress, 0 => BisectStatus::InProgress,
1 => BisectStatus::Error { 1 => BisectStatus::Error {
output: row.get(3)?, output: row.get(4)?,
}, },
2 => BisectStatus::Success { 2 => BisectStatus::Success {
output: row.get(3)?, output: row.get(4)?,
}, },
_ => return Err(rusqlite::Error::InvalidQuery), // actually not lol _ => return Err(rusqlite::Error::InvalidQuery), // actually not lol
}, },
time: row.get(3)?,
}) })
}) })
.wrap_err("getting bisections from db query")?; .wrap_err("getting bisections from db query")?;
@ -82,7 +84,7 @@ pub fn get_bisections(conn: &Connection) -> color_eyre::Result<Vec<Bisection>> {
pub fn get_bisection(conn: &Connection, id: Uuid) -> color_eyre::Result<Option<Bisection>> { pub fn get_bisection(conn: &Connection, id: Uuid) -> color_eyre::Result<Option<Bisection>> {
let mut select = conn let mut select = conn
.prepare("SELECT job_id, code, status, stdout_stderr FROM bisect WHERE job_id = ?1") .prepare("SELECT job_id, code, status, time, stdout_stderr FROM bisect WHERE job_id = ?1")
.wrap_err("preparing select")?; .wrap_err("preparing select")?;
let mut iter = select let mut iter = select
@ -93,13 +95,14 @@ pub fn get_bisection(conn: &Connection, id: Uuid) -> color_eyre::Result<Option<B
status: match row.get(2)? { status: match row.get(2)? {
0 => BisectStatus::InProgress, 0 => BisectStatus::InProgress,
1 => BisectStatus::Error { 1 => BisectStatus::Error {
output: row.get(3)?, output: row.get(4)?,
}, },
2 => BisectStatus::Success { 2 => BisectStatus::Success {
output: row.get(3)?, output: row.get(4)?,
}, },
_ => return Err(rusqlite::Error::InvalidQuery), // actually not lol _ => return Err(rusqlite::Error::InvalidQuery), // actually not lol
}, },
time: row.get(3)?,
}) })
}) })
.wrap_err("getting bisections from db query")?; .wrap_err("getting bisections from db query")?;