summaryrefslogtreecommitdiff
path: root/zeitgeist.go
diff options
context:
space:
mode:
authorÖzgür Kesim <oec@kesim.org>2024-11-28 18:27:59 +0100
committerÖzgür Kesim <oec@kesim.org>2024-11-28 18:27:59 +0100
commit255c624b733e44e39392dd565da55d6f2350076f (patch)
tree5226ea6a193404ddf94baec14f1bb503b9419abc /zeitgeist.go
parent69f0a3e8ebe620e840b7b49f8103ca41319ac031 (diff)
parallel rendering of WP Totals
Diffstat (limited to 'zeitgeist.go')
-rw-r--r--zeitgeist.go125
1 files changed, 103 insertions, 22 deletions
diff --git a/zeitgeist.go b/zeitgeist.go
index 643f0e2..9dc6e67 100644
--- a/zeitgeist.go
+++ b/zeitgeist.go
@@ -15,6 +15,7 @@ import (
"slices"
"strconv"
"strings"
+ "sync"
"text/template"
"time"
)
@@ -593,25 +594,28 @@ func (p *Project) readTimelogs(dir string) error {
//go:embed templates/*.t
var embedFS embed.FS
+var once sync.Once
+var templates *template.Template
func (p *Project) printReport(name string) {
- var tmp *template.Template
var e error
- if *fl_templates != "" {
- tmp, e = template.ParseGlob(*fl_templates + "/*.t")
- } else {
- tmp, e = template.ParseFS(embedFS, "templates/*.t")
- }
- if e != nil {
- log.Fatalf("Couldn't parse templates: %v\n", e)
- }
+ once.Do(func() {
+ if *fl_templates != "" {
+ templates, e = template.ParseGlob(*fl_templates + "/*.t")
+ } else {
+ templates, e = template.ParseFS(embedFS, "templates/*.t")
+ }
+ if e != nil {
+ log.Fatalf("Couldn't parse templates: %v\n", e)
+ }
+ })
- if nil == tmp.Lookup(name) {
+ if nil == templates.Lookup(name) {
log.Fatalf("Couldn't find template %q\n", name)
}
- e = tmp.ExecuteTemplate(os.Stdout, name, p)
+ e = templates.ExecuteTemplate(os.Stdout, name, p)
if e != nil {
log.Fatalf("Couldn't execute template %q: %v\n", name, e)
}
@@ -815,7 +819,7 @@ type Totals struct {
}
type WPTotals struct {
- *Totals
+ Totals
Tasks map[string]*Totals
}
@@ -854,23 +858,100 @@ func (p *Project) TotalWPTask(wp, task string) (to *Totals, e error) {
return to, nil
}
-func (p *Project) TotalWP(name string) (t *Totals, e error) {
+func (p *Project) TotalWP(name string) (tot *WPTotals, e error) {
wp, ok := p.Workpackages[name]
if !ok {
return nil, fmt.Errorf("no such workpackage handle: %q", name)
}
- t = &Totals{
- Budgeted: wp.TotalBudget(),
- Planned: p.Planned.FilterWP(name).Total(),
- Done: p.Timeline.FilterWP(name).Total(),
+ tot = &WPTotals{
+ Totals: Totals{
+ Budgeted: wp.TotalBudget(),
+ Planned: p.Planned.FilterWP(name).Total(),
+ Done: p.Timeline.FilterWP(name).Total(),
+ },
+ Tasks: make(map[string]*Totals),
+ }
+ for tn, t := range wp.Tasks {
+ tot.Tasks[tn] = &Totals{
+ Budgeted: t.Budget,
+ Planned: p.Planned.FilterWPTask(name, tn).Total(),
+ Done: p.Timeline.FilterWPTask(name, tn).Total(),
+ }
}
- return t, nil
+ return tot, nil
}
-func (p *Project) Totals() (t map[string]*Totals) {
- t = make(map[string]*Totals)
+type AllTotals struct {
+ Totals
+ WP map[string]*WPTotals
+}
+
+func (p *Project) Totals() (at *AllTotals) {
+ at = &AllTotals{
+ // TODO: fill in totals here, too
+ WP: make(map[string]*WPTotals),
+ }
for n := range p.Workpackages {
- t[n], _ = p.TotalWP(n)
+ at.WP[n], _ = p.TotalWP(n)
+ }
+ return at
+}
+
+func renderParallel(content ...[]string) []string {
+ maxh := 0
+ maxw := make([]int, len(content))
+
+ for i, c := range content {
+ h := len(c)
+ if maxh < h {
+ maxh = h
+ }
+ for _, l := range c {
+ w := len(l)
+ if maxw[i] < w {
+ maxw[i] = w
+ }
+ }
+ }
+ output := []string{}
+
+ for r := range maxh {
+ parts := []string{}
+ for c := range len(content) {
+ var snip string
+ if r < len(content[c]) {
+ snip = content[c][r]
+ }
+ parts = append(parts, fmt.Sprintf("%-[1]*s", maxw[c], snip))
+ }
+ output = append(output, strings.Join(parts, " | "))
+ }
+
+ return output
+}
+
+func (p *Project) ParallelWPTotals(tmpl ...string) ([]string, error) {
+ tm := "wp-total.t"
+ if len(tmpl) > 0 {
+ tm = tmpl[0]
+ }
+ if nil == templates.Lookup(tm) {
+ return nil, fmt.Errorf("template %q not found", tm)
+ }
+
+ totals := p.Totals()
+ content := [][]string{}
+ for name, wpt := range totals.WP {
+ buf := &bytes.Buffer{}
+ data := struct {
+ WP string
+ *WPTotals
+ }{name, wpt}
+ e := templates.ExecuteTemplate(buf, tm, data)
+ if e != nil {
+ return nil, fmt.Errorf("while rendering totals for %s with template %s: %w", name, tm, e)
+ }
+ content = append(content, strings.Split(buf.String(), "\n"))
}
- return t
+ return renderParallel(content...), nil
}