// Package am-vis generates diagrams of a filtered graph.
package main import ( amgraph dbgtypes ) // const CmdDbgServer = "dbg-server" // nolint:lll type Args struct { RenderDump *RenderDumpCmd `arg:"subcommand:render-dump" help:"Render from a debugger dump file"` // DbgServer *DbgServerCmd `arg:"subcommand:dbg-server" help:"Render from live connections"` // TODO RenderAllowlist // preset single render defaults RenderDistance int `arg:"-d,--render-distance" default:"0"` RenderDepth int `arg:"--render-depth" default:"0"` RenderStart bool `arg:"--render-start" default:"false"` RenderReady bool `arg:"--render-ready" default:"false"` RenderException bool `arg:"--render-exception" default:"false"` RenderStates bool `arg:"--render-states" default:"true"` RenderInherited bool `arg:"--render-inherited" default:"true"` RenderPipes bool `arg:"--render-pipes" default:"false"` RenderDetailedPipes bool `arg:"--render-detailed-pipes" default:"true"` RenderRelations bool `arg:"--render-relations" default:"true"` RenderConns bool `arg:"--render-conns" default:"true"` RenderParentRel bool `arg:"--render-parent-rel" default:"true"` RenderHalfConns bool `arg:"--render-half-conns" default:"true"` RenderHalfPipes bool `arg:"--render-half-pipes" default:"true"` RenderNestSubmachines bool `arg:"--render-nest-submachines" default:"false"` RenderTags bool `arg:"--render-tags" default:"false"` // presets Bird bool `arg:"-b,--bird" help:"Use the bird's view preset"` Map bool `arg:"-b,--map" help:"Use the map view preset"` // output OutputElk bool `arg:"--output-elk" default:"true" help:"Use ELK layout"` OutputFilename string `arg:"-o,--output-filename" default:"am-vis"` } func (Args) () string { return utils.Sp(` Render diagrams of interconnected state machines. Examples: # single machine am-vis render-dump mymach.gob.br mach://MyMach1/t234 # bird's view with distance of 2 from MyMach1 am-vis --bird -d 2 \ render-dump mymach.gob.br mach://MyMach1/TX-ID # bird's view with detailed pipes am-vis --bird --render-detailed-pipes \ render-dump mymach.gob.br mach://MyMach1/TX-ID # map view with inherited states am-vis --render-inherited \ render-dump mymach.gob.br mach://MyMach1/t234 # map view am-vis --map render-dump mymach.gob.br `) } // nolint:lll type RenderDumpCmd struct { DumpFilename string `arg:"-f,--dump-file" help:"Input dbg dump file" default:"am-dbg-dump.gob.br"` MachUrl string `arg:"positional"` } // TODO DbgServerCmd // nolint:lll // type DbgServerCmd struct { // ListenAddr string `arg:"-l,--listen-addr" default:"127.0.0.1:7452"` // FwdAddrs []string `arg:"-f,--fwd-addr,separate" help:"Forward msgs to these addresses"` // DumpFilename string `arg:"positional,required" help:"Load a baseline dump file"` // } var args Args func main() { := context.Background() := arg.MustParse(&args) if .Subcommand() == nil { .Fail("missing subcommand (" + types.CmdRenderDump + ")") } switch { case args.RenderDump != nil: if := renderDump(, args, os.Args[1:]); != nil { _ = .FailSubcommand(.Error(), types.CmdRenderDump) } } } var ss = states.VisualizerStates func renderDump( context.Context, Args, []string) error { // go server.StartRpc(mach, p.ServerAddr, nil, p.FwdData) , := visualizer.New(, "am-vis") if != nil { return } // parse mach URL if .RenderDump.MachUrl == "" && !.Map { return errors.New("machine URL is required when not using --map") } , := dbgtypes.ParseMachUrl(.RenderDump.MachUrl) if != nil { return } // init & import .Mach.Add1(ss.Start, nil) // TODO pass to StartState = .HImportData(.RenderDump.DumpFilename) if != nil { return } := slices.Collect(maps.Values(.Clients())) fmt.Printf("Imported %d clients\n", len()) := slices.ContainsFunc(, func( amgraph.Client) bool { return .Id == .MachId }) if ! { return fmt.Errorf("machine %s not found in the dump file", .MachId) } // presets switch { case .Map: visualizer.PresetMap(.R) case .Bird: visualizer.PresetBird(.R) default: visualizer.PresetSingle(.R) } applyOverrides(, , .R) // render .R.RenderMachs = []string{.MachId} .R.OutputFilename = .OutputFilename .R.OutputMermaid = false fmt.Printf("Rendering... please wait\n") if := .R.GenDiagrams(); != nil { return } fmt.Printf("Rendered %s\n", .OutputFilename+".svg") fmt.Printf("Rendered %s\n", .OutputFilename+".d2") return nil } func applyOverrides( Args, []string, *visualizer.Renderer) { if slices.Contains(, "--render-detailed-pipes") { .RenderDetailedPipes = .RenderDetailedPipes } if slices.Contains(, "--render-pipes") { .RenderPipes = .RenderPipes } if slices.Contains(, "--render-exception") { .RenderException = .RenderException } if slices.Contains(, "--render-tags") { .RenderTags = .RenderTags } if slices.Contains(, "--render-inherited") { .RenderInherited = .RenderInherited } if slices.Contains(, "--render-relations") { .RenderRelations = .RenderRelations } if slices.Contains(, "--render-conns") { .RenderConns = .RenderConns } if slices.Contains(, "--render-parent-rel") { .RenderParentRel = .RenderParentRel } if slices.Contains(, "--render-half-conns") { .RenderHalfConns = .RenderHalfConns } if slices.Contains(, "--render-half-pipes") { .RenderHalfPipes = .RenderHalfPipes } if slices.Contains(, "--render-nest-submachines") { .RenderNestSubmachines = .RenderNestSubmachines } if slices.Contains(, "--render-start") { .RenderStart = .RenderStart } if slices.Contains(, "--render-ready") { .RenderReady = .RenderReady } if slices.Contains(, "--render-depth") { .RenderDepth = .RenderDepth } if slices.Contains(, "--render-states") { .RenderStates = .RenderStates } if slices.Contains(, "--output-elk") { .OutputElk = .OutputElk } }