2022-11-03 13:54:49 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
"os/exec"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"strings"
|
|
|
|
|
|
2022-12-01 19:19:39 +00:00
|
|
|
"oss.terrastruct.com/util-go/xmain"
|
|
|
|
|
|
2022-11-03 13:54:49 +00:00
|
|
|
"oss.terrastruct.com/d2/d2plugin"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func help(ms *xmain.State) {
|
|
|
|
|
fmt.Fprintf(ms.Stdout, `Usage:
|
2022-12-01 10:48:30 +00:00
|
|
|
%[1]s [--watch=false] [--theme=0] file.d2 [file.svg | file.png]
|
|
|
|
|
%[1]s layout [name]
|
|
|
|
|
%[1]s fmt file.d2
|
2022-11-30 11:01:13 +00:00
|
|
|
|
|
|
|
|
%[1]s compiles and renders file.d2 to file.svg | file.png
|
|
|
|
|
It defaults to file.svg if an output path is not provided.
|
2022-11-03 13:54:49 +00:00
|
|
|
|
|
|
|
|
Use - to have d2 read from stdin or write to stdout.
|
|
|
|
|
|
2022-12-01 05:14:38 +00:00
|
|
|
See man d2 for more detailed docs.
|
2022-11-30 11:01:13 +00:00
|
|
|
|
2022-11-03 13:54:49 +00:00
|
|
|
Flags:
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
Subcommands:
|
|
|
|
|
%[1]s layout - Lists available layout engine options with short help
|
2022-12-30 21:22:45 +00:00
|
|
|
%[1]s layout [name] - Display long help for a particular layout engine, including its configuration options
|
2022-12-01 17:21:16 +00:00
|
|
|
%[1]s fmt file.d2 - Format file.d2
|
2022-11-03 13:54:49 +00:00
|
|
|
|
2022-11-11 09:17:06 +00:00
|
|
|
See more docs and the source code at https://oss.terrastruct.com/d2
|
2022-12-01 10:48:30 +00:00
|
|
|
`, filepath.Base(ms.Name), ms.Opts.Defaults())
|
2022-11-03 13:54:49 +00:00
|
|
|
}
|
|
|
|
|
|
2022-12-01 17:21:16 +00:00
|
|
|
func layoutCmd(ctx context.Context, ms *xmain.State) error {
|
2022-11-17 00:48:19 +00:00
|
|
|
if len(ms.Opts.Flags.Args()) == 1 {
|
2022-11-03 13:54:49 +00:00
|
|
|
return shortLayoutHelp(ctx, ms)
|
2022-11-17 00:48:19 +00:00
|
|
|
} else if len(ms.Opts.Flags.Args()) == 2 {
|
2022-11-03 13:54:49 +00:00
|
|
|
return longLayoutHelp(ctx, ms)
|
|
|
|
|
} else {
|
2022-11-07 23:20:39 +00:00
|
|
|
return pluginSubcommand(ctx, ms)
|
2022-11-03 13:54:49 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func shortLayoutHelp(ctx context.Context, ms *xmain.State) error {
|
|
|
|
|
var pluginLines []string
|
|
|
|
|
plugins, err := d2plugin.ListPlugins(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
for _, p := range plugins {
|
2022-11-08 21:52:46 +00:00
|
|
|
var l string
|
|
|
|
|
if p.Type == "bundled" {
|
|
|
|
|
l = fmt.Sprintf("%s (bundled) - %s", p.Name, p.ShortHelp)
|
|
|
|
|
} else {
|
|
|
|
|
l = fmt.Sprintf("%s (%s) - %s", p.Name, humanPath(p.Path), p.ShortHelp)
|
|
|
|
|
}
|
|
|
|
|
pluginLines = append(pluginLines, l)
|
2022-11-03 13:54:49 +00:00
|
|
|
}
|
|
|
|
|
fmt.Fprintf(ms.Stdout, `Available layout engines found:
|
|
|
|
|
|
|
|
|
|
%s
|
|
|
|
|
|
|
|
|
|
Usage:
|
2022-11-15 00:35:22 +00:00
|
|
|
To use a particular layout engine, set the environment variable D2_LAYOUT=[name] or flag --layout=[name].
|
2022-11-03 13:54:49 +00:00
|
|
|
|
|
|
|
|
Example:
|
|
|
|
|
D2_LAYOUT=dagre d2 in.d2 out.svg
|
|
|
|
|
|
|
|
|
|
Subcommands:
|
2022-12-30 21:22:45 +00:00
|
|
|
%s layout [layout name] - Display long help for a particular layout engine, including its configuration options
|
2022-11-03 13:54:49 +00:00
|
|
|
|
|
|
|
|
See more docs at https://oss.terrastruct.com/d2
|
|
|
|
|
`, strings.Join(pluginLines, "\n"), ms.Name)
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func longLayoutHelp(ctx context.Context, ms *xmain.State) error {
|
2022-11-17 00:48:19 +00:00
|
|
|
layout := ms.Opts.Flags.Arg(1)
|
2022-11-03 13:54:49 +00:00
|
|
|
plugin, path, err := d2plugin.FindPlugin(ctx, layout)
|
|
|
|
|
if errors.Is(err, exec.ErrNotFound) {
|
|
|
|
|
return layoutNotFound(ctx, layout)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pluginLocation := "bundled"
|
|
|
|
|
if path != "" {
|
|
|
|
|
pluginLocation = fmt.Sprintf("executable plugin at %s", humanPath(path))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pluginInfo, err := plugin.Info(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-08 00:19:15 +00:00
|
|
|
if !strings.HasSuffix(pluginInfo.LongHelp, "\n") {
|
|
|
|
|
pluginInfo.LongHelp += "\n"
|
|
|
|
|
}
|
2022-11-03 13:54:49 +00:00
|
|
|
fmt.Fprintf(ms.Stdout, `%s (%s):
|
|
|
|
|
|
2022-11-08 00:19:15 +00:00
|
|
|
%s`, pluginInfo.Name, pluginLocation, pluginInfo.LongHelp)
|
2022-11-03 13:54:49 +00:00
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func layoutNotFound(ctx context.Context, layout string) error {
|
|
|
|
|
var names []string
|
|
|
|
|
plugins, err := d2plugin.ListPlugins(ctx)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
for _, p := range plugins {
|
|
|
|
|
names = append(names, p.Name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return xmain.UsageErrorf(`D2_LAYOUT "%s" is not bundled and could not be found in your $PATH.
|
|
|
|
|
The available options are: %s. For details on each option, run "d2 layout".
|
|
|
|
|
|
|
|
|
|
For more information on setup, please visit https://github.com/terrastruct/d2.`,
|
|
|
|
|
layout, strings.Join(names, ", "))
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-07 23:20:39 +00:00
|
|
|
func pluginSubcommand(ctx context.Context, ms *xmain.State) error {
|
2022-11-17 00:48:19 +00:00
|
|
|
layout := ms.Opts.Flags.Arg(1)
|
2022-11-07 23:20:39 +00:00
|
|
|
plugin, _, err := d2plugin.FindPlugin(ctx, layout)
|
|
|
|
|
if errors.Is(err, exec.ErrNotFound) {
|
|
|
|
|
return layoutNotFound(ctx, layout)
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-17 00:48:19 +00:00
|
|
|
ms.Opts.Args = ms.Opts.Flags.Args()[2:]
|
2022-11-07 23:20:39 +00:00
|
|
|
return d2plugin.Serve(plugin)(ctx, ms)
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 13:54:49 +00:00
|
|
|
func humanPath(fp string) string {
|
|
|
|
|
if strings.HasPrefix(fp, os.Getenv("HOME")) {
|
|
|
|
|
return filepath.Join("~", strings.TrimPrefix(fp, os.Getenv("HOME")))
|
|
|
|
|
}
|
|
|
|
|
return fp
|
|
|
|
|
}
|