generate.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Copyright © 2019 - 2020 Oscar Campos <oscar.campos@thepimpam.com>
  2. // Copyright © 2017 - William Edwards
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License
  15. package main
  16. import (
  17. "fmt"
  18. "go/parser"
  19. "go/token"
  20. "os"
  21. "os/exec"
  22. "path/filepath"
  23. "runtime"
  24. "strings"
  25. "text/template"
  26. "git.alfi.li/gamelang/gdnative-go/gdnative"
  27. )
  28. // RegistryData structure is a container for registrable classes
  29. // that is passed to the gdnative_wrapper.go.tmpl template for filling
  30. type RegistryData struct {
  31. Package string
  32. Classes map[string]gdnative.Registrable
  33. }
  34. // GDNativeInit construct and returns a SetNativeInitScript call
  35. func (rd RegistryData) GDNativeInit() string {
  36. initFunctions := []string{}
  37. for className := range rd.Classes {
  38. initFunctions = append(initFunctions, fmt.Sprintf("nativeScriptInit%s", className))
  39. }
  40. return fmt.Sprintf("gdnative.SetNativeScriptInit(%s)", strings.Join(initFunctions, ", "))
  41. }
  42. func (cmd *generateCmd) Run(ctx *context) error {
  43. fset := token.NewFileSet()
  44. packages, parseErr := parser.ParseDir(fset, ctx.Path, cmd.filter, parser.ParseComments)
  45. if parseErr != nil {
  46. return fmt.Errorf("could not parse Go files at %s: %w", ctx.Path, parseErr)
  47. }
  48. tplPath, pathErr := getTemplatePath("gdnative_wrapper.go")
  49. if pathErr != nil {
  50. return fmt.Errorf("could not get GDNative template: %w", pathErr)
  51. }
  52. for pkg, p := range packages {
  53. data := RegistryData{Package: pkg, Classes: map[string]gdnative.Registrable{}}
  54. registrable := gdnative.LookupRegistrableTypeDeclarations(p)
  55. if len(registrable) == 0 {
  56. fmt.Printf("not found any registrable sources on %s", ctx.Path)
  57. return nil
  58. }
  59. for className, classData := range registrable {
  60. data.Classes[className] = classData
  61. }
  62. // create a template from the template file
  63. tpl, tplErr := template.ParseFiles(tplPath)
  64. if tplErr != nil {
  65. return tplErr
  66. }
  67. outputFileName := fmt.Sprintf("%s_registrable.gen.go", pkg)
  68. outputFilePath := filepath.Join(ctx.Path, outputFileName)
  69. file, fileErr := os.Create(outputFilePath)
  70. if fileErr != nil {
  71. return fmt.Errorf("can not open output file %s for writing: %w", outputFilePath, fileErr)
  72. }
  73. execErr := tpl.Execute(file, data)
  74. if execErr != nil {
  75. return execErr
  76. }
  77. return format(outputFilePath)
  78. }
  79. return nil
  80. }
  81. // get the template path
  82. func getTemplatePath(templateType string) (string, error) {
  83. currentPath, err := getCurrentPath()
  84. if err != nil {
  85. return "", err
  86. }
  87. return filepath.Join(currentPath, "..", "..", "generate", "templates", templateType+".tmpl"), nil
  88. }
  89. // get the current in execution file path on disk
  90. func getCurrentPath() (string, error) {
  91. _, filename, _, ok := runtime.Caller(0)
  92. if !ok {
  93. return "", fmt.Errorf("could not get current file execution path")
  94. }
  95. return filename, nil
  96. }
  97. func (cmd *generateCmd) filter(info os.FileInfo) bool {
  98. if info.IsDir() {
  99. return false
  100. }
  101. length := len(info.Name())
  102. if length > 7 && info.Name()[length-7:length-2] == ".gen." {
  103. return false
  104. }
  105. return true
  106. }
  107. // formats the given path with gofmt
  108. func format(filepath string) error {
  109. fmt.Println("gofmt", "-w", filepath)
  110. cmd := exec.Command("gofmt", "-w", filepath)
  111. return cmd.Run()
  112. }