summaryrefslogtreecommitdiff
path: root/zeitgeist.go
diff options
context:
space:
mode:
authorÖzgür Kesim <oec@kesim.org>2024-11-27 18:05:53 +0100
committerÖzgür Kesim <oec@kesim.org>2024-11-27 18:05:53 +0100
commit0ebf69db6c2acb3f7b88eec1f0852ccf40068077 (patch)
tree4357927cbcc32a47cbe3b974c0dace77c40df4ec /zeitgeist.go
parent43e5471fdbf91b0028c496f8e01091b2d1ad8189 (diff)
fix plan handling
Diffstat (limited to 'zeitgeist.go')
-rw-r--r--zeitgeist.go66
1 files changed, 64 insertions, 2 deletions
diff --git a/zeitgeist.go b/zeitgeist.go
index 811de40..762b0af 100644
--- a/zeitgeist.go
+++ b/zeitgeist.go
@@ -25,6 +25,7 @@ var (
fl_plandir = flag.String("pl", "", "directory to search for plans")
fl_templates = flag.String("tm", "", "directory to search for the templates")
fl_report = flag.String("rp", "report.t", "default report template")
+ fl_today = flag.String("today", time.Now().Format(time.DateOnly), "what is the date today")
)
type Project struct {
@@ -41,6 +42,7 @@ type Project struct {
Blocked Timeline
Timeline Timeline
Planned Timeline
+ Today Date
}
type Timeline map[Date]Entries
@@ -74,6 +76,26 @@ func (en Entries) FilterWP(name string) Entries {
return r
}
+func (en Entries) FilterTask(task string) Entries {
+ r := Entries{}
+ for _, e := range en {
+ if task == e.Task {
+ r = append(r, e)
+ }
+ }
+ return r
+}
+
+func (en Entries) FilterWPTask(wp, task string) Entries {
+ r := Entries{}
+ for _, e := range en {
+ if wp == e.WP && task == e.Task {
+ r = append(r, e)
+ }
+ }
+ return r
+}
+
func (en Entries) Totals() Amount {
var a Amount
for _, e := range en {
@@ -82,6 +104,14 @@ func (en Entries) Totals() Amount {
return a
}
+func (t Timeline) FilterWPTask(wp, task string) Entries {
+ r := Entries{}
+ for _, e := range t {
+ r = append(r, e.FilterWPTask(wp, task)...)
+ }
+ return r
+}
+
func (t Timeline) FilterWP(name string) Entries {
r := Entries{}
for _, entries := range t {
@@ -229,6 +259,11 @@ type Deliverable struct {
func main() {
flag.Parse()
+ today, e := time.Parse(time.DateOnly, *fl_today)
+ if e != nil {
+ log.Fatalf("couldn't parse today parameter: %v", e)
+ }
+
p, e := loadProject(*fl_project)
if e != nil {
log.Fatalf("error loading project: %v", e)
@@ -237,6 +272,7 @@ func main() {
log.Fatalf("start '%s' after end '%s'", p.Start, p.End)
}
+ p.Today = Date(today)
if p.Timeline == nil {
p.Timeline = make(Timeline)
}
@@ -307,7 +343,7 @@ func (p *Project) readPlans(dir string) error {
// 2024-02-11..2024-02-23 wp2:short *8h [comment]
// 2024-02-11..2024-02-23 wp2:short 3d [comment]
var line = scanner.Text()
- if strings.HasPrefix(line, "#") {
+ if strings.HasPrefix(line, "#") || "" == strings.TrimSpace(line) {
continue
}
@@ -349,6 +385,10 @@ func (p *Project) readPlans(dir string) error {
}
}
+ if last.After(r[0]) || last.After(r[1]) {
+ return fmt.Errorf("file %q, line %d: dates not monotonic: %s before %s", name, nr, parts[0], Date(last))
+ }
+
if !isrange {
if last.After(r[0]) {
return fmt.Errorf("file %q, line %d: dates not monotonic, %s older", name, nr, Date(r[0]))
@@ -754,7 +794,29 @@ type Totals struct {
}
func (t *Totals) Unaccounted() Amount {
- return t.Budgeted - t.Planned
+ d := t.Budgeted - t.Planned
+ // TODO: rounding OK!?
+ if d < 4 {
+ return 0
+ }
+ return d
+}
+
+func (p *Project) TotalWPTask(wp, task string) (to *Totals, e error) {
+ w, ok := p.Workpackages[wp]
+ if !ok {
+ return nil, fmt.Errorf("no such workpackage handle: %q", wp)
+ }
+ t, ok := w.Tasks[task]
+ if !ok {
+ return nil, fmt.Errorf("no such task in workpackage %q: %q", wp, task)
+ }
+ to = &Totals{
+ Budgeted: t.Budget,
+ Planned: p.Planned.FilterWPTask(wp, task).Total(),
+ Actual: p.Timeline.FilterWPTask(wp, task).Total(),
+ }
+ return to, nil
}
func (p *Project) TotalWP(name string) (t *Totals, e error) {