From 255c624b733e44e39392dd565da55d6f2350076f Mon Sep 17 00:00:00 2001 From: Özgür Kesim Date: Thu, 28 Nov 2024 18:27:59 +0100 Subject: parallel rendering of WP Totals --- zeitgeist.go | 125 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 103 insertions(+), 22 deletions(-) (limited to 'zeitgeist.go') 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 } -- cgit v1.2.3