1
0
Fork 0
mirror of https://github.com/anyproto/anytype-heart.git synced 2025-06-07 21:37:04 +09:00
anytype-heart/cmd/debugtree/debugtree.go
2023-05-24 17:10:52 +02:00

171 lines
4.2 KiB
Go

//go:build cgo
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"os/exec"
"runtime"
"strings"
"time"
"github.com/gogo/protobuf/proto"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/debug/treearchive"
"github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/goccy/go-graphviz"
"github.com/anyproto/anytype-heart/util/pbtypes"
)
var (
file = flag.String("f", "", "path to debug file")
fromRoot = flag.Bool("r", false, "build from root of the tree")
makeJson = flag.Bool("j", false, "generate json file")
makeTree = flag.Bool("t", false, "generate graphviz file")
printState = flag.Bool("s", false, "print result state debug")
changeIdx = flag.Int("c", -1, "build tree before given index and print change")
objectStore = flag.Bool("o", false, "show object store info")
fileHashes = flag.Bool("h", false, "show file hashes in state")
)
func main() {
flag.Parse()
if *file == "" {
flag.PrintDefaults()
return
}
fmt.Println("opening file...")
st := time.Now()
archive, err := treearchive.Open(*file)
if err != nil {
log.Fatal("can't open debug file:", err)
}
defer archive.Close()
fmt.Printf("open archive done in %.1fs\n", time.Since(st).Seconds())
importer := treearchive.NewTreeImporter(archive.ListStorage(), archive.TreeStorage())
st = time.Now()
err = importer.Import(*fromRoot, "")
if err != nil {
log.Fatal("can't import the tree", err)
}
fmt.Printf("import tree done in %.1fs\n", time.Since(st).Seconds())
if *makeJson {
treeJson, err := importer.Json()
if err != nil {
log.Fatal("can't build json:", err)
}
res, err := json.MarshalIndent(treeJson, "", " ")
if err != nil {
log.Fatal("can't marshall json:", err)
}
tf, err := ioutil.TempFile("", "tree_*.json")
if err != nil {
log.Fatal("can't create temp file:", err)
}
fmt.Println("tree json file:", tf.Name())
tf.Write(res)
tf.Close()
}
if *changeIdx != -1 {
ch, err := importer.ChangeAt(*changeIdx)
if err != nil {
log.Fatal("can't get the change in tree: ", err)
}
fmt.Println("Change:")
fmt.Println(pbtypes.Sprint(ch.Model))
err = importer.Import(*fromRoot, ch.Id)
if err != nil {
log.Fatal("can't import the tree before", ch.Id, err)
}
}
ot := importer.ObjectTree()
di, err := ot.Debug(state.ChangeParser{})
if err != nil {
log.Fatal("can't get debug info from tree", err)
}
fmt.Printf("Tree root:\t%s\nTree len:\t%d\nTree heads:\t%s\n",
ot.Root().Id,
di.TreeLen,
strings.Join(di.Heads, ","))
if *printState {
fmt.Println("Building state...")
stt := time.Now()
s, err := importer.State()
if err != nil {
log.Fatal("can't build state:", err)
}
dur := time.Since(stt)
fmt.Println(s.StringDebug())
payload := &model.ObjectChangePayload{}
err = proto.Unmarshal(ot.ChangeInfo().ChangePayload, payload)
if err != nil {
return
}
sbt := smartblock.SmartBlockType(payload.SmartBlockType)
fmt.Printf("Smarblock type:\t%v\n", sbt.ToProto())
if *fileHashes {
fmt.Println("File keys:")
for _, fk := range s.GetAndUnsetFileKeys() {
fmt.Printf("\t%s: %d\n", fk.Hash, len(fk.Keys))
}
}
fmt.Println("state building time:", dur)
}
if *objectStore {
fmt.Println("fetch object store info..")
ls, err := archive.LocalStore()
if err != nil {
fmt.Println("can't open objectStore info:", err)
} else {
fmt.Println(pbtypes.Sprint(ls))
}
}
if *makeTree {
gvo, err := graphviz.ParseBytes([]byte(di.Graphviz))
if err != nil {
log.Fatal("can't open graphviz data:", err)
}
tf, err := ioutil.TempFile("", "tree_*.svg")
if err != nil {
log.Fatal("can't create temp file:", err)
}
g := graphviz.New()
g.Render(gvo, graphviz.SVG, tf)
fmt.Println("tree file:", tf.Name())
tf.Close()
open(tf.Name())
}
}
func open(path string) {
var err error
switch runtime.GOOS {
case "linux":
err = exec.Command("xdg-open", path).Start()
case "windows":
err = exec.Command("rundll32", "rl.dll,FileProtocolHandler", path).Start()
case "darwin":
err = exec.Command("open", path).Start()
default:
err = fmt.Errorf("unsupported platform")
}
if err != nil {
log.Fatal(err)
}
}