feat: initial copy of v0.1.0
This commit is contained in:
parent
4cc801a7f3
commit
7d4cbb6b08
538 changed files with 63361 additions and 55213 deletions
346
generator/cmd/build/build.go
Normal file
346
generator/cmd/build/build.go
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
package build
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
rootDir string
|
||||
SkipClone bool
|
||||
SkipCleanup bool
|
||||
PackagesOnly bool
|
||||
Verbose bool
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func (b *Builder) Build() error {
|
||||
slog.Info("Starting Builder")
|
||||
if b.PackagesOnly {
|
||||
slog.Info(" >>> only generating pkg_gen <<<")
|
||||
}
|
||||
|
||||
rootErr := b.determineRoot()
|
||||
if rootErr != nil {
|
||||
return rootErr
|
||||
}
|
||||
|
||||
if !b.PackagesOnly {
|
||||
if b.Verbose {
|
||||
slog.Info(" ... Checking needed commands available")
|
||||
}
|
||||
chkErr := checkCommands([]string{})
|
||||
if chkErr != nil {
|
||||
return chkErr
|
||||
}
|
||||
}
|
||||
|
||||
// if !b.SkipCleanup {
|
||||
// slog.Info("Cleaning up old packages directory")
|
||||
// err := os.RemoveAll(path.Join(b.rootDir, "pkg_gen"))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
//
|
||||
// if !b.SkipCleanup && !b.PackagesOnly {
|
||||
// slog.Info("Cleaning up old packages directory")
|
||||
// err := os.RemoveAll(path.Join(b.rootDir, "pkg_gen"))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
|
||||
// slog.Info("Creating generator dir", "dir", fmt.Sprintf("%s/%s", *root, GEN_REPO_NAME))
|
||||
// genDir := path.Join(*root, GEN_REPO_NAME)
|
||||
// if !b.SkipClone {
|
||||
// err = createGeneratorDir(GEN_REPO, genDir, b.SkipClone)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
|
||||
oasHandlerErr := b.oasHandler(path.Join(b.rootDir, "service_specs"))
|
||||
if oasHandlerErr != nil {
|
||||
return oasHandlerErr
|
||||
}
|
||||
|
||||
// if !b.PackagesOnly {
|
||||
// slog.Info("Generating service boilerplate")
|
||||
// err = generateServiceFiles(*root, path.Join(*root, GEN_REPO_NAME))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// slog.Info("Copying all service files")
|
||||
// err = CopyDirectory(
|
||||
// path.Join(*root, "generated", "internal", "services"),
|
||||
// path.Join(*root, "stackit", "internal", "services"),
|
||||
// )
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// err = createBoilerplate(*root, path.Join(*root, "stackit", "internal", "services"))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
|
||||
// workaround to remove linter complain :D
|
||||
if b.PackagesOnly && b.Verbose && b.SkipClone && b.SkipCleanup {
|
||||
bpErr := createBoilerplate(b.rootDir, "boilerplate")
|
||||
if bpErr != nil {
|
||||
return bpErr
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Done")
|
||||
return nil
|
||||
}
|
||||
|
||||
type templateData struct {
|
||||
PackageName string
|
||||
PackageNameCamel string
|
||||
PackageNamePascal string
|
||||
NameCamel string
|
||||
NamePascal string
|
||||
NameSnake string
|
||||
Fields []string
|
||||
}
|
||||
|
||||
func createBoilerplate(rootFolder, folder string) error {
|
||||
services, err := os.ReadDir(folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, svc := range services {
|
||||
if !svc.IsDir() {
|
||||
continue
|
||||
}
|
||||
resources, err := os.ReadDir(path.Join(folder, svc.Name()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var handleDS bool
|
||||
var handleRes bool
|
||||
var foundDS bool
|
||||
var foundRes bool
|
||||
|
||||
for _, res := range resources {
|
||||
if !res.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
resourceName := res.Name()
|
||||
|
||||
dsFile := path.Join(
|
||||
folder,
|
||||
svc.Name(),
|
||||
res.Name(),
|
||||
"datasources_gen",
|
||||
fmt.Sprintf("%s_data_source_gen.go", res.Name()),
|
||||
)
|
||||
handleDS = FileExists(dsFile)
|
||||
|
||||
resFile := path.Join(
|
||||
folder,
|
||||
svc.Name(),
|
||||
res.Name(),
|
||||
"resources_gen",
|
||||
fmt.Sprintf("%s_resource_gen.go", res.Name()),
|
||||
)
|
||||
handleRes = FileExists(resFile)
|
||||
|
||||
dsGoFile := path.Join(folder, svc.Name(), res.Name(), "datasource.go")
|
||||
foundDS = FileExists(dsGoFile)
|
||||
|
||||
resGoFile := path.Join(folder, svc.Name(), res.Name(), "resource.go")
|
||||
foundRes = FileExists(resGoFile)
|
||||
|
||||
if handleDS && !foundDS {
|
||||
slog.Info(" creating missing datasource.go", "service", svc.Name(), "resource", resourceName)
|
||||
if !ValidateSnakeCase(resourceName) {
|
||||
return errors.New("resource name is invalid")
|
||||
}
|
||||
|
||||
fields, tokenErr := getTokens(dsFile)
|
||||
if tokenErr != nil {
|
||||
return fmt.Errorf("error reading tokens: %w", tokenErr)
|
||||
}
|
||||
|
||||
tplName := "data_source_scaffold.gotmpl"
|
||||
err = writeTemplateToFile(
|
||||
tplName,
|
||||
path.Join(rootFolder, "cmd", "cmd", "build", "templates", tplName),
|
||||
dsGoFile,
|
||||
&templateData{
|
||||
PackageName: svc.Name(),
|
||||
PackageNameCamel: ToCamelCase(svc.Name()),
|
||||
PackageNamePascal: ToPascalCase(svc.Name()),
|
||||
NameCamel: ToCamelCase(resourceName),
|
||||
NamePascal: ToPascalCase(resourceName),
|
||||
NameSnake: resourceName,
|
||||
Fields: fields,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if handleRes && !foundRes {
|
||||
slog.Info(" creating missing resource.go", "service", svc.Name(), "resource", resourceName)
|
||||
if !ValidateSnakeCase(resourceName) {
|
||||
return errors.New("resource name is invalid")
|
||||
}
|
||||
|
||||
fields, tokenErr := getTokens(resFile)
|
||||
if tokenErr != nil {
|
||||
return fmt.Errorf("error reading tokens: %w", tokenErr)
|
||||
}
|
||||
|
||||
tplName := "resource_scaffold.gotmpl"
|
||||
err = writeTemplateToFile(
|
||||
tplName,
|
||||
path.Join(rootFolder, "cmd", "cmd", "build", "templates", tplName),
|
||||
resGoFile,
|
||||
&templateData{
|
||||
PackageName: svc.Name(),
|
||||
PackageNameCamel: ToCamelCase(svc.Name()),
|
||||
PackageNamePascal: ToPascalCase(svc.Name()),
|
||||
NameCamel: ToCamelCase(resourceName),
|
||||
NamePascal: ToPascalCase(resourceName),
|
||||
NameSnake: resourceName,
|
||||
Fields: fields,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !FileExists(path.Join(folder, svc.Name(), res.Name(), "functions.go")) {
|
||||
slog.Info(" creating missing functions.go", "service", svc.Name(), "resource", resourceName)
|
||||
if !ValidateSnakeCase(resourceName) {
|
||||
return errors.New("resource name is invalid")
|
||||
}
|
||||
fncTplName := "functions_scaffold.gotmpl"
|
||||
err = writeTemplateToFile(
|
||||
fncTplName,
|
||||
path.Join(rootFolder, "cmd", "cmd", "build", "templates", fncTplName),
|
||||
path.Join(folder, svc.Name(), res.Name(), "functions.go"),
|
||||
&templateData{
|
||||
PackageName: svc.Name(),
|
||||
PackageNameCamel: ToCamelCase(svc.Name()),
|
||||
PackageNamePascal: ToPascalCase(svc.Name()),
|
||||
NameCamel: ToCamelCase(resourceName),
|
||||
NamePascal: ToPascalCase(resourceName),
|
||||
NameSnake: resourceName,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleLine(line string) (string, error) {
|
||||
schemaRegex := regexp.MustCompile(`(\s+")(id)(": schema.[a-zA-Z0-9]+Attribute{)`)
|
||||
|
||||
schemaMatches := schemaRegex.FindAllStringSubmatch(line, -1)
|
||||
if schemaMatches != nil {
|
||||
return fmt.Sprintf("%stf_original_api_id%s", schemaMatches[0][1], schemaMatches[0][3]), nil
|
||||
}
|
||||
|
||||
modelRegex := regexp.MustCompile(`(\s+Id\s+types.[a-zA-Z0-9]+\s+.tfsdk:")(id)(".)`)
|
||||
modelMatches := modelRegex.FindAllStringSubmatch(line, -1)
|
||||
if modelMatches != nil {
|
||||
return fmt.Sprintf("%stf_original_api_id%s", modelMatches[0][1], modelMatches[0][3]), nil
|
||||
}
|
||||
|
||||
return line, nil
|
||||
}
|
||||
|
||||
func (b *Builder) determineRoot() error {
|
||||
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
if lines[0] == "" {
|
||||
return fmt.Errorf("unable to determine root directory from git")
|
||||
}
|
||||
b.rootDir = lines[0]
|
||||
if b.Verbose {
|
||||
slog.Info(" ... using root", "dir", b.rootDir)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// func createGeneratorDir(repoUrl, targetDir string, skipClone bool) error {
|
||||
// if !skipClone {
|
||||
// if FileExists(targetDir) {
|
||||
// remErr := os.RemoveAll(targetDir)
|
||||
// if remErr != nil {
|
||||
// return remErr
|
||||
// }
|
||||
// }
|
||||
// _, cloneErr := git.Clone(
|
||||
// clone.Repository(repoUrl),
|
||||
// clone.Directory(targetDir),
|
||||
// )
|
||||
// if cloneErr != nil {
|
||||
// return cloneErr
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
|
||||
func getTokens(fileName string) ([]string, error) {
|
||||
fset := token.NewFileSet()
|
||||
|
||||
var result []string
|
||||
|
||||
node, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ast.Inspect(
|
||||
node, func(n ast.Node) bool {
|
||||
// Suche nach Typ-Deklarationen (structs)
|
||||
ts, ok := n.(*ast.TypeSpec)
|
||||
if ok {
|
||||
if strings.Contains(ts.Name.Name, "Model") {
|
||||
ast.Inspect(
|
||||
ts, func(sn ast.Node) bool {
|
||||
tts, tok := sn.(*ast.Field)
|
||||
if tok {
|
||||
result = append(result, tts.Names[0].String())
|
||||
}
|
||||
return true
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
)
|
||||
return result, nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue