Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dagger: function completion #2246

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions completers/dagger_completer/cmd/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ var callCmd = &cobra.Command{

func init() {
carapace.Gen(callCmd).Standalone()
callCmd.Flags().SetInterspersed(false)

callCmd.PersistentFlags().Bool("focus", false, "Only show output for focused commands")
callCmd.PersistentFlags().Bool("json", false, "Present result as JSON")
Expand Down
1 change: 1 addition & 0 deletions completers/dagger_completer/cmd/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func init() {
carapace.Gen(functionsCmd).Standalone()

functionsCmd.PersistentFlags().Bool("focus", false, "Only show output for focused commands")
functionsCmd.PersistentFlags().Bool("json", false, "Output as json")
functionsCmd.PersistentFlags().StringP("mod", "m", "", "Path to dagger.json config file for the module or a directory containing that file. Either local path (e.g. \"/path/to/some/dir\") or a github repo (e.g. \"github.com/dagger/dagger/path/to/some/subdir\")")
rootCmd.AddCommand(functionsCmd)

Expand Down
6 changes: 6 additions & 0 deletions completers/dagger_completer/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"github.com/rsteube/carapace"
"github.com/rsteube/carapace-bridge/pkg/actions/bridge"
"github.com/spf13/cobra"
)

Expand All @@ -15,8 +16,13 @@ var runCmd = &cobra.Command{

func init() {
carapace.Gen(runCmd).Standalone()
runCmd.Flags().SetInterspersed(false)

runCmd.Flags().String("cleanup-timeout", "", "max duration to wait between SIGTERM and SIGKILL on interrupt")
runCmd.Flags().Bool("focus", false, "Only show output for focused commands.")
rootCmd.AddCommand(runCmd)

carapace.Gen(runCmd).PositionalAnyCompletion(
bridge.ActionCarapaceBin(),
)
}
133 changes: 120 additions & 13 deletions pkg/actions/tools/dagger/function.go
Original file line number Diff line number Diff line change
@@ -1,27 +1,134 @@
package dagger

import (
"regexp"
"strings"
"encoding/json"
"os"
"time"
"unicode"

"github.com/rsteube/carapace"
"github.com/rsteube/carapace/pkg/cache"
"github.com/rsteube/carapace/pkg/cache/key"
"github.com/spf13/cobra"
)

// ActionFunctions completes functions
type function struct {
Name string `json:"Name"`
Description string `json:"Description"`
Args []struct {
Name string `json:"Name"`
Description string `json:"Description"`
TypeDef struct {
Kind string `json:"Kind"`
Optional bool `json:"Optional"`
AsObject *struct {
Name string `json:"Name"`
Functions any `json:"Functions"`
Fields any `json:"Fields"`
Constructor any `json:"Constructor"`
SourceModuleName string `json:"SourceModuleName"`
} `json:"AsObject"`
AsInterface any `json:"AsInterface"`
AsInput any `json:"AsInput"`
AsList any `json:"AsList"`
} `json:"TypeDef"`
DefaultValue string `json:"DefaultValue"`
} `json:"Args"`
}

type daggerFile struct {
Name string
Sdk string
Source string
}

// ActionFunctions completes functions and their arguments
//
// container-echo (dagger call container-echo --string-arg yo stdout)
// grep-dir (dagger call grep-dir --directory-arg . --pattern GrepDir)
// --directory-arg
func ActionFunctions() carapace.Action {
return carapace.ActionExecCommand("dagger", "functions", "--silent")(func(output []byte) carapace.Action {
lines := strings.Split(string(output), "\n")
r := regexp.MustCompile(`^(?P<name>[^ ]+) +example usage: "(?P<example>.*)"$`)

vals := make([]string, 0)
for _, line := range lines[1:] {
if matches := r.FindStringSubmatch(line); matches != nil {
vals = append(vals, matches[1], matches[2])
return carapace.ActionCallback(func(c carapace.Context) carapace.Action {
content, err := os.ReadFile("dagger.json")
if err != nil {
return carapace.ActionMessage(err.Error())
}

var d daggerFile
if err := json.Unmarshal(content, &d); err != nil {
return carapace.ActionMessage(err.Error())
}

output, err := cache.Cache(24*time.Hour, key.FolderStats(d.Source))(func() ([]byte, error) {
return c.Command("dagger", "functions", "--json").Output()
})
if err != nil {
return carapace.ActionMessage(err.Error())
}

var functions []function
if err := json.Unmarshal(output, &functions); err != nil {
return carapace.ActionMessage(err.Error())
}

cmd := &cobra.Command{}
carapace.Gen(cmd).Standalone()
for _, f := range functions {
f.Name = toKebab(f.Name)
subCmd := &cobra.Command{
Use: f.Name,
Short: f.Description,
Run: func(cmd *cobra.Command, args []string) {},
}
carapace.Gen(subCmd).Standalone()

for _, arg := range f.Args {
arg.Name = toKebab(arg.Name)

// TODO transform camelcase to kebab
switch arg.TypeDef.Kind { // TODO more types
case "STRING_KIND", "OBJECT_KIND":
subCmd.Flags().String(arg.Name, arg.DefaultValue, arg.Description)
default:
return carapace.ActionMessage("unknown kind %s", arg.TypeDef.Kind)
}

if arg.TypeDef.Optional {
subCmd.Flag(arg.Name).NoOptDefVal = " "
}

localArg := arg
carapace.Gen(subCmd).FlagCompletion(carapace.ActionMap{
arg.Name: carapace.ActionCallback(func(c carapace.Context) carapace.Action {
if localArg.TypeDef.AsObject == nil {
return carapace.ActionValues()
}

switch localArg.TypeDef.AsObject.Name { // TODO more
case "Directory":
return carapace.ActionDirectories()
case "File":
return carapace.ActionFiles()
default:
return carapace.ActionValues()
}
}),
})
}

cmd.AddCommand(subCmd)
}
return carapace.ActionValuesDescribed(vals...)

return carapace.ActionExecute(cmd)
})
}

func toKebab(s string) string {
runes := make([]rune, 0)
for _, r := range []rune(s) {

Check failure on line 127 in pkg/actions/tools/dagger/function.go

View workflow job for this annotation

GitHub Actions / build

should range over string, not []rune(string) (S1029)

Check failure on line 127 in pkg/actions/tools/dagger/function.go

View workflow job for this annotation

GitHub Actions / build

should range over string, not []rune(string) (SA6003)

Check failure on line 127 in pkg/actions/tools/dagger/function.go

View workflow job for this annotation

GitHub Actions / build

should range over string, not []rune(string) (S1029)

Check failure on line 127 in pkg/actions/tools/dagger/function.go

View workflow job for this annotation

GitHub Actions / build

should range over string, not []rune(string) (SA6003)
if unicode.IsUpper(r) {
runes = append(runes, '-')
}
runes = append(runes, unicode.ToLower(r))
}
return string(runes)
}
Loading