]> Cypherpunks.ru repositories - goredo.git/blobdiff - dot.go
DOT generation
[goredo.git] / dot.go
diff --git a/dot.go b/dot.go
new file mode 100644 (file)
index 0000000..d59bc40
--- /dev/null
+++ b/dot.go
@@ -0,0 +1,94 @@
+/*
+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
+}