From 7b4421b9a00855c843e915341638d62e303d4c58 Mon Sep 17 00:00:00 2001 From: Sam Alba Date: Wed, 2 Jun 2021 16:22:38 +0200 Subject: [PATCH] cmd/doc: boiler plate and for inputs / outputs scanning Signed-off-by: Sam Alba --- cmd/dagger/cmd/doc.go | 144 +++++++++++++++++++++++++++++++++++++ cmd/dagger/cmd/root.go | 1 + environment/environment.go | 4 +- environment/inputs_scan.go | 4 +- go.mod | 1 + 5 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 cmd/dagger/cmd/doc.go diff --git a/cmd/dagger/cmd/doc.go b/cmd/dagger/cmd/doc.go new file mode 100644 index 00000000..d55b4f1c --- /dev/null +++ b/cmd/dagger/cmd/doc.go @@ -0,0 +1,144 @@ +package cmd + +import ( + "context" + "fmt" + "io/ioutil" + "regexp" + "strings" + "unicode/utf8" + + "cuelang.org/go/cue" + "cuelang.org/go/cue/format" + "github.com/rs/zerolog/log" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "go.dagger.io/dagger/cmd/dagger/cmd/common" + "go.dagger.io/dagger/cmd/dagger/logger" + "go.dagger.io/dagger/compiler" + "go.dagger.io/dagger/environment" + "golang.org/x/crypto/ssh/terminal" +) + +const ( + textFormat = "txt" + markdownFormat = "md" +) + +var docCmd = &cobra.Command{ + Use: "doc [PACKAGE | PATH]", + Short: "document a package", + Args: cobra.MaximumNArgs(1), + PreRun: func(cmd *cobra.Command, args []string) { + // Fix Viper bug for duplicate flags: + // https://github.com/spf13/viper/issues/233 + if err := viper.BindPFlags(cmd.Flags()); err != nil { + panic(err) + } + }, + Run: func(cmd *cobra.Command, args []string) { + lg := logger.New() + ctx := lg.WithContext(cmd.Context()) + workspace := common.CurrentWorkspace(ctx) + st := common.CurrentEnvironmentState(ctx, workspace) + + format := viper.GetString("output") + if format != textFormat && format != markdownFormat { + lg.Fatal().Msg("output must be either `txt` or `md`") + } + + val, err := loadCode(args[0]) + if err != nil { + lg.Fatal().Err(err).Msg("cannot compile code") + } + PrintDoc(ctx, val, format) + }, +} + +func init() { + docCmd.Flags().StringP("output", "o", textFormat, "Output format (txt|md)") + + if err := viper.BindPFlags(docCmd.Flags()); err != nil { + panic(err) + } +} + +func extractComment(v cue.Value) string { + docs := []string{} + for _, c := range v.Doc() { + docs = append(docs, strings.TrimSpace(c.Text())) + } + doc := strings.Join(docs, " ") + + lines := strings.Split(doc, "\n") + + // Strip out FIXME, TODO, and INTERNAL comments + docs = []string{} + for _, line := range lines { + if strings.HasPrefix(line, "FIXME: ") || + strings.HasPrefix(line, "TODO: ") || + strings.HasPrefix(line, "INTERNAL: ") { + continue + } + docs = append(docs, line) + } + return strings.Join(docs, " ") +} + +func extractSpec(v cue.Value) string { + node := v.Source() + if node == nil { + return fmt.Sprintf("%v", v) + } + src, err := format.Node(node) + if err != nil { + panic(err) + } + space := regexp.MustCompile(`[\s\n]+`) + return strings.TrimSpace( + space.ReplaceAllString(string(src), " "), + ) +} + +func mdEscape(s string) string { + escape := []string{"|", "<", ">"} + for _, c := range escape { + s = strings.ReplaceAll(s, c, `\`+c) + } + return s +} + +func terminalTrim(msg string) string { + // If we're not running on a terminal, return the whole string + size, _, err := terminal.GetSize(1) + if err != nil { + return msg + } + + // Otherwise, trim to fit half the terminal + size /= 2 + for utf8.RuneCountInString(msg) > size { + msg = msg[0:len(msg)-4] + "…" + } + return msg +} + +func loadCode(path string) (*compiler.Value, error) { + src, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + + val, err := compiler.Compile("", string(src)) + if err != nil { + return nil, err + } + + return val, nil +} + +func PrintDoc(ctx context.Context, val *compiler.Value, format string) { + lg := log.Ctx(ctx) + + environment.ScanOutputs(ctx, val) +} diff --git a/cmd/dagger/cmd/root.go b/cmd/dagger/cmd/root.go index 19ab0229..a4d0a061 100644 --- a/cmd/dagger/cmd/root.go +++ b/cmd/dagger/cmd/root.go @@ -46,6 +46,7 @@ func init() { input.Cmd, output.Cmd, versionCmd, + docCmd, ) if err := viper.BindPFlags(rootCmd.PersistentFlags()); err != nil { diff --git a/environment/environment.go b/environment/environment.go index a0aa24b7..260fd47d 100644 --- a/environment/environment.go +++ b/environment/environment.go @@ -320,7 +320,7 @@ func (e *Environment) ScanInputs(ctx context.Context, mergeUserInputs bool) ([]* } } - return scanInputs(ctx, src), nil + return ScanInputs(ctx, src), nil } func (e *Environment) ScanOutputs(ctx context.Context) ([]*compiler.Value, error) { @@ -340,5 +340,5 @@ func (e *Environment) ScanOutputs(ctx context.Context) ([]*compiler.Value, error } } - return scanOutputs(ctx, src), nil + return ScanOutputs(ctx, src), nil } diff --git a/environment/inputs_scan.go b/environment/inputs_scan.go index 0939a9ac..7b3a3648 100644 --- a/environment/inputs_scan.go +++ b/environment/inputs_scan.go @@ -42,7 +42,7 @@ func isReference(val cue.Value) bool { return isRef(val) } -func scanInputs(ctx context.Context, value *compiler.Value) []*compiler.Value { +func ScanInputs(ctx context.Context, value *compiler.Value) []*compiler.Value { lg := log.Ctx(ctx) inputs := []*compiler.Value{} @@ -67,7 +67,7 @@ func scanInputs(ctx context.Context, value *compiler.Value) []*compiler.Value { return inputs } -func scanOutputs(ctx context.Context, value *compiler.Value) []*compiler.Value { +func ScanOutputs(ctx context.Context, value *compiler.Value) []*compiler.Value { lg := log.Ctx(ctx) inputs := []*compiler.Value{} diff --git a/go.mod b/go.mod index 0ed3cba4..8352a529 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/uber/jaeger-lib v2.4.1+incompatible // indirect go.mozilla.org/sops/v3 v3.7.1 go.uber.org/atomic v1.7.0 // indirect + golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 golang.org/x/net v0.0.0-20210331212208-0fccb6fa2b5c // indirect golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1