mirror of
https://seed.radicle.dev/rad:z3qg5TKmN83afz2fj9z3fQjU8vaYE.git
synced 2026-10-18 19:10:37 +08:00
feat: add a table of contents to the run log
Signed-off-by: Lars Wirzenius <liw@liw.fi>
This commit is contained in:
@@ -17,6 +17,13 @@ fn main() {
|
||||
"This is stdout".as_bytes(),
|
||||
"Error messages go here".as_bytes(),
|
||||
);
|
||||
run_log.runcmd(
|
||||
&["cargo", "check", "--all-targets", "--workspace"],
|
||||
Path::new("/tmp"),
|
||||
0,
|
||||
"This is stdout".as_bytes(),
|
||||
"Error messages go here".as_bytes(),
|
||||
);
|
||||
|
||||
run_log.write().expect("write html log");
|
||||
}
|
||||
|
||||
+60
-24
@@ -67,7 +67,6 @@ impl RunLog {
|
||||
let mut doc = Document::default();
|
||||
|
||||
doc.push_to_head(&Element::new(Tag::Title).with_text(title));
|
||||
|
||||
doc.push_to_body(&Element::new(Tag::H1).with_text(title));
|
||||
|
||||
let mut ul = Element::new(Tag::Ul);
|
||||
@@ -95,15 +94,20 @@ impl RunLog {
|
||||
doc.push_to_body(&error);
|
||||
}
|
||||
|
||||
for cmd in self.commands.iter() {
|
||||
cmd.format(&mut doc);
|
||||
}
|
||||
|
||||
if self.timeout {
|
||||
let timeout = Element::new(Tag::P).with_text("Last command timed out");
|
||||
doc.push_to_body(&timeout);
|
||||
}
|
||||
|
||||
let mut toc = ToC::default();
|
||||
let mut body = Element::new(Tag::Div);
|
||||
for cmd in self.commands.iter() {
|
||||
cmd.format(&mut body, &mut toc);
|
||||
}
|
||||
|
||||
doc.push_to_body(&toc.as_html());
|
||||
doc.push_to_body(&body);
|
||||
|
||||
let html = format!("{}", doc);
|
||||
std::fs::write(&self.filename, html.as_bytes())
|
||||
.map_err(|e| RunLogError::Write(self.filename.clone(), e))?;
|
||||
@@ -134,14 +138,16 @@ impl Command {
|
||||
self.argv.as_slice().join(" ")
|
||||
}
|
||||
|
||||
fn format(&self, doc: &mut Document) {
|
||||
doc.push_to_body(
|
||||
&Element::new(Tag::H2)
|
||||
.with_text("Run: ")
|
||||
.with_child(Element::new(Tag::Code).with_text(&self.command())),
|
||||
fn format(&self, body: &mut Element, toc: &mut ToC) {
|
||||
body.push_child(
|
||||
&toc.push(
|
||||
Element::new(Tag::Span)
|
||||
.with_text("Run: ")
|
||||
.with_child(Element::new(Tag::Code).with_text(&self.command())),
|
||||
),
|
||||
);
|
||||
|
||||
doc.push_to_body(&Element::new(Tag::P).with_text("Command arguments:"));
|
||||
body.push_child(&Element::new(Tag::P).with_text("Command arguments:"));
|
||||
let mut ul = Element::new(Tag::Ul);
|
||||
for arg in self.argv.iter() {
|
||||
ul.push_child(
|
||||
@@ -149,34 +155,64 @@ impl Command {
|
||||
.with_child(Element::new(Tag::Code).with_text(&format!("{:?}", arg))),
|
||||
);
|
||||
}
|
||||
doc.push_to_body(&ul);
|
||||
body.push_child(&ul);
|
||||
|
||||
doc.push_to_body(
|
||||
body.push_child(
|
||||
&Element::new(Tag::P)
|
||||
.with_text("In directory: ")
|
||||
.with_child(Element::new(Tag::Code).with_text(&format!("{}", self.cwd.display()))),
|
||||
);
|
||||
|
||||
doc.push_to_body(&Element::new(Tag::P).with_text(&format!("Exit code: {}", self.exit)));
|
||||
body.push_child(&Element::new(Tag::P).with_text(&format!("Exit code: {}", self.exit)));
|
||||
|
||||
self.output(doc, "Stdout:", &self.stdout);
|
||||
self.output(doc, "Stderr:", &self.stderr);
|
||||
self.output(body, "Stdout:", &self.stdout);
|
||||
self.output(body, "Stderr:", &self.stderr);
|
||||
}
|
||||
|
||||
fn output(&self, doc: &mut Document, stream: &str, data: &[u8]) {
|
||||
fn output(&self, body: &mut Element, stream: &str, data: &[u8]) {
|
||||
if !data.is_empty() {
|
||||
doc.push_to_body(&Element::new(Tag::P).with_text(stream));
|
||||
doc.push_to_body(
|
||||
&Element::new(Tag::P).with_child(
|
||||
Element::new(Tag::Blockquote).with_child(
|
||||
Element::new(Tag::Pre).with_text(&String::from_utf8_lossy(data)),
|
||||
),
|
||||
),
|
||||
body.push_child(&Element::new(Tag::P).with_text(stream));
|
||||
body.push_child(
|
||||
&Element::new(Tag::Blockquote)
|
||||
.with_child(Element::new(Tag::Pre).with_text(&String::from_utf8_lossy(data))),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct ToC {
|
||||
counter: usize,
|
||||
headings: Vec<(String, Element)>,
|
||||
}
|
||||
|
||||
impl ToC {
|
||||
fn push(&mut self, content: Element) -> Element {
|
||||
self.counter += 1;
|
||||
let anchor = format!("h{}", self.counter);
|
||||
self.headings.push((anchor.clone(), content.clone()));
|
||||
Element::new(Tag::H2)
|
||||
.with_attribute("id", &format!("h{}", self.counter))
|
||||
.with_child(content)
|
||||
}
|
||||
|
||||
fn as_html(&self) -> Element {
|
||||
let mut toc =
|
||||
Element::new(Tag::Div).with_child(Element::new(Tag::H2).with_text("Table of contents"));
|
||||
let mut list = Element::new(Tag::Ul);
|
||||
for (anchor, content) in self.headings.iter() {
|
||||
let entry = Element::new(Tag::Li).with_child(
|
||||
Element::new(Tag::A)
|
||||
.with_attribute("href", &format!("#{anchor}"))
|
||||
.with_child(content.clone()),
|
||||
);
|
||||
list.push_child(&entry);
|
||||
}
|
||||
toc.push_child(&list);
|
||||
toc
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum RunLogError {
|
||||
#[error("programming error: missing field for run log {0}")]
|
||||
|
||||
Reference in New Issue
Block a user