diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 3320fc87a..8e629a0ab 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -19,3 +19,4 @@ - Fixes rare panic exporting to gifs [#1257](https://github.com/terrastruct/d2/pull/1257) - Fixes bad performance in large grid diagrams [#1263](https://github.com/terrastruct/d2/pull/1263) - Fixes bug in ELK when container has ID "root" [#1268](https://github.com/terrastruct/d2/pull/1268) +- Fixes edge case panic with invalid CLI arguments [#1271](https://github.com/terrastruct/d2/pull/1271) diff --git a/d2plugin/serve.go b/d2plugin/serve.go index acc697a96..9cae5ca2f 100644 --- a/d2plugin/serve.go +++ b/d2plugin/serve.go @@ -21,20 +21,22 @@ import ( // Also see execPlugin in exec.go for the d2 binary plugin protocol. func Serve(p Plugin) xmain.RunFunc { return func(ctx context.Context, ms *xmain.State) (err error) { - fs, err := p.Flags(ctx) - if err != nil { - return err - } - for _, f := range fs { - f.AddToOpts(ms.Opts) - } - err = ms.Opts.Flags.Parse(ms.Opts.Args) - if !errors.Is(err, pflag.ErrHelp) && err != nil { - return xmain.UsageErrorf("failed to parse flags: %v", err) - } - if errors.Is(err, pflag.ErrHelp) { - // At some point we want to write a friendly help. - return info(ctx, p, ms) + if !ms.Opts.Flags.Parsed() { + fs, err := p.Flags(ctx) + if err != nil { + return err + } + for _, f := range fs { + f.AddToOpts(ms.Opts) + } + err = ms.Opts.Flags.Parse(ms.Opts.Args) + if !errors.Is(err, pflag.ErrHelp) && err != nil { + return xmain.UsageErrorf("failed to parse flags: %v", err) + } + if errors.Is(err, pflag.ErrHelp) { + // At some point we want to write a friendly help. + return info(ctx, p, ms) + } } if len(ms.Opts.Flags.Args()) < 1 { diff --git a/e2etests-cli/main_test.go b/e2etests-cli/main_test.go index c5f33effb..6cb634235 100644 --- a/e2etests-cli/main_test.go +++ b/e2etests-cli/main_test.go @@ -58,6 +58,14 @@ func TestCLI_E2E(t *testing.T) { assert.Testdata(t, ".svg", svg) }, }, + { + name: "flags-panic", + run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) { + writeFile(t, dir, "hello-world.d2", `x -> y`) + err := runTestMain(t, ctx, dir, env, "layout", "dagre", "--dagre-nodesep", "50", "hello-world.d2") + assert.ErrorString(t, err, `failed to wait xmain test: e2etests-cli/d2: failed to unmarshal input to graph: `) + }, + }, { name: "empty-layer", run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {