diff --git a/internal/cmd/generate.go b/internal/cmd/generate.go index 00e8871c7e..de8342c4d9 100644 --- a/internal/cmd/generate.go +++ b/internal/cmd/generate.go @@ -349,6 +349,7 @@ func codegen(ctx context.Context, combo config.CombinedSettings, sql OutputPair, switch { case plug.Process != nil: handler = &process.Runner{ + GoPkg: plug.Process.GoPkg, Cmd: plug.Process.Cmd, Env: plug.Env, Format: plug.Process.Format, diff --git a/internal/config/config.go b/internal/config/config.go index 0ff805fccd..57ce814a8d 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -89,6 +89,7 @@ type Plugin struct { Name string `json:"name" yaml:"name"` Env []string `json:"env" yaml:"env"` Process *struct { + GoPkg string `json:"go_package" yaml:"go_package"` Cmd string `json:"cmd" yaml:"cmd"` Format string `json:"format" yaml:"format"` } `json:"process" yaml:"process"` @@ -159,7 +160,8 @@ var ErrPluginExists = errors.New("a plugin with that name already exists") var ErrPluginNotFound = errors.New("no plugin found") var ErrPluginNoType = errors.New("plugin: field `process` or `wasm` required") var ErrPluginBothTypes = errors.New("plugin: `process` and `wasm` cannot both be defined") -var ErrPluginProcessNoCmd = errors.New("plugin: missing process command") +var ErrPluginProcessTooManyCmd = errors.New("plugin: only one of `cmd` or `go_package` is allowed for process plugin") +var ErrPluginProcessNoCmd = errors.New("plugin: missing `cmd` or `go_package` for process plugin") var ErrInvalidDatabase = errors.New("database must be managed or have a non-empty URI") var ErrManagedDatabaseNoProject = errors.New(`managed databases require a cloud project diff --git a/internal/config/v_two.go b/internal/config/v_two.go index 0fe22ffa2c..a83de1d7d1 100644 --- a/internal/config/v_two.go +++ b/internal/config/v_two.go @@ -48,8 +48,11 @@ func v2ParseConfig(rd io.Reader) (Config, error) { if conf.Plugins[i].Process != nil && conf.Plugins[i].WASM != nil { return conf, ErrPluginBothTypes } - if conf.Plugins[i].Process != nil { - if conf.Plugins[i].Process.Cmd == "" { + if r := conf.Plugins[i].Process; r != nil { + switch { + case r.Cmd != "" && r.GoPkg != "": + return conf, ErrPluginProcessTooManyCmd + case r.Cmd == "" && r.GoPkg == "": return conf, ErrPluginProcessNoCmd } } diff --git a/internal/ext/process/gen.go b/internal/ext/process/gen.go index b5720dbc33..9507cfb9b2 100644 --- a/internal/ext/process/gen.go +++ b/internal/ext/process/gen.go @@ -19,6 +19,7 @@ import ( ) type Runner struct { + GoPkg string Cmd string Format string Env []string @@ -53,13 +54,39 @@ func (r *Runner) Invoke(ctx context.Context, method string, args any, reply any, return fmt.Errorf("unknown plugin format: %s", r.Format) } - // Check if the output plugin exists - path, err := exec.LookPath(r.Cmd) - if err != nil { - return fmt.Errorf("process: %s not found", r.Cmd) + var cmd *exec.Cmd + switch { + case r.Cmd != "": + // Check if the output plugin exists + path, err := exec.LookPath(r.Cmd) + if err != nil { + return fmt.Errorf("process: %s not found", r.Cmd) + } + cmd = exec.CommandContext(ctx, path, method) + case r.GoPkg != "": + // Check if the go binary exists + path, err := exec.LookPath("go") + if err != nil { + return fmt.Errorf("go binary required to run go package %s", r.GoPkg) + } + cmd = exec.CommandContext(ctx, path, method) + cmd.Args = []string{"go", "run", r.GoPkg} + r.Env = append(r.Env, []string{ + "GO111MODULE", + "GOROOT", + "GOPATH", + "GOPROXY", + "GOPRIVATE", + "GONOPROXY", + "GONOSUMDB", + "GOMODCACHE", + "GOFLAGS", + "GOCACHE", + "GOENV", + "HOME", + }...) } - cmd := exec.CommandContext(ctx, path, method) cmd.Stdin = bytes.NewReader(stdin) cmd.Env = []string{ fmt.Sprintf("SQLC_VERSION=%s", info.Version),