Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3aba510

Browse files
author
tengu-alt
committedSep 3, 2024
Upgrade for the native protocols spec page
1 parent dddece2 commit 3aba510

File tree

12 files changed

+604
-14
lines changed

12 files changed

+604
-14
lines changed
 

‎cqlprotodoc/README.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Comes from https://github.com/martin-sucha/cqlprotodoc
2+
3+
cqlprotodoc converts
4+
[CQL protocol specification files](https://github.com/apache/cassandra/tree/trunk/doc)
5+
to HTML for easier browsing.
6+
7+
Usage:
8+
9+
1. Update template-notice.txt based on your Cassandra distribution.
10+
2. `cqlprotodoc <path_to_cassandra_doc_dir> <output_dir>`
11+
12+
The generated files are published at https://martin-sucha.github.io/cqlprotodoc/

‎cqlprotodoc/go.mod‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module cqlprotodoc
2+
3+
go 1.17
4+
5+
require github.com/mvdan/xurls v1.1.0

‎cqlprotodoc/go.sum‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
github.com/mvdan/xurls v1.1.0 h1:OpuDelGQ1R1ueQ6sSryzi6P+1RtBpfQHM8fJwlE45ww=
2+
github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU=

‎cqlprotodoc/main.go‎

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
package main
2+
3+
import (
4+
"cqlprotodoc/spec"
5+
"embed"
6+
"fmt"
7+
"html/template"
8+
"os"
9+
"path/filepath"
10+
"strings"
11+
)
12+
13+
//go:embed template.gohtml
14+
var templateFS embed.FS
15+
16+
//go:embed template-notice.txt
17+
var notice []byte
18+
19+
type TOCNode struct {
20+
spec.TOCEntry
21+
Exists bool
22+
Children []*TOCNode
23+
}
24+
25+
func buildTOCTree(entries []spec.TOCEntry, sectionNumbers map[string]struct{}) []*TOCNode {
26+
var root TOCNode
27+
stack := []*TOCNode{&root}
28+
for _, e := range entries {
29+
level := strings.Count(e.Number, ".") + 1
30+
if len(stack) > level {
31+
stack = stack[:level]
32+
}
33+
parent := stack[len(stack)-1]
34+
_, exists := sectionNumbers[e.Number]
35+
node := &TOCNode{
36+
TOCEntry: e,
37+
Children: nil,
38+
Exists: exists,
39+
}
40+
parent.Children = append(parent.Children, node)
41+
stack = append(stack, node)
42+
}
43+
return root.Children
44+
}
45+
46+
type templateData struct {
47+
spec.Document
48+
LicenseHTML template.HTML
49+
TOCTree []*TOCNode
50+
Sections []Section
51+
}
52+
53+
type Section struct {
54+
spec.Section
55+
Level int
56+
BodyHTML template.HTML
57+
}
58+
59+
func link(sb *strings.Builder, href, text string) {
60+
sb.WriteString(`<a href="`)
61+
sb.WriteString(template.HTMLEscapeString(href))
62+
sb.WriteString(`">`)
63+
sb.WriteString(template.HTMLEscapeString(text))
64+
sb.WriteString(`</a>`)
65+
}
66+
67+
func formatBody(text []spec.Text, sectionNumbers map[string]struct{}) template.HTML {
68+
var sb strings.Builder
69+
for _, t := range text {
70+
switch {
71+
case t.SectionRef != "":
72+
if _, ok := sectionNumbers[t.SectionRef]; ok {
73+
link(&sb, "#s"+t.SectionRef, t.Text)
74+
} else {
75+
sb.WriteString(template.HTMLEscapeString(t.Text))
76+
}
77+
case t.Href != "":
78+
link(&sb, t.Href, t.Text)
79+
default:
80+
sb.WriteString(template.HTMLEscapeString(t.Text))
81+
}
82+
}
83+
return template.HTML(sb.String())
84+
}
85+
86+
func buildSections(in []spec.Section, sectionNumbers map[string]struct{}) []Section {
87+
ret := make([]Section, len(in))
88+
for i, s := range in {
89+
ret[i].Section = in[i]
90+
ret[i].Level = strings.Count(s.Number, ".") + 2
91+
ret[i].BodyHTML = formatBody(in[i].Body, sectionNumbers)
92+
}
93+
return ret
94+
}
95+
96+
func checkSectionLinks(d spec.Document, sectionNumbers, tocNumbers map[string]struct{}) {
97+
98+
for _, t := range d.TOC {
99+
if _, ok := sectionNumbers[t.Number]; !ok {
100+
fmt.Fprintf(os.Stderr, "section %q exists in TOC, but not in sections\n", t.Number)
101+
}
102+
}
103+
for _, s := range d.Sections {
104+
if _, ok := tocNumbers[s.Number]; !ok {
105+
fmt.Fprintf(os.Stderr, "section %q exists in sections, but not in TOC\n", s.Number)
106+
}
107+
for _, tt := range s.Body {
108+
if tt.SectionRef != "" {
109+
if _, ok := sectionNumbers[tt.SectionRef]; !ok {
110+
fmt.Fprintf(os.Stderr, "non-existing section %q is referenced from section %q\n",
111+
tt.SectionRef, s.Number)
112+
}
113+
}
114+
}
115+
}
116+
}
117+
118+
var tmpl = template.Must(template.ParseFS(templateFS, "template.gohtml"))
119+
120+
func processDocument(inputPath, outputPath string) (outErr error) {
121+
data, err := os.ReadFile(inputPath)
122+
if err != nil {
123+
return err
124+
}
125+
doc, err := spec.Parse(string(data))
126+
if err != nil {
127+
return err
128+
}
129+
sectionNumbers := make(map[string]struct{})
130+
for _, s := range doc.Sections {
131+
sectionNumbers[s.Number] = struct{}{}
132+
}
133+
tocNumbers := make(map[string]struct{})
134+
for _, t := range doc.TOC {
135+
tocNumbers[t.Number] = struct{}{}
136+
}
137+
checkSectionLinks(doc, sectionNumbers, tocNumbers)
138+
f, err := os.Create(outputPath)
139+
if err != nil {
140+
return err
141+
}
142+
defer func() {
143+
closeErr := f.Close()
144+
if closeErr != nil && outErr == nil {
145+
outErr = closeErr
146+
}
147+
}()
148+
return tmpl.Execute(f, templateData{
149+
Document: doc,
150+
LicenseHTML: formatBody(doc.License, sectionNumbers),
151+
TOCTree: buildTOCTree(doc.TOC, sectionNumbers),
152+
Sections: buildSections(doc.Sections, sectionNumbers),
153+
})
154+
}
155+
156+
func main() {
157+
if len(os.Args) != 3 {
158+
fmt.Fprintln(os.Stderr, "Usage: <cassandra_doc_dir> <output_dir>")
159+
return
160+
}
161+
inputDir := os.Args[1]
162+
outputDir := os.Args[2]
163+
for _, name := range []string{"v5", "v4", "v3"} {
164+
fmt.Fprintln(os.Stderr, name)
165+
err := processDocument(filepath.Join(inputDir, fmt.Sprintf("native_protocol_%s.spec", name)),
166+
filepath.Join(outputDir, fmt.Sprintf("native_protocol_%s.html", name)))
167+
if err != nil {
168+
fmt.Fprintf(os.Stderr, "%s: %v\n", name, err)
169+
return
170+
}
171+
}
172+
err := os.WriteFile(filepath.Join(outputDir, "NOTICE"), notice, 0666)
173+
if err != nil {
174+
fmt.Fprintf(os.Stderr, "NOTICE: %v\n", err)
175+
return
176+
}
177+
}
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Please sign in to comment.