+/*
+goredo -- redo implementation on pure Go
+Copyright (C) 2020 Sergey Matveev <stargrave@stargrave.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, version 3 of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// Dependency DOT graph generation
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "path"
+
+ "go.cypherpunks.ru/recfile"
+)
+
+type DotNodes struct {
+ from string
+ to string
+}
+
+func dotWalker(data map[DotNodes]bool, tgtOrig string) (map[DotNodes]bool, error) {
+ cwd, tgt := cwdAndTgt(tgtOrig)
+ depPath := path.Join(cwd, RedoDir, tgt+DepSuffix)
+ fdDep, err := os.Open(depPath)
+ if err != nil {
+ return nil, err
+ }
+ defer fdDep.Close()
+ var dep string
+ r := recfile.NewReader(fdDep)
+ for {
+ m, err := r.NextMap()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return nil, err
+ }
+ switch m["Type"] {
+ case DepTypeIfcreate:
+ data[DotNodes{tgtOrig, cwdMustRel(cwd, m["Target"])}] = true
+ case DepTypeIfchange:
+ dep = m["Target"]
+ data[DotNodes{tgtOrig, cwdMustRel(cwd, dep)}] = false
+ if isSrc(cwd, dep) || dep == tgt {
+ continue
+ }
+ data, err = dotWalker(data, cwdMustRel(cwd, dep))
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ return data, nil
+}
+
+func dotPrint(tgts []string) error {
+ data := map[DotNodes]bool{}
+ var err error
+ for _, tgt := range tgts {
+ data, err = dotWalker(data, tgt)
+ if err != nil {
+ return err
+ }
+ }
+ fmt.Println(`digraph d {
+ rankdir=LR
+ ranksep=2
+ splines=false // splines=ortho
+ node[shape=rectangle]`)
+ for nodes, nonexistent := range data {
+ fmt.Printf("\n\t\"%s\" -> \"%s\"", nodes.from, nodes.to)
+ if nonexistent {
+ fmt.Print(" [style=dotted]")
+ }
+ }
+ fmt.Println("\n}")
+ return nil
+}