coder/scripts/rbacgen/main.go

91 lines
1.8 KiB
Go

package main
import (
"bytes"
"context"
_ "embed"
"fmt"
"go/format"
"go/types"
"html/template"
"log"
"os"
"sort"
"golang.org/x/tools/go/packages"
)
//go:embed object.gotmpl
var objectGoTpl string
type TplState struct {
ResourceNames []string
}
// main will generate a file that lists all rbac objects.
// This is to provide an "AllResources" function that is always
// in sync.
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
path := "."
if len(os.Args) > 1 {
path = os.Args[1]
}
cfg := &packages.Config{
Mode: packages.NeedTypes | packages.NeedName | packages.NeedTypesInfo | packages.NeedDeps,
Tests: false,
Context: ctx,
}
pkgs, err := packages.Load(cfg, path)
if err != nil {
log.Fatalf("Failed to load package: %s", err.Error())
}
if len(pkgs) != 1 {
log.Fatalf("Expected 1 package, got %d", len(pkgs))
}
rbacPkg := pkgs[0]
if rbacPkg.Name != "rbac" {
log.Fatalf("Expected rbac package, got %q", rbacPkg.Name)
}
tpl, err := template.New("object.gotmpl").Parse(objectGoTpl)
if err != nil {
log.Fatalf("Failed to parse templates: %s", err.Error())
}
var out bytes.Buffer
err = tpl.Execute(&out, TplState{
ResourceNames: allResources(rbacPkg),
})
if err != nil {
log.Fatalf("Execute template: %s", err.Error())
}
formatted, err := format.Source(out.Bytes())
if err != nil {
log.Fatalf("Format template: %s", err.Error())
}
_, _ = fmt.Fprint(os.Stdout, string(formatted))
}
func allResources(pkg *packages.Package) []string {
var resources []string
names := pkg.Types.Scope().Names()
for _, name := range names {
obj, ok := pkg.Types.Scope().Lookup(name).(*types.Var)
if ok && obj.Type().String() == "github.com/coder/coder/v2/coderd/rbac.Object" {
resources = append(resources, obj.Name())
}
}
sort.Strings(resources)
return resources
}