Compare commits

..

10 Commits

Author SHA1 Message Date
Tom Alexander
cb5838345e Merge branch 'style_tables'
All checks were successful
build-natter Build build-natter has succeeded
2023-12-22 18:07:46 -05:00
Tom Alexander
1107a653cf Add borders to the table groups. 2023-12-22 18:06:55 -05:00
Tom Alexander
95d4ee7080 Render the table groups. 2023-12-22 18:06:55 -05:00
Tom Alexander
fa2dd96f78 Update intermediate phase for table groups. 2023-12-22 18:00:07 -05:00
Tom Alexander
7741e192f5 Group table rows into sections. 2023-12-22 00:08:06 -05:00
Tom Alexander
5dfd46852f Add some basic styling to tables. 2023-12-21 21:59:52 -05:00
Tom Alexander
88e10010d8 Remove extra workspace from tekton pipeline.
Some checks failed
build-natter Build build-natter has failed
2023-12-21 20:36:03 -05:00
Tom Alexander
52c564d4fd Merge branch 'docker' 2023-12-21 20:29:00 -05:00
Tom Alexander
f7874c1843 Add lighthouse job to build the natter images. 2023-12-21 20:25:46 -05:00
Tom Alexander
40120667f7 Add a Dockerfile for building and running natter. 2023-12-21 20:04:04 -05:00
18 changed files with 376 additions and 8 deletions

3
.dockerignore Normal file
View File

@@ -0,0 +1,3 @@
**/.git
target/
org_test_documents/

View File

@@ -0,0 +1,151 @@
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: build-natter
spec:
pipelineSpec:
params:
- name: image-name
description: The name for the built image
type: string
- name: path-to-image-context
description: The path to the build context
type: string
- name: path-to-dockerfile
description: The path to the Dockerfile
type: string
tasks:
- name: report-pending
taskRef:
name: gitea-set-status
runAfter:
- fetch-repository
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
- name: REPO_FULL_NAME
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
- name: GITEA_HOST_URL
value: code.fizz.buzz
- name: SHA
value: "$(tasks.fetch-repository.results.commit)"
- name: DESCRIPTION
value: "Build $(params.JOB_NAME) has started"
- name: STATE
value: pending
- name: TARGET_URL
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
- name: fetch-repository
taskRef:
name: git-clone
workspaces:
- name: output
workspace: git-source
params:
- name: url
value: $(params.REPO_URL)
- name: revision
value: $(params.PULL_BASE_SHA)
- name: deleteExisting
value: "true"
- name: build-image-runner
taskRef:
name: kaniko
params:
- name: IMAGE
value: "$(params.image-name):$(tasks.fetch-repository.results.commit)"
- name: CONTEXT
value: $(params.path-to-image-context)
- name: DOCKERFILE
value: $(params.path-to-dockerfile)
- name: BUILDER_IMAGE
value: "gcr.io/kaniko-project/executor:v1.12.1"
- name: EXTRA_ARGS
value:
- "--destination=$(params.image-name)" # Also write the :latest image
- --cache=true
- --cache-copy-layers
- --cache-repo=harbor.fizz.buzz/kanikocache/cache
- --use-new-run # Should result in a speed-up
- --reproducible # To remove timestamps so layer caching works.
- --snapshot-mode=redo
- --skip-unused-stages=true
- --registry-mirror=dockerhub.dockerhub.svc.cluster.local
workspaces:
- name: source
workspace: git-source
- name: dockerconfig
workspace: docker-credentials
runAfter:
- fetch-repository
finally:
- name: report-success
when:
- input: "$(tasks.status)"
operator: in
values: ["Succeeded", "Completed"]
taskRef:
name: gitea-set-status
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
- name: REPO_FULL_NAME
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
- name: GITEA_HOST_URL
value: code.fizz.buzz
- name: SHA
value: "$(tasks.fetch-repository.results.commit)"
- name: DESCRIPTION
value: "Build $(params.JOB_NAME) has succeeded"
- name: STATE
value: success
- name: TARGET_URL
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
- name: report-failure
when:
- input: "$(tasks.status)"
operator: in
values: ["Failed"]
taskRef:
name: gitea-set-status
params:
- name: CONTEXT
value: "$(params.JOB_NAME)"
- name: REPO_FULL_NAME
value: "$(params.REPO_OWNER)/$(params.REPO_NAME)"
- name: GITEA_HOST_URL
value: code.fizz.buzz
- name: SHA
value: "$(tasks.fetch-repository.results.commit)"
- name: DESCRIPTION
value: "Build $(params.JOB_NAME) has failed"
- name: STATE
value: failure
- name: TARGET_URL
value: "https://tekton.fizz.buzz/#/namespaces/$(context.pipelineRun.namespace)/pipelineruns/$(context.pipelineRun.name)"
workspaces:
- name: git-source
- name: docker-credentials
workspaces:
- name: git-source
volumeClaimTemplate:
spec:
storageClassName: "nfs-client"
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
subPath: rust-source
- name: docker-credentials
secret:
secretName: harbor-plain
serviceAccountName: build-bot
timeout: 240h0m0s
params:
- name: image-name
value: "harbor.fizz.buzz/private/natter"
- name: path-to-image-context
value: .
- name: path-to-dockerfile
value: docker/natter/Dockerfile

11
.lighthouse/triggers.yaml Normal file
View File

@@ -0,0 +1,11 @@
apiVersion: config.lighthouse.jenkins-x.io/v1alpha1
kind: TriggerConfig
spec:
postsubmits:
- name: build-natter
source: "pipeline-build-natter.yaml"
# Override https-based url from lighthouse events.
clone_uri: "git@code.fizz.buzz:talexander/natter.git"
branches:
- ^main$
- ^master$

View File

@@ -32,3 +32,9 @@ serde_json = "1.0.107"
tokio = { version = "1.30.0", default-features = false, features = ["rt", "rt-multi-thread", "fs", "io-util"] } tokio = { version = "1.30.0", default-features = false, features = ["rt", "rt-multi-thread", "fs", "io-util"] }
toml = "0.8.2" toml = "0.8.2"
walkdir = "2.4.0" walkdir = "2.4.0"
# Optimized build for any sort of release.
[profile.release-lto]
inherits = "release"
lto = true
strip = "symbols"

View File

@@ -14,6 +14,10 @@
--src-block-language-background: #84828f; --src-block-language-background: #84828f;
--quote-block-border-color: #84828f; --quote-block-border-color: #84828f;
--table-border-color: #6a687a;
--table-odd-background-color: #0a0a0a;
--table-even-background-color: #141414;
} }
body { body {
@@ -184,4 +188,37 @@ body {
} }
} }
} }
.org_table {
table-layout: fixed;
border-collapse: collapse;
border: 1px solid var(--table-border-color);
> tbody {
border-width: 1px 0;
border-style: solid;
border-color: var(--table-border-color);
> tr {
> td {
padding: 0.2rem;
}
}
> tr:nth-child(odd) {
background-color: var(--table-odd-background-color);
}
> tr:nth-child(even) {
background-color: var(--table-even-background-color);
}
}
> thead {
border-width: 1px 0;
border-style: solid;
border-color: var(--table-border-color);
> tr {
> th {
padding: 0.2rem;
font-weight: 600;
}
}
}
}
} }

View File

@@ -1 +1,5 @@
<table>{#.children}{>table_row/}{/.children}</table> <table class="org_table">{#.children}{@select key=.type}
{@eq value="head"}{>table_head/}{/eq}
{@eq value="body"}{>table_body/}{/eq}
{@none}{!TODO: make this panic!}ERROR: Unrecognized type {.type}.{/none}
{/select}{/.children}</table>

View File

@@ -0,0 +1 @@
<tbody>{#.children}{>table_row/}{/.children}</tbody>

View File

@@ -0,0 +1 @@
<thead>{#.children}{>table_head_row/}{/.children}</thead>

View File

@@ -0,0 +1 @@
<th scope="col">{#.children}{>object/}{/.children}</th>

View File

@@ -0,0 +1 @@
<tr>{#.children}{>table_head_cell/}{/.children}</tr>

13
docker/natter/Dockerfile Normal file
View File

@@ -0,0 +1,13 @@
FROM rustlang/rust:nightly-alpine3.17 AS builder
RUN apk add --no-cache musl-dev
RUN mkdir /root/natter
WORKDIR /root/natter
COPY . .
# TODO: Add static build, which currently errors due to proc_macro. RUSTFLAGS="-C target-feature=+crt-static"
RUN CARGO_TARGET_DIR=/target cargo build --profile release-lto
FROM alpine:3.17 AS runner
COPY --from=builder /target/release-lto/natter /usr/bin/

32
docker/natter/Makefile Normal file
View File

@@ -0,0 +1,32 @@
SHELL := bash
.ONESHELL:
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules
OS:=$(shell uname -s)
ifeq ($(origin .RECIPEPREFIX), undefined)
$(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
endif
.RECIPEPREFIX = >
IMAGE_NAME:=natter
TARGET :=
.PHONY: help
help:
> @grep -h "##" $(MAKEFILE_LIST) | grep -v grep | sed -E 's/^([^:]*): *## */\1: /'
.PHONY: build
build: ## Build the docker image.
> docker build --tag $(IMAGE_NAME) --target=$(TARGET) --file Dockerfile ../../
.PHONY: shell
shell: ## Launch an interactive shell inside the docker image.
shell: build
> docker run --rm -i -t --entrypoint /bin/sh --mount type=tmpfs,destination=/tmp $(IMAGE_NAME)
.PHONY: clean
clean:
> docker rmi $(IMAGE_NAME)

View File

@@ -59,6 +59,7 @@ mod subscript;
mod superscript; mod superscript;
mod table; mod table;
mod table_cell; mod table_cell;
mod table_group;
mod table_row; mod table_row;
mod target; mod target;
mod timestamp; mod timestamp;

View File

@@ -1,8 +1,10 @@
use serde::Serialize; use serde::Serialize;
use super::render_context::RenderContext; use super::render_context::RenderContext;
use super::table_group::RenderTableGroup;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::ITable; use crate::intermediate::ITable;
use crate::intermediate::ITableGroup;
use super::macros::render; use super::macros::render;
use super::table_row::RenderTableRow; use super::table_row::RenderTableRow;
@@ -11,15 +13,29 @@ use super::table_row::RenderTableRow;
#[serde(tag = "type")] #[serde(tag = "type")]
#[serde(rename = "table")] #[serde(rename = "table")]
pub(crate) struct RenderTable { pub(crate) struct RenderTable {
children: Vec<RenderTableRow>, children: Vec<RenderTableGroup>,
post_blank: organic::types::PostBlank, post_blank: organic::types::PostBlank,
} }
render!(RenderTable, ITable, original, render_context, { render!(RenderTable, ITable, original, render_context, {
let children = { let children = {
let mut ret = Vec::new(); let mut ret = Vec::new();
for obj in original.children.iter() { for group in original.children.iter() {
ret.push(RenderTableRow::new(render_context.clone(), obj)?); let mut rows = Vec::new();
match group {
ITableGroup::Head(irows) => {
for obj in irows {
rows.push(RenderTableRow::new(render_context.clone(), obj)?);
}
ret.push(RenderTableGroup::Head { children: rows });
}
ITableGroup::Body(irows) => {
for obj in irows {
rows.push(RenderTableRow::new(render_context.clone(), obj)?);
}
ret.push(RenderTableGroup::Body { children: rows });
}
}
} }
ret ret
}; };

View File

@@ -0,0 +1,12 @@
use super::table_row::RenderTableRow;
use serde::Serialize;
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
pub(crate) enum RenderTableGroup {
#[serde(rename = "head")]
Head { children: Vec<RenderTableRow> },
#[serde(rename = "body")]
Body { children: Vec<RenderTableRow> },
}

View File

@@ -59,6 +59,7 @@ mod subscript;
mod superscript; mod superscript;
mod table; mod table;
mod table_cell; mod table_cell;
mod table_group;
mod table_row; mod table_row;
mod target; mod target;
mod timestamp; mod timestamp;
@@ -126,6 +127,7 @@ pub(crate) use subscript::ISubscript;
pub(crate) use superscript::ISuperscript; pub(crate) use superscript::ISuperscript;
pub(crate) use table::ITable; pub(crate) use table::ITable;
pub(crate) use table_cell::ITableCell; pub(crate) use table_cell::ITableCell;
pub(crate) use table_group::ITableGroup;
pub(crate) use table_row::ITableRow; pub(crate) use table_row::ITableRow;
pub(crate) use target::ITarget; pub(crate) use target::ITarget;
pub(crate) use timestamp::ITimestamp; pub(crate) use timestamp::ITimestamp;

View File

@@ -1,11 +1,12 @@
use super::macros::intermediate; use super::macros::intermediate;
use super::table_row::ITableRow; use super::table_row::ITableRow;
use crate::error::CustomError; use crate::error::CustomError;
use crate::intermediate::table_group::ITableGroup;
use organic::types::StandardProperties; use organic::types::StandardProperties;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct ITable { pub(crate) struct ITable {
pub(crate) children: Vec<ITableRow>, pub(crate) children: Vec<ITableGroup>,
pub(crate) post_blank: organic::types::PostBlank, pub(crate) post_blank: organic::types::PostBlank,
} }
@@ -15,10 +16,40 @@ intermediate!(
original, original,
intermediate_context, intermediate_context,
{ {
let children = { // Separate groups by lines, multiple contiguous lines are the same as one.
// If there is only one group, it is a tbody.
// If there are more than one group, the first is thead and the rest are tbody.
let sections = group_into_sections(&original.children);
let children = if sections.len() == 1 {
// If there is only one section, then it is a body.
let mut ret = Vec::new(); let mut ret = Vec::new();
for obj in original.children.iter() { for group in sections.into_iter() {
ret.push(ITableRow::new(intermediate_context.clone(), obj).await?); let mut rows = Vec::new();
for obj in group.into_iter() {
rows.push(ITableRow::new(intermediate_context.clone(), obj).await?)
}
ret.push(ITableGroup::Body(rows));
}
ret
} else {
// If there are more than one section, the first is a head and the rest are body.
let mut ret = Vec::new();
let mut sections = sections.into_iter();
if let Some(group) = sections.next() {
let mut rows = Vec::new();
for obj in group.into_iter() {
rows.push(ITableRow::new(intermediate_context.clone(), obj).await?)
}
ret.push(ITableGroup::Head(rows));
}
for group in sections {
let mut rows = Vec::new();
for obj in group.into_iter() {
rows.push(ITableRow::new(intermediate_context.clone(), obj).await?)
}
ret.push(ITableGroup::Body(rows));
} }
ret ret
}; };
@@ -29,3 +60,41 @@ intermediate!(
}) })
} }
); );
enum GroupIntoSectionsState<'orig, 'parse> {
NonSection,
Section(Vec<&'orig organic::types::TableRow<'parse>>),
}
fn group_into_sections<'orig, 'parse>(
rows: &'orig Vec<organic::types::TableRow<'parse>>,
) -> Vec<Vec<&'orig organic::types::TableRow<'parse>>> {
let mut sections = Vec::new();
let mut rows = rows.into_iter();
let mut state = GroupIntoSectionsState::NonSection;
loop {
state = match (state, rows.next()) {
(GroupIntoSectionsState::NonSection, None) => break,
(GroupIntoSectionsState::NonSection, Some(row)) if row.children.is_empty() => {
GroupIntoSectionsState::NonSection
}
(GroupIntoSectionsState::NonSection, Some(row)) => {
GroupIntoSectionsState::Section(vec![row])
}
(GroupIntoSectionsState::Section(section), None) => {
sections.push(section);
break;
}
(GroupIntoSectionsState::Section(section), Some(row)) if row.children.is_empty() => {
sections.push(section);
GroupIntoSectionsState::NonSection
}
(GroupIntoSectionsState::Section(mut section), Some(row)) => {
section.push(row);
GroupIntoSectionsState::Section(section)
}
}
}
sections
}

View File

@@ -0,0 +1,7 @@
use super::ITableRow;
#[derive(Debug, Clone)]
pub(crate) enum ITableGroup {
Head(Vec<ITableRow>),
Body(Vec<ITableRow>),
}