Switch remote deploy to vendored source builds
Move remote deployment to a vendored source bundle built on the target host via Docker so redeploys no longer require local cross-compilation or host Go installation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
384
vendor/github.com/wailsapp/wails/v2/internal/binding/binding.go
generated
vendored
Normal file
384
vendor/github.com/wailsapp/wails/v2/internal/binding/binding.go
generated
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
package binding
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/typescriptify"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
)
|
||||
|
||||
type Bindings struct {
|
||||
db *DB
|
||||
logger logger.CustomLogger
|
||||
exemptions slicer.StringSlicer
|
||||
|
||||
structsToGenerateTS map[string]map[string]interface{}
|
||||
enumsToGenerateTS map[string]map[string]interface{}
|
||||
tsPrefix string
|
||||
tsSuffix string
|
||||
tsInterface bool
|
||||
obfuscate bool
|
||||
}
|
||||
|
||||
// NewBindings returns a new Bindings object
|
||||
func NewBindings(logger *logger.Logger, structPointersToBind []interface{}, exemptions []interface{}, obfuscate bool, enumsToBind []interface{}) *Bindings {
|
||||
result := &Bindings{
|
||||
db: newDB(),
|
||||
logger: logger.CustomLogger("Bindings"),
|
||||
structsToGenerateTS: make(map[string]map[string]interface{}),
|
||||
enumsToGenerateTS: make(map[string]map[string]interface{}),
|
||||
obfuscate: obfuscate,
|
||||
}
|
||||
|
||||
for _, exemption := range exemptions {
|
||||
if exemption == nil {
|
||||
continue
|
||||
}
|
||||
name := runtime.FuncForPC(reflect.ValueOf(exemption).Pointer()).Name()
|
||||
// Yuk yuk yuk! Is there a better way?
|
||||
name = strings.TrimSuffix(name, "-fm")
|
||||
result.exemptions.Add(name)
|
||||
}
|
||||
|
||||
for _, enum := range enumsToBind {
|
||||
result.AddEnumToGenerateTS(enum)
|
||||
}
|
||||
|
||||
// Add the structs to bind
|
||||
for _, ptr := range structPointersToBind {
|
||||
err := result.Add(ptr)
|
||||
if err != nil {
|
||||
logger.Fatal("Error during binding: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Add the given struct methods to the Bindings
|
||||
func (b *Bindings) Add(structPtr interface{}) error {
|
||||
methods, err := b.getMethods(structPtr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot bind value to app: %s", err.Error())
|
||||
}
|
||||
|
||||
for _, method := range methods {
|
||||
b.db.AddMethod(method.Path.Package, method.Path.Struct, method.Path.Name, method)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bindings) DB() *DB {
|
||||
return b.db
|
||||
}
|
||||
|
||||
func (b *Bindings) ToJSON() (string, error) {
|
||||
return b.db.ToJSON()
|
||||
}
|
||||
|
||||
func (b *Bindings) GenerateModels() ([]byte, error) {
|
||||
models := map[string]string{}
|
||||
var seen slicer.StringSlicer
|
||||
var seenEnumsPackages slicer.StringSlicer
|
||||
allStructNames := b.getAllStructNames()
|
||||
allStructNames.Sort()
|
||||
allEnumNames := b.getAllEnumNames()
|
||||
allEnumNames.Sort()
|
||||
for packageName, structsToGenerate := range b.structsToGenerateTS {
|
||||
thisPackageCode := ""
|
||||
w := typescriptify.New()
|
||||
w.WithPrefix(b.tsPrefix)
|
||||
w.WithSuffix(b.tsSuffix)
|
||||
w.WithInterface(b.tsInterface)
|
||||
w.Namespace = packageName
|
||||
w.WithBackupDir("")
|
||||
w.KnownStructs = allStructNames
|
||||
w.KnownEnums = allEnumNames
|
||||
// sort the structs
|
||||
var structNames []string
|
||||
for structName := range structsToGenerate {
|
||||
structNames = append(structNames, structName)
|
||||
}
|
||||
sort.Strings(structNames)
|
||||
for _, structName := range structNames {
|
||||
fqstructname := packageName + "." + structName
|
||||
if seen.Contains(fqstructname) {
|
||||
continue
|
||||
}
|
||||
structInterface := structsToGenerate[structName]
|
||||
w.Add(structInterface)
|
||||
}
|
||||
|
||||
// if we have enums for this package, add them as well
|
||||
var enums, enumsExist = b.enumsToGenerateTS[packageName]
|
||||
if enumsExist {
|
||||
// Sort the enum names first to make the output deterministic
|
||||
sortedEnumNames := make([]string, 0, len(enums))
|
||||
for enumName := range enums {
|
||||
sortedEnumNames = append(sortedEnumNames, enumName)
|
||||
}
|
||||
sort.Strings(sortedEnumNames)
|
||||
|
||||
for _, enumName := range sortedEnumNames {
|
||||
enum := enums[enumName]
|
||||
fqemumname := packageName + "." + enumName
|
||||
if seen.Contains(fqemumname) {
|
||||
continue
|
||||
}
|
||||
w.AddEnum(enum)
|
||||
}
|
||||
seenEnumsPackages.Add(packageName)
|
||||
}
|
||||
|
||||
str, err := w.Convert(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
thisPackageCode += str
|
||||
seen.AddSlice(w.GetGeneratedStructs())
|
||||
models[packageName] = thisPackageCode
|
||||
}
|
||||
|
||||
// Add outstanding enums to the models that were not in packages with structs
|
||||
for packageName, enumsToGenerate := range b.enumsToGenerateTS {
|
||||
if seenEnumsPackages.Contains(packageName) {
|
||||
continue
|
||||
}
|
||||
|
||||
thisPackageCode := ""
|
||||
w := typescriptify.New()
|
||||
w.WithPrefix(b.tsPrefix)
|
||||
w.WithSuffix(b.tsSuffix)
|
||||
w.WithInterface(b.tsInterface)
|
||||
w.Namespace = packageName
|
||||
w.WithBackupDir("")
|
||||
|
||||
for enumName, enum := range enumsToGenerate {
|
||||
fqemumname := packageName + "." + enumName
|
||||
if seen.Contains(fqemumname) {
|
||||
continue
|
||||
}
|
||||
w.AddEnum(enum)
|
||||
}
|
||||
str, err := w.Convert(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
thisPackageCode += str
|
||||
models[packageName] = thisPackageCode
|
||||
}
|
||||
|
||||
// Sort the package names first to make the output deterministic
|
||||
sortedPackageNames := make([]string, 0, len(models))
|
||||
for packageName := range models {
|
||||
sortedPackageNames = append(sortedPackageNames, packageName)
|
||||
}
|
||||
sort.Strings(sortedPackageNames)
|
||||
|
||||
var modelsData bytes.Buffer
|
||||
for _, packageName := range sortedPackageNames {
|
||||
modelData := models[packageName]
|
||||
if strings.TrimSpace(modelData) == "" {
|
||||
continue
|
||||
}
|
||||
modelsData.WriteString("export namespace " + packageName + " {\n")
|
||||
sc := bufio.NewScanner(strings.NewReader(modelData))
|
||||
for sc.Scan() {
|
||||
modelsData.WriteString("\t" + sc.Text() + "\n")
|
||||
}
|
||||
modelsData.WriteString("\n}\n\n")
|
||||
}
|
||||
return modelsData.Bytes(), nil
|
||||
}
|
||||
|
||||
func (b *Bindings) WriteModels(modelsDir string) error {
|
||||
modelsData, err := b.GenerateModels()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Don't write if we don't have anything
|
||||
if len(modelsData) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
filename := filepath.Join(modelsDir, "models.ts")
|
||||
err = os.WriteFile(filename, modelsData, 0o755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bindings) AddEnumToGenerateTS(e interface{}) {
|
||||
enumType := reflect.TypeOf(e)
|
||||
|
||||
var packageName string
|
||||
var enumName string
|
||||
// enums should be represented as array of all possible values
|
||||
if hasElements(enumType) {
|
||||
enum := enumType.Elem()
|
||||
// simple enum represented by struct with Value/TSName fields
|
||||
if enum.Kind() == reflect.Struct {
|
||||
_, tsNamePresented := enum.FieldByName("TSName")
|
||||
enumT, valuePresented := enum.FieldByName("Value")
|
||||
if tsNamePresented && valuePresented {
|
||||
packageName = getPackageName(enumT.Type.String())
|
||||
enumName = enumT.Type.Name()
|
||||
} else {
|
||||
return
|
||||
}
|
||||
// otherwise expecting implementation with TSName() https://github.com/tkrajina/typescriptify-golang-structs#enums-with-tsname
|
||||
} else {
|
||||
packageName = getPackageName(enumType.Elem().String())
|
||||
enumName = enumType.Elem().Name()
|
||||
}
|
||||
if b.enumsToGenerateTS[packageName] == nil {
|
||||
b.enumsToGenerateTS[packageName] = make(map[string]interface{})
|
||||
}
|
||||
if b.enumsToGenerateTS[packageName][enumName] != nil {
|
||||
return
|
||||
}
|
||||
b.enumsToGenerateTS[packageName][enumName] = e
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bindings) AddStructToGenerateTS(packageName string, structName string, s interface{}) {
|
||||
if b.structsToGenerateTS[packageName] == nil {
|
||||
b.structsToGenerateTS[packageName] = make(map[string]interface{})
|
||||
}
|
||||
if b.structsToGenerateTS[packageName][structName] != nil {
|
||||
return
|
||||
}
|
||||
b.structsToGenerateTS[packageName][structName] = s
|
||||
|
||||
// Iterate this struct and add any struct field references
|
||||
structType := reflect.TypeOf(s)
|
||||
for hasElements(structType) {
|
||||
structType = structType.Elem()
|
||||
}
|
||||
|
||||
for i := 0; i < structType.NumField(); i++ {
|
||||
field := structType.Field(i)
|
||||
if field.Anonymous || !field.IsExported() {
|
||||
continue
|
||||
}
|
||||
kind := field.Type.Kind()
|
||||
if kind == reflect.Struct {
|
||||
fqname := field.Type.String()
|
||||
sNameSplit := strings.SplitN(fqname, ".", 2)
|
||||
if len(sNameSplit) < 2 {
|
||||
continue
|
||||
}
|
||||
sName := sNameSplit[1]
|
||||
pName := getPackageName(fqname)
|
||||
a := reflect.New(field.Type)
|
||||
if b.hasExportedJSONFields(field.Type) {
|
||||
s := reflect.Indirect(a).Interface()
|
||||
b.AddStructToGenerateTS(pName, sName, s)
|
||||
}
|
||||
} else {
|
||||
fType := field.Type
|
||||
for hasElements(fType) {
|
||||
fType = fType.Elem()
|
||||
}
|
||||
if fType.Kind() == reflect.Struct {
|
||||
fqname := fType.String()
|
||||
sNameSplit := strings.SplitN(fqname, ".", 2)
|
||||
if len(sNameSplit) < 2 {
|
||||
continue
|
||||
}
|
||||
sName := sNameSplit[1]
|
||||
pName := getPackageName(fqname)
|
||||
a := reflect.New(fType)
|
||||
if b.hasExportedJSONFields(fType) {
|
||||
s := reflect.Indirect(a).Interface()
|
||||
b.AddStructToGenerateTS(pName, sName, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bindings) SetTsPrefix(prefix string) *Bindings {
|
||||
b.tsPrefix = prefix
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bindings) SetTsSuffix(postfix string) *Bindings {
|
||||
b.tsSuffix = postfix
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bindings) SetOutputType(outputType string) *Bindings {
|
||||
if outputType == "interfaces" {
|
||||
b.tsInterface = true
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Bindings) getAllStructNames() *slicer.StringSlicer {
|
||||
var result slicer.StringSlicer
|
||||
for packageName, structsToGenerate := range b.structsToGenerateTS {
|
||||
for structName := range structsToGenerate {
|
||||
result.Add(packageName + "." + structName)
|
||||
}
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
func (b *Bindings) getAllEnumNames() *slicer.StringSlicer {
|
||||
var result slicer.StringSlicer
|
||||
for packageName, enumsToGenerate := range b.enumsToGenerateTS {
|
||||
for enumName := range enumsToGenerate {
|
||||
result.Add(packageName + "." + enumName)
|
||||
}
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
func (b *Bindings) hasExportedJSONFields(typeOf reflect.Type) bool {
|
||||
for i := 0; i < typeOf.NumField(); i++ {
|
||||
jsonFieldName := ""
|
||||
f := typeOf.Field(i)
|
||||
// function, complex, and channel types cannot be json-encoded
|
||||
if f.Type.Kind() == reflect.Chan ||
|
||||
f.Type.Kind() == reflect.Func ||
|
||||
f.Type.Kind() == reflect.UnsafePointer ||
|
||||
f.Type.Kind() == reflect.Complex128 ||
|
||||
f.Type.Kind() == reflect.Complex64 {
|
||||
continue
|
||||
}
|
||||
jsonTag, hasTag := f.Tag.Lookup("json")
|
||||
if !hasTag && f.IsExported() {
|
||||
return true
|
||||
}
|
||||
if len(jsonTag) == 0 {
|
||||
continue
|
||||
}
|
||||
jsonTagParts := strings.Split(jsonTag, ",")
|
||||
if len(jsonTagParts) > 0 {
|
||||
jsonFieldName = jsonTagParts[0]
|
||||
}
|
||||
for _, t := range jsonTagParts {
|
||||
if t == "-" {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if jsonFieldName != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user