mirror of https://github.com/pulumi/pulumi.git
172 lines
4.1 KiB
Go
172 lines
4.1 KiB
Go
// Copyright 2016-2023, Pulumi Corporation.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// gen-pux-applyn generates Apply functions for the pulumix package.
|
|
// For each N in 1..8, it generates the following functions
|
|
// (type parameters elided for brevity):
|
|
//
|
|
// func ApplyN(T1, ..., TN, func(I1, ..., IN) O) Output[O]
|
|
// func ApplyNErr(T1, ..., TN, func(I1, ..., IN) (O, error)) Output[O]
|
|
// func ApplyNContext(context.Context, T1, ..., TN, func(I1, ..., IN) O) Output[O]
|
|
// func ApplyNContextErr(context.Context, T1, ..., TN, func(I1, ..., IN) (O, error)) Output[O]
|
|
//
|
|
// // Where each Ti satisfies Input[Ii].
|
|
//
|
|
// The output of this program should be placed in the pulumix package.
|
|
// It assumes availability of unexported types and functions from that package.
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"embed"
|
|
"flag"
|
|
"fmt"
|
|
"go/format"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"text/template"
|
|
"time"
|
|
|
|
"github.com/hashicorp/go-multierror"
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
|
|
)
|
|
|
|
func main() {
|
|
log.SetFlags(0) // don't print timestamps
|
|
|
|
var p params
|
|
flag.StringVar(&p.Dir, "d", "", "output directory (default: current directory)")
|
|
flag.IntVar(&p.N, "n", 0, "generate Apply functions for 1..n parameters")
|
|
flag.Parse()
|
|
|
|
if err := run(&p); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
type params struct {
|
|
Dir string // output directory
|
|
N int // max parameter count for an Apply function
|
|
}
|
|
|
|
func run(p *params) error {
|
|
if p.N == 0 {
|
|
p.N = 8
|
|
}
|
|
|
|
if p.Dir == "" {
|
|
cwd, err := os.Getwd()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
p.Dir = cwd
|
|
}
|
|
|
|
g := generator{Dir: p.Dir}
|
|
g.Generate(1, p.N)
|
|
return g.Err()
|
|
}
|
|
|
|
var (
|
|
//go:embed tmpl/*
|
|
_tmplFS embed.FS
|
|
|
|
_tmpl = template.Must(
|
|
template.New("").
|
|
Funcs(template.FuncMap{
|
|
"seq": seq,
|
|
}).
|
|
ParseFS(_tmplFS, "tmpl/*"),
|
|
)
|
|
)
|
|
|
|
// seq generates a slice in the range [start, stop] (inclusive).
|
|
// It is necessary because text/template does not support three-clause for loops.
|
|
func seq(start, stop int) []int {
|
|
result := make([]int, stop-start+1)
|
|
for i := range result {
|
|
result[i] = start + i
|
|
}
|
|
return result
|
|
}
|
|
|
|
type generator struct {
|
|
Dir string // output directory
|
|
|
|
// Errors encountered during generation.
|
|
errors []error
|
|
}
|
|
|
|
// Err returns an error if any errors were encountered during generation.
|
|
func (g *generator) Err() error {
|
|
if len(g.errors) == 0 {
|
|
return nil
|
|
}
|
|
return &multierror.Error{Errors: g.errors}
|
|
}
|
|
|
|
// Generate generates apply functions for parameters in the range
|
|
// [start, stop] (inclusive).
|
|
func (g *generator) Generate(start, stop int) {
|
|
data := struct {
|
|
Start int
|
|
Stop int
|
|
Year int
|
|
}{
|
|
Start: start,
|
|
Stop: stop,
|
|
Year: time.Now().Year(),
|
|
}
|
|
|
|
var src, test bytes.Buffer
|
|
g.executeTemplate(&src, "applyn.go.tmpl", data)
|
|
g.executeTemplate(&test, "applyn_test.go.tmpl", data)
|
|
g.writeGoFile("applyn.go", src.Bytes())
|
|
g.writeGoFile("applyn_test.go", test.Bytes())
|
|
}
|
|
|
|
func (g *generator) executeTemplate(w io.Writer, name string, data any) {
|
|
err := _tmpl.ExecuteTemplate(w, name, data)
|
|
if err != nil {
|
|
g.errf("execute template %s: %w", name, err)
|
|
}
|
|
}
|
|
|
|
func (g *generator) writeGoFile(relpath string, bs []byte) {
|
|
src, err := format.Source(bs)
|
|
if err != nil {
|
|
log.Printf("Invalid generated code:\n%s", bs)
|
|
g.errf("format %s: %w", relpath, err)
|
|
return
|
|
}
|
|
|
|
f, err := os.Create(filepath.Join(g.Dir, relpath))
|
|
if err != nil {
|
|
g.errf("create %s: %w", relpath, err)
|
|
return
|
|
}
|
|
defer contract.IgnoreClose(f)
|
|
|
|
_, err = f.Write(src)
|
|
if err != nil {
|
|
g.errf("write %s: %w", relpath, err)
|
|
}
|
|
}
|
|
|
|
func (g *generator) errf(format string, args ...any) {
|
|
g.errors = append(g.errors, fmt.Errorf(format, args...))
|
|
}
|