diff --git a/d2plugin/exec.go b/d2plugin/exec.go index 0a348c0c9..0a186c908 100644 --- a/d2plugin/exec.go +++ b/d2plugin/exec.go @@ -41,9 +41,29 @@ type execPlugin struct { opts map[string]string } -func (p execPlugin) Flags() []PluginSpecificFlag { - // TODO - return nil +func (p execPlugin) Flags(ctx context.Context) (_ []PluginSpecificFlag, err error) { + ctx, cancel := context.WithTimeout(ctx, time.Second*10) + defer cancel() + cmd := exec.CommandContext(ctx, p.path, "flags") + defer xdefer.Errorf(&err, "failed to run %v", cmd.Args) + + stdout, err := cmd.Output() + if err != nil { + ee := &exec.ExitError{} + if errors.As(err, &ee) && len(ee.Stderr) > 0 { + return nil, fmt.Errorf("%v\nstderr:\n%s", ee, ee.Stderr) + } + return nil, err + } + + var flags []PluginSpecificFlag + + err = json.Unmarshal(stdout, &flags) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal json: %w", err) + } + + return flags, nil } func (p *execPlugin) HydrateOpts(opts []byte) error { diff --git a/d2plugin/plugin.go b/d2plugin/plugin.go index b4524cdad..0b7288a75 100644 --- a/d2plugin/plugin.go +++ b/d2plugin/plugin.go @@ -32,7 +32,7 @@ type Plugin interface { // Info returns the current info information of the plugin. Info(context.Context) (*PluginInfo, error) - Flags() []PluginSpecificFlag + Flags(context.Context) ([]PluginSpecificFlag, error) HydrateOpts([]byte) error @@ -123,10 +123,14 @@ func FindPlugin(ctx context.Context, name string) (Plugin, string, error) { return &execPlugin{path: path}, path, nil } -func ListPluginFlags() []PluginSpecificFlag { +func ListPluginFlags(ctx context.Context) ([]PluginSpecificFlag, error) { var out []PluginSpecificFlag for _, p := range plugins { - out = append(out, p.Flags()...) + flags, err := p.Flags(ctx) + if err != nil { + return nil, err + } + out = append(out, flags...) } - return out + return out, nil } diff --git a/d2plugin/plugin_dagre.go b/d2plugin/plugin_dagre.go index e78629481..2e23e0db6 100644 --- a/d2plugin/plugin_dagre.go +++ b/d2plugin/plugin_dagre.go @@ -21,7 +21,7 @@ type dagrePlugin struct { opts *d2dagrelayout.Opts } -func (p dagrePlugin) Flags() []PluginSpecificFlag { +func (p dagrePlugin) Flags(context.Context) ([]PluginSpecificFlag, error) { return []PluginSpecificFlag{ { Name: "dagre-nodesep", @@ -37,7 +37,7 @@ func (p dagrePlugin) Flags() []PluginSpecificFlag { Usage: "number of pixels that separate edges horizontally.", Tag: "edgesep", }, - } + }, nil } func (p *dagrePlugin) HydrateOpts(opts []byte) error { diff --git a/d2plugin/plugin_elk.go b/d2plugin/plugin_elk.go index b07db9c37..c3ab55544 100644 --- a/d2plugin/plugin_elk.go +++ b/d2plugin/plugin_elk.go @@ -21,7 +21,7 @@ type elkPlugin struct { opts *d2elklayout.ConfigurableOpts } -func (p elkPlugin) Flags() []PluginSpecificFlag { +func (p elkPlugin) Flags(context.Context) ([]PluginSpecificFlag, error) { // 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 { @@ -44,7 +44,7 @@ func (p elkPlugin) Flags() []PluginSpecificFlag { Usage: "number of pixels that separate nodes horizontally.", Tag: "elk.algorithm", }, - } + }, nil } func (p *elkPlugin) HydrateOpts(opts []byte) error { diff --git a/main.go b/main.go index d536bdaed..727761ed5 100644 --- a/main.go +++ b/main.go @@ -76,7 +76,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) { return err } - err = populateLayoutOpts(ms) + err = populateLayoutOpts(ctx, ms) if err != nil { return err } @@ -150,7 +150,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) { return err } - err = parseLayoutOpts(ms, plugin) + err = parseLayoutOpts(ctx, ms, plugin) if err != nil { return err } @@ -300,8 +300,11 @@ func DiscardSlog(ctx context.Context) context.Context { return ctxlog.With(ctx, slog.Make(sloghuman.Sink(io.Discard))) } -func populateLayoutOpts(ms *xmain.State) error { - pluginFlags := d2plugin.ListPluginFlags() +func populateLayoutOpts(ctx context.Context, ms *xmain.State) error { + pluginFlags, err := d2plugin.ListPluginFlags(ctx) + if err != nil { + return err + } for _, f := range pluginFlags { switch f.Type { @@ -315,9 +318,13 @@ func populateLayoutOpts(ms *xmain.State) error { return nil } -func parseLayoutOpts(ms *xmain.State, plugin d2plugin.Plugin) error { +func parseLayoutOpts(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin) error { opts := make(map[string]interface{}) - for _, f := range plugin.Flags() { + flags, err := plugin.Flags(ctx) + if err != nil { + return err + } + for _, f := range flags { switch f.Type { case "string": val, _ := ms.Opts.Flags.GetString(f.Name)