mirror of
https://github.com/Noratrieb/cargo-bisect-rustc-service.git
synced 2026-01-14 16:25:01 +01:00
time and error handling
This commit is contained in:
parent
41396f19c7
commit
ae9f992ef8
5 changed files with 88 additions and 42 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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"] }
|
||||||
|
|
|
||||||
101
index.html
101
index.html
|
|
@ -19,6 +19,10 @@
|
||||||
columns: 100;
|
columns: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
.bisect-btn {
|
.bisect-btn {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
|
|
@ -76,66 +80,101 @@ 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);
|
||||||
|
|
||||||
const fetched = await fetch(`${BASE_URL}bisect?${params}`, {
|
let jobId;
|
||||||
method: "POST",
|
try {
|
||||||
body,
|
const fetched = await fetch(`${BASE_URL}bisect?${params}`, {
|
||||||
headers: {
|
method: "POST",
|
||||||
"Content-Type": "application/text",
|
body,
|
||||||
},
|
headers: {
|
||||||
});
|
"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<T> Struct<T> {
|
||||||
|
|
||||||
tryFetch();
|
tryFetch();
|
||||||
|
|
||||||
status.innerHTML = `Waiting for result, job id=${job_id}`;
|
htmlStatus.innerHTML = `Waiting for result, job id=${jobId}`;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
19
src/db.rs
19
src/db.rs
|
|
@ -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")?;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue