From 35ccc05d3965f1637f245384dbbc4c65a7fcc9cb Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Fri, 30 Dec 2022 00:09:28 -0800 Subject: [PATCH] refactor --- d2plugin/exec.go | 12 +++-- d2plugin/plugin.go | 21 +++++++- d2plugin/plugin_dagre.go | 27 ++++++++-- d2plugin/plugin_elk.go | 41 ++++++++++++--- main.go | 107 ++++++++++++++++++++------------------- 5 files changed, 143 insertions(+), 65 deletions(-) diff --git a/d2plugin/exec.go b/d2plugin/exec.go index b15ac7a5f..0a348c0c9 100644 --- a/d2plugin/exec.go +++ b/d2plugin/exec.go @@ -41,10 +41,16 @@ type execPlugin struct { opts map[string]string } -func (p execPlugin) HydrateOpts(ctx context.Context, opts interface{}) error { +func (p execPlugin) Flags() []PluginSpecificFlag { + // TODO + return nil +} + +func (p *execPlugin) HydrateOpts(opts []byte) error { if opts != nil { - execOpts, ok := opts.(map[string]string) - if !ok { + var execOpts map[string]string + err := json.Unmarshal(opts, &execOpts) + if err != nil { return xmain.UsageErrorf("non-exec layout options given for exec") } diff --git a/d2plugin/plugin.go b/d2plugin/plugin.go index 2e538f4c4..b4524cdad 100644 --- a/d2plugin/plugin.go +++ b/d2plugin/plugin.go @@ -19,11 +19,22 @@ import ( // See plugin_* files for the plugins available for bundling. var plugins []Plugin +type PluginSpecificFlag struct { + Name string + Type string + Default interface{} + Usage string + // Must match the tag in the opt + Tag string +} + type Plugin interface { // Info returns the current info information of the plugin. Info(context.Context) (*PluginInfo, error) - HydrateOpts(context.Context, interface{}) error + Flags() []PluginSpecificFlag + + HydrateOpts([]byte) error // Layout runs the plugin's autolayout algorithm on the input graph // and returns a new graph with the computed placements. @@ -111,3 +122,11 @@ func FindPlugin(ctx context.Context, name string) (Plugin, string, error) { return &execPlugin{path: path}, path, nil } + +func ListPluginFlags() []PluginSpecificFlag { + var out []PluginSpecificFlag + for _, p := range plugins { + out = append(out, p.Flags()...) + } + return out +} diff --git a/d2plugin/plugin_dagre.go b/d2plugin/plugin_dagre.go index b4d75688b..e78629481 100644 --- a/d2plugin/plugin_dagre.go +++ b/d2plugin/plugin_dagre.go @@ -4,6 +4,7 @@ package d2plugin import ( "context" + "encoding/json" "oss.terrastruct.com/d2/d2graph" "oss.terrastruct.com/d2/d2layouts/d2dagrelayout" @@ -20,10 +21,30 @@ type dagrePlugin struct { opts *d2dagrelayout.Opts } -func (p *dagrePlugin) HydrateOpts(ctx context.Context, opts interface{}) error { +func (p dagrePlugin) Flags() []PluginSpecificFlag { + return []PluginSpecificFlag{ + { + Name: "dagre-nodesep", + Type: "int64", + Default: int64(d2dagrelayout.DefaultOpts.NodeSep), + Usage: "number of pixels that separate nodes horizontally.", + Tag: "nodesep", + }, + { + Name: "dagre-edgesep", + Type: "int64", + Default: int64(d2dagrelayout.DefaultOpts.EdgeSep), + Usage: "number of pixels that separate edges horizontally.", + Tag: "edgesep", + }, + } +} + +func (p *dagrePlugin) HydrateOpts(opts []byte) error { if opts != nil { - dagreOpts, ok := opts.(d2dagrelayout.Opts) - if !ok { + var dagreOpts d2dagrelayout.Opts + err := json.Unmarshal(opts, &dagreOpts) + if err != nil { return xmain.UsageErrorf("non-dagre layout options given for dagre") } diff --git a/d2plugin/plugin_elk.go b/d2plugin/plugin_elk.go index da0ee3a5e..b07db9c37 100644 --- a/d2plugin/plugin_elk.go +++ b/d2plugin/plugin_elk.go @@ -4,6 +4,7 @@ package d2plugin import ( "context" + "encoding/json" "oss.terrastruct.com/d2/d2graph" "oss.terrastruct.com/d2/d2layouts/d2elklayout" @@ -20,10 +21,38 @@ type elkPlugin struct { opts *d2elklayout.ConfigurableOpts } -func (p *elkPlugin) HydrateOpts(ctx context.Context, opts interface{}) error { +func (p elkPlugin) Flags() []PluginSpecificFlag { + // ms.Opts.String("", "elk-algorithm", "", d2elklayout.DefaultOpts.Algorithm, "number of pixels that separate nodes horizontally.") + // _, err = ms.Opts.Int64("", "elk-nodeNodeBetweenLayers", "", int64(d2elklayout.DefaultOpts.NodeSpacing), "number of pixels that separate edges horizontally.") + // if err != nil { + // return err + // } + // ms.Opts.String("", "elk-padding", "", d2elklayout.DefaultOpts.Padding, "number of pixels that separate nodes horizontally.") + // _, err = ms.Opts.Int64("", "elk-edgeNodeBetweenLayers", "", int64(d2elklayout.DefaultOpts.EdgeNodeSpacing), "number of pixels that separate edges horizontally.") + // if err != nil { + // return err + // } + // _, err = ms.Opts.Int64("", "elk-nodeSelfLoop", "", int64(d2elklayout.DefaultOpts.SelfLoopSpacing), "number of pixels that separate edges horizontally.") + // if err != nil { + // return err + // } + return []PluginSpecificFlag{ + { + Name: "elk-algorithm", + Type: "string", + Default: d2elklayout.DefaultOpts.Algorithm, + Usage: "number of pixels that separate nodes horizontally.", + Tag: "elk.algorithm", + }, + } +} + +func (p *elkPlugin) HydrateOpts(opts []byte) error { if opts != nil { - elkOpts, ok := opts.(d2elklayout.ConfigurableOpts) - if !ok { + var elkOpts d2elklayout.ConfigurableOpts + err := json.Unmarshal(opts, &elkOpts) + if err != nil { + // TODO not right return xmain.UsageErrorf("non-dagre layout options given for dagre") } @@ -32,7 +61,7 @@ func (p *elkPlugin) HydrateOpts(ctx context.Context, opts interface{}) error { return nil } -func (p *elkPlugin) Info(context.Context) (*PluginInfo, error) { +func (p elkPlugin) Info(context.Context) (*PluginInfo, error) { return &PluginInfo{ Name: "elk", ShortHelp: "Eclipse Layout Kernel (ELK) with the Layered algorithm.", @@ -42,10 +71,10 @@ See https://github.com/kieler/elkjs for more.`, }, nil } -func (p *elkPlugin) Layout(ctx context.Context, g *d2graph.Graph) error { +func (p elkPlugin) Layout(ctx context.Context, g *d2graph.Graph) error { return d2elklayout.Layout(ctx, g, p.opts) } -func (p *elkPlugin) PostProcess(ctx context.Context, in []byte) ([]byte, error) { +func (p elkPlugin) PostProcess(ctx context.Context, in []byte) ([]byte, error) { return in, nil } diff --git a/main.go b/main.go index 28ef74ea2..d536bdaed 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "encoding/json" "errors" "fmt" "io" @@ -17,8 +18,6 @@ import ( "oss.terrastruct.com/util-go/go2" "oss.terrastruct.com/util-go/xmain" - "oss.terrastruct.com/d2/d2layouts/d2dagrelayout" - "oss.terrastruct.com/d2/d2layouts/d2elklayout" "oss.terrastruct.com/d2/d2lib" "oss.terrastruct.com/d2/d2plugin" "oss.terrastruct.com/d2/d2renderers/d2fonts" @@ -151,12 +150,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) { return err } - layoutOpts, err := parseLayoutOpts(ms, *layoutFlag) - if err != nil { - return err - } - - err = plugin.HydrateOpts(ctx, layoutOpts) + err = parseLayoutOpts(ms, plugin) if err != nil { return err } @@ -307,56 +301,65 @@ func DiscardSlog(ctx context.Context) context.Context { } func populateLayoutOpts(ms *xmain.State) error { - _, err := ms.Opts.Int64("", "dagre-nodesep", "", int64(d2dagrelayout.DefaultOpts.NodeSep), "number of pixels that separate nodes horizontally.") - if err != nil { - return err - } - _, err = ms.Opts.Int64("", "dagre-edgesep", "", int64(d2dagrelayout.DefaultOpts.EdgeSep), "number of pixels that separate edges horizontally.") - if err != nil { - return err - } + pluginFlags := d2plugin.ListPluginFlags() - ms.Opts.String("", "elk-algorithm", "", d2elklayout.DefaultOpts.Algorithm, "number of pixels that separate nodes horizontally.") - _, err = ms.Opts.Int64("", "elk-nodeNodeBetweenLayers", "", int64(d2elklayout.DefaultOpts.NodeSpacing), "number of pixels that separate edges horizontally.") - if err != nil { - return err - } - ms.Opts.String("", "elk-padding", "", d2elklayout.DefaultOpts.Padding, "number of pixels that separate nodes horizontally.") - _, err = ms.Opts.Int64("", "elk-edgeNodeBetweenLayers", "", int64(d2elklayout.DefaultOpts.EdgeNodeSpacing), "number of pixels that separate edges horizontally.") - if err != nil { - return err - } - _, err = ms.Opts.Int64("", "elk-nodeSelfLoop", "", int64(d2elklayout.DefaultOpts.SelfLoopSpacing), "number of pixels that separate edges horizontally.") - if err != nil { - return err + for _, f := range pluginFlags { + switch f.Type { + case "string": + ms.Opts.String("", f.Name, "", f.Default.(string), f.Usage) + case "int64": + ms.Opts.Int64("", f.Name, "", f.Default.(int64), f.Usage) + } } return nil } -func parseLayoutOpts(ms *xmain.State, layout string) (interface{}, error) { - switch layout { - case "dagre": - nodesep, _ := ms.Opts.Flags.GetInt64("dagre-nodesep") - edgesep, _ := ms.Opts.Flags.GetInt64("dagre-edgesep") - return d2dagrelayout.Opts{ - NodeSep: int(nodesep), - EdgeSep: int(edgesep), - }, nil - case "elk": - algorithm, _ := ms.Opts.Flags.GetString("elk-algorithm") - nodeSpacing, _ := ms.Opts.Flags.GetInt64("elk-nodeNodeBetweenLayers") - padding, _ := ms.Opts.Flags.GetString("elk-padding") - edgeNodeSpacing, _ := ms.Opts.Flags.GetInt64("elk-edgeNodeSpacing") - selfLoopSpacing, _ := ms.Opts.Flags.GetInt64("elk-nodeSelfLoop") - return d2elklayout.ConfigurableOpts{ - Algorithm: algorithm, - NodeSpacing: int(nodeSpacing), - Padding: padding, - EdgeNodeSpacing: int(edgeNodeSpacing), - SelfLoopSpacing: int(selfLoopSpacing), - }, nil +func parseLayoutOpts(ms *xmain.State, plugin d2plugin.Plugin) error { + opts := make(map[string]interface{}) + for _, f := range plugin.Flags() { + switch f.Type { + case "string": + val, _ := ms.Opts.Flags.GetString(f.Name) + opts[f.Tag] = val + case "int64": + val, _ := ms.Opts.Flags.GetInt64(f.Name) + opts[f.Tag] = val + } } - return nil, fmt.Errorf("unexpected error, layout not found for parsing opts") + b, err := json.Marshal(opts) + if err != nil { + return err + } + + err = plugin.HydrateOpts(b) + return err + + // switch layout { + // case "dagre": + // nodesep, _ := ms.Opts.Flags.GetInt64("dagre-nodesep") + // edgesep, _ := ms.Opts.Flags.GetInt64("dagre-edgesep") + // return d2dagrelayout.Opts{ + // NodeSep: int(nodesep), + // EdgeSep: int(edgesep), + // }, nil + // case "elk": + // algorithm, _ := ms.Opts.Flags.GetString("elk-algorithm") + // nodeSpacing, _ := ms.Opts.Flags.GetInt64("elk-nodeNodeBetweenLayers") + // padding, _ := ms.Opts.Flags.GetString("elk-padding") + // edgeNodeSpacing, _ := ms.Opts.Flags.GetInt64("elk-edgeNodeSpacing") + // selfLoopSpacing, _ := ms.Opts.Flags.GetInt64("elk-nodeSelfLoop") + // return d2elklayout.ConfigurableOpts{ + // Algorithm: algorithm, + // NodeSpacing: int(nodeSpacing), + // Padding: padding, + // EdgeNodeSpacing: int(edgeNodeSpacing), + // SelfLoopSpacing: int(selfLoopSpacing), + // }, nil + // default: + // + // } + // + // return nil, fmt.Errorf("unexpected error, layout not found for parsing opts") }