151 lines
4.8 KiB
Go
151 lines
4.8 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"html"
|
|
"net/url"
|
|
"slices"
|
|
"strings"
|
|
)
|
|
|
|
type SvgWriter struct {
|
|
ypos float64
|
|
header []byte
|
|
out bytes.Buffer
|
|
}
|
|
|
|
const (
|
|
SvgType_Package = iota
|
|
SvgType_Project
|
|
)
|
|
|
|
func NewSvg(SvgType int) *SvgWriter {
|
|
svg := &SvgWriter{}
|
|
svg.header = []byte(`<svg version="2.0" overflow="auto" width="40ex" height="`)
|
|
svg.out.WriteString(`em" xmlns="http://www.w3.org/2000/svg">`)
|
|
switch SvgType {
|
|
case SvgType_Package:
|
|
svg.out.WriteString(`<defs>
|
|
<g id="s">
|
|
<rect width="15ex" height="1.5em" stroke-width="1" stroke="green" fill="#efe" rx="5" />
|
|
<text x="2.5ex" y="1.1em">succeeded</text>
|
|
</g>
|
|
<g id="f">
|
|
<rect width="15ex" height="1.5em" stroke-width="1" stroke="red" fill="#fee" rx="5" />
|
|
<text x="5ex" y="1.1em">failed</text>
|
|
</g>
|
|
<g id="b">
|
|
<rect width="15ex" height="1.5em" stroke-width="1" stroke="grey" fill="#fbf" rx="5" />
|
|
<text x="3.75ex" y="1.1em">blocked</text>
|
|
</g>
|
|
<g id="broken">
|
|
<rect width="15ex" height="1.5em" stroke-width="1" stroke="grey" fill="#fff" rx="5" />
|
|
<text x="4.5ex" y="1.1em" stroke="red" fill="red">broken</text>
|
|
</g>
|
|
<g id="build">
|
|
<rect width="15ex" height="1.5em" stroke-width="1" stroke="yellow" fill="#664" rx="5" />
|
|
<text x="3.75ex" y="1.1em" fill="yellow">building</text>
|
|
</g>
|
|
<g id="u">
|
|
<rect width="15ex" height="1.5em" stroke-width="1" stroke="yellow" fill="#555" rx="5" />
|
|
<text x="2ex" y="1.1em" fill="orange">unresolvable</text>
|
|
</g>
|
|
<g id="scheduled">
|
|
<rect width="15ex" height="1.5em" stroke-width="1" stroke="blue" fill="none" rx="5" />
|
|
<text x="3ex" y="1.1em" stroke="none" fill="blue">scheduled</text>
|
|
</g>
|
|
<g id="d">
|
|
<rect width="15ex" height="1.5em" stroke-width="1" stroke="grey" fill="none" rx="5" />
|
|
<text x="4ex" y="1.1em" stroke="none" fill="grey">disabled</text>
|
|
</g>
|
|
<g id="e">
|
|
<rect width="15ex" height="1.5em" stroke-width="1" stroke="grey" fill="none" rx="5" />
|
|
<text x="4ex" y="1.1em" stroke="none" fill="#aaf">excluded</text>
|
|
</g>
|
|
<g id="un">
|
|
<rect width="15ex" height="1.5em" stroke-width="1" stroke="grey" fill="none" rx="5" />
|
|
<text x="4ex" y="1.1em" stroke="none" fill="grey">unknown</text>
|
|
</g>
|
|
<rect id="repotitle" width="100%" height="2em" stroke-width="1" stroke="grey" fill="grey" rx="2" />
|
|
</defs>`)
|
|
|
|
case SvgType_Project:
|
|
svg.out.WriteString(`<defs>
|
|
</defs>`)
|
|
}
|
|
|
|
return svg
|
|
}
|
|
|
|
func (svg *SvgWriter) WriteTitle(title string) {
|
|
svg.out.WriteString(`<text stroke="black" fill="black" x="1ex" y="` + fmt.Sprint(svg.ypos-.5) + `em">` + html.EscapeString(title) + "</text>")
|
|
svg.ypos += 2.5
|
|
|
|
}
|
|
|
|
func (svg *SvgWriter) WriteSubtitle(subtitle string) {
|
|
svg.out.WriteString(`<use href="#repotitle" y="` + fmt.Sprint(svg.ypos-2) + `em"/>`)
|
|
svg.out.WriteString(`<text stroke="black" fill="black" x="3ex" y="` + fmt.Sprint(svg.ypos-.6) + `em">` + html.EscapeString(subtitle) + `</text>`)
|
|
svg.ypos += 2
|
|
}
|
|
|
|
func (svg *SvgWriter) WritePackageStatus(loglink, arch, status, detail string) {
|
|
StatusToSVG := func(S string) string {
|
|
switch S {
|
|
case "succeeded":
|
|
return "s"
|
|
case "failed":
|
|
return "f"
|
|
case "broken", "scheduled":
|
|
return S
|
|
case "blocked":
|
|
return "b"
|
|
case "building":
|
|
return "build"
|
|
case "unresolvable":
|
|
return "u"
|
|
case "disabled":
|
|
return "d"
|
|
case "excluded":
|
|
return "e"
|
|
}
|
|
return "un"
|
|
}
|
|
|
|
svg.out.WriteString(`<text fill="#113" x="5ex" y="` + fmt.Sprint(svg.ypos-.6) + `em">` + html.EscapeString(arch) + `</text>`)
|
|
svg.out.WriteString(`<g>`)
|
|
if len(loglink) > 0 {
|
|
u, err := url.Parse(loglink)
|
|
if err == nil {
|
|
svg.out.WriteString(`<a href="` + u.String() + `" target="_blank" rel="noopener">`)
|
|
}
|
|
}
|
|
svg.out.WriteString(`<use href="#` + StatusToSVG(status) + `" x="20ex" y="` + fmt.Sprint(svg.ypos-1.7) + `em"/>`)
|
|
if len(loglink) > 0 {
|
|
svg.out.WriteString(`</a>`)
|
|
}
|
|
if len(detail) > 0 {
|
|
svg.out.WriteString(`<title>` + html.EscapeString(detail) + "</title>")
|
|
}
|
|
|
|
svg.out.WriteString("</g>\n")
|
|
svg.ypos += 2
|
|
}
|
|
|
|
func (svg *SvgWriter) WriteProjectStatus(project, repo, arch, status string, count int) {
|
|
u, err := url.Parse(*ObsUrl + "/project/monitor/" + url.PathEscape(project) + "?defaults=0&" + url.QueryEscape(status) + "=1&arch_" + url.QueryEscape(arch) + "=1&repo_" + url.QueryEscape(strings.ReplaceAll(repo, ".", "_")) + "=1")
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
svg.out.WriteString(`<g><a href="` + u.String() + `" target="_blank" rel="noopener">` + "\n" +
|
|
`<text fill="#113" x="5ex" y="` + fmt.Sprint(svg.ypos-0.6) + "em\">\n" +
|
|
html.EscapeString(status+": ") + fmt.Sprint(count) + "</text></a></g>\n")
|
|
svg.ypos += 2
|
|
}
|
|
|
|
func (svg *SvgWriter) GenerateSvg() []byte {
|
|
return slices.Concat(svg.header, []byte(fmt.Sprint(svg.ypos)), svg.out.Bytes(), []byte("</svg>"))
|
|
}
|