ref: 4c2cab79cdc4cdaa502aa928dda32ea5cd8db595
parent: 2bc3c60c50995de3d1f49d85a97e674b572a28dd
author: halfwit <halfwit@Halfwits-MBP.hitronhub.home>
date: Tue Jan 28 04:08:01 PST 2020
Move towards having flags for printing
--- a/command.go
+++ b/command.go
@@ -1,6 +1,7 @@
package main
import (
+ "errors"
"flag"
"fmt"
)
@@ -10,6 +11,7 @@
add = "add"
child = "child"
create = "create"
+ destroy = "destroy"
dot = "dot"
generate = "generate"
list = "list"
@@ -17,11 +19,12 @@
parent = "parent"
remove = "rm"
task = "task"
+ toggle = "toggle"
)
type command struct {
args []string
- runner func() error
+ runner func() (string, error)
}
func newCommand(arg string) (*command, error) {
@@ -29,7 +32,7 @@
if arg == task {
c.args = flag.Args()[1:]
c.runner = c.task
-
+
return c, nil
}
@@ -71,14 +74,14 @@
return nil
}
-func (c *command) add() error {
+func (c *command) add() (string, error) {
if len(c.args) != 3 {
- return fmt.Errorf(errNoArg, add)
+ return "", fmt.Errorf(errNoArg, add)
}
l, err := layoutFromTodoFile()
if err != nil {
- return err
+ return "", err
}
switch c.args[0] {
@@ -87,106 +90,92 @@
case child:
l.addLink(c.args[1], c.args[2])
default:
- return fmt.Errorf(errBadArg, c.args[0])
+ return "", fmt.Errorf(errBadArg, c.args[0])
}
- writeTodo(l)
-
- return nil
+ return writeTodo(l)
}
-func (c *command) dot() error {
+func (c *command) dot() (string, error) {
l, err := layoutFromTodoFile()
if err != nil && c.args[0] != create {
- return err
+ return "", err
}
- writeDot(l)
-
- return nil
+ return writeDot(l)
}
// generate walks the file looking for a handful of known tokens
-func (c *command) generate() error {
+func (c *command) generate() (string, error) {
g := &generator{}
if g.dotTodoExists() {
err := g.parseTodo()
if err != nil {
- return err
+ return "", err
}
}
l := g.toLayout()
- writeTodo(l)
- return nil
+ return writeTodo(l)
}
-func (c *command) list() error {
+func (c *command) list() (string, error) {
l, err := layoutFromTodoFile()
if err != nil {
- return err
+ return "", err
}
- writeList(l)
-
- return nil
+ return writeList(l)
}
-func (c *command) listall() error {
+func (c *command) listall() (string, error) {
l, err := layoutFromTodoFile()
if err != nil {
- return err
+ return "", err
}
- writeListAll(l)
-
- return nil
+ return writeListAll(l)
}
-func (c *command) rm() error {
+func (c *command) rm() (string, error) {
if len(c.args) != 3 {
- return fmt.Errorf(errNoArg, remove)
+ return "", fmt.Errorf(errNoArg, remove)
}
l, err := layoutFromTodoFile()
if err != nil && c.args[0] != create {
- return err
+ return "", err
}
- defer writeTodo(l)
-
switch c.args[0] {
- case "parent":
+ case parent:
l.rmLink(c.args[2], c.args[1])
- case "child":
+ case child:
l.rmLink(c.args[1], c.args[1])
default:
- return fmt.Errorf(errBadArg, c.args[0])
+ return "", fmt.Errorf(errBadArg, c.args[0])
}
- return nil
+ return writeTodo(l)
}
-func (c *command) run() error {
+func (c *command) run() (string, error) {
if c.runner != nil {
- err := c.runner()
- if err != nil {
- return err
- }
+ return c.runner()
}
- return nil
+ return "", errors.New(errNoCmd)
}
-func (c *command) task() error {
+func (c *command) task() (string, error) {
if len(c.args) < 2 {
- return fmt.Errorf(errNoArg, task)
+ return "", fmt.Errorf(errNoArg, task)
}
l, err := layoutFromTodoFile()
if err != nil && c.args[0] != create {
- return err
+ return "", err
}
switch c.args[0] {
@@ -193,50 +182,54 @@
case create:
err = l.create(c.args[1])
if err != nil {
- return err
+ return "", err
}
writeTodo(l)
- return nil
- case "destroy":
+ return "", nil
+ case destroy:
err := l.destroy(c.args[1])
if err != nil {
- return err
+ return "", err
}
writeTodo(l)
- return nil
- case "add":
+ return "", nil
+ case add:
if l.taskExists(c.args[1], c.args[2]) {
- return fmt.Errorf(errExists, c.args[1])
+ return "", fmt.Errorf(errExists, c.args[1])
}
if e := l.addTask(c.args[1], c.args[2]); e != nil {
- return e
+ return "", e
}
writeTodo(l)
- return nil
- case "rm":
+ return "", nil
+ case remove:
if !l.taskExists(c.args[1], c.args[2]) {
- return fmt.Errorf(errNoEntry, c.args[2])
+ return "", fmt.Errorf(errNoEntry, c.args[2])
}
- defer writeTodo(l)
+ if e := l.rmTask(c.args[1], c.args[2]); e != nil {
+ return "", e
+ }
- return l.rmTask(c.args[1], c.args[2])
- case "toggle":
+ return writeTodo(l)
+ case toggle:
if !l.taskExists(c.args[1], c.args[2]) {
- return fmt.Errorf(errNoEntry, c.args[1])
+ return "", fmt.Errorf(errNoEntry, c.args[1])
}
- defer writeTodo(l)
+ if e := l.toggleTask(c.args[1], c.args[2]); e != nil {
+ return "", e
+ }
- return l.toggleTask(c.args[1], c.args[2])
+ return writeTodo(l)
default:
- return fmt.Errorf(errBadArg, c.args[0])
+ return "", fmt.Errorf(errBadArg, c.args[0])
}
}
--- a/dag.go
+++ b/dag.go
@@ -1,19 +1,17 @@
package main
import (
- "log"
-
"github.com/goombaio/dag"
)
-func dagFromLayout(l *Layout) *dag.DAG {
+func dagFromLayout(l *Layout) (*dag.DAG, error) {
dg := dag.NewDAG()
dm := make(map[string]*dag.Vertex)
-
+
for _, job := range l.Jobs {
dm[job.Key] = dag.NewVertex(job.Key, job)
if e := dg.AddVertex(dm[job.Key]); e != nil {
- log.Println(e)
+ return nil, e
}
}
@@ -29,11 +27,11 @@
}
if e := dg.AddEdge(dm[job.Key], dm[other.Key]); e != nil {
- log.Println(e)
+ return nil, e
}
}
}
}
- return dg
+ return dg, nil
}
--- a/generate.go
+++ b/generate.go
@@ -16,7 +16,7 @@
func (g *generator) parseTodo() error {
var err error
-
+
g.existing, err = layoutFromTodoFile()
if err != nil {
return err
--- a/layout.go
+++ b/layout.go
@@ -4,6 +4,7 @@
"bufio"
"errors"
"fmt"
+
"os"
"regexp"
"strings"
@@ -70,7 +71,7 @@
func parseTags(sc *bufio.Scanner) []string {
txt := sc.Text()
n := strings.Index(txt, ":")
-
+
return stringToTags(txt[:n])
}
@@ -179,7 +180,7 @@
r := regexp.MustCompile(`([^\[\]]*)\s?(\[.*\])+\s?(.*)`)
matches := r.FindAllStringSubmatch(incoming, -1)
- if matches != nil && len(matches[0]) < 3 {
+ if matches == nil || len(matches[0]) < 3 {
return nil, errors.New("could not parse string")
}
--- a/todo.go
+++ b/todo.go
@@ -1,15 +1,24 @@
package main
import (
+ "flag"
+ "fmt"
"log"
- "os"
)
func main() {
- cmd, err := newCommand(os.Args[0])
+ flag.Parse()
+
+ cmd, err := newCommand(flag.Arg(0))
if err != nil {
log.Fatal(err)
}
- log.Fatal(cmd.run())
+ s, err := cmd.run()
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // TODO(halfwit) Switch to our own writer type and pass in os.Stdout
+ fmt.Printf("%s", s)
}
--- a/write.go
+++ b/write.go
@@ -1,8 +1,8 @@
package main
import (
+ "errors"
"fmt"
- "log"
"os"
"strings"
"text/template"
@@ -19,10 +19,10 @@
{{end}}{{end}}`
// Writer that creates our normal file
-func writeTodo(l *Layout) {
+func writeTodo(l *Layout) (string, error) {
wr, err := os.Create(".todo")
if err != nil {
- log.Fatal(err)
+ return "", err
}
defer wr.Close()
@@ -29,14 +29,15 @@
t := template.Must(template.New("todoTmpl").Parse(todoTmpl))
- err = t.Execute(wr, l)
- if err != nil {
- log.Fatal(err)
+ if e := t.Execute(wr, l); e != nil {
+ return "", e
}
+
+ return "", nil
}
// Writer that outputs in dot format
-func writeDot(l *Layout) {
+func writeDot(l *Layout) (string, error) {
var sb strings.Builder
sb.WriteString("digraph depgraph {\n\trankdir=RL;\n")
@@ -67,7 +68,7 @@
for _, entry := range job.Tasks[0].Entries {
sb.WriteString("\n")
sb.WriteString(entry.Desc)
-
+
if entry.Done {
sb.WriteString(" ✓")
}
@@ -84,18 +85,25 @@
}
for _, req := range job.Requires {
- sb.WriteString(fmt.Sprintf("%s -> %s;\n", job.Key, req))
+ sb.WriteString(fmt.Sprintf("%s -> %s;\n", req, job.Key))
}
}
sb.WriteString("}\n")
- fmt.Println(sb.String())
+ return sb.String(), nil
}
// Writer that outputs only leaves
-func writeList(l *Layout) {
+func writeList(l *Layout) (string, error) {
+ var sb strings.Builder
+
l.removeCompleted()
- d := dagFromLayout(l)
+
+ d, err := dagFromLayout(l)
+ if err != nil {
+ return "", err
+ }
+
leaves := d.SinkVertices()
for _, leaf := range leaves {
@@ -102,7 +110,7 @@
job := leaf.Value.(*Job)
for _, t := range job.Tasks {
- fmt.Printf("%v - %s\n", job.Tags, t.Title)
+ fmt.Fprintf(&sb, "%v - %s\n", job.Tags, t.Title)
for _, e := range t.Entries {
var f rune
@@ -114,23 +122,31 @@
f = '✗'
}
- fmt.Printf(" %c %s\n", f, e.Desc)
+ fmt.Fprintf(&sb, " %c %s\n", f, e.Desc)
}
}
}
+
+ return sb.String(), nil
}
// Writer that outputs all nodes
-func writeListAll(l *Layout) {
- var walk func(v *dag.Vertex)
+func writeListAll(l *Layout) (string, error) {
+ var walk func(v *dag.Vertex) error
+ var sb strings.Builder
- d := dagFromLayout(l)
+ d, err := dagFromLayout(l)
+ if err != nil {
+ return "", err
+ }
+
seen := map[*Job]bool{}
- walk = func(v *dag.Vertex) {
+ walk = func(v *dag.Vertex) error {
+
job := v.Value.(*Job)
if seen[job] {
- return
+ return errors.New(errBadTodo)
}
seen[job] = true
@@ -137,7 +153,7 @@
children, err := d.Successors(v)
if err != nil {
- log.Fatal(err)
+ return err
}
for _, child := range children {
@@ -145,7 +161,7 @@
}
for _, t := range job.Tasks {
- fmt.Printf("[%v] - %s\n", job.Key, t.Title)
+ fmt.Fprintf(&sb, "[%v] - %s\n", job.Key, t.Title)
for _, e := range t.Entries {
var f rune
@@ -157,12 +173,18 @@
f = '✗'
}
- fmt.Printf(" %c %s\n", f, e.Desc)
+ fmt.Fprintf(&sb, " %c %s\n", f, e.Desc)
}
}
+
+ return nil
}
for _, t := range d.SourceVertices() {
- walk(t)
+ if e := walk(t); e != nil {
+ return "", e
+ }
}
+
+ return sb.String(), nil
}