Skip to content

Commit

Permalink
Support application.New outside of main, ...
Browse files Browse the repository at this point in the history
- Add `BasePath`: The base package path
- Add `UseBaseName`: Place the base package bindings inside a folder with the base package name
- Add more tests
  • Loading branch information
abichinger committed Apr 21, 2024
1 parent d6f4385 commit ae10e75
Show file tree
Hide file tree
Showing 41 changed files with 586 additions and 39 deletions.
4 changes: 3 additions & 1 deletion v3/internal/flags/bindings.go
Expand Up @@ -9,7 +9,9 @@ import (

type GenerateBindingsOptions struct {
BuildFlagsString string `name:"f" description:"Provide a list of additional space-separated Go build flags. Flags can be wrapped (even partially) in single or double quotes to include spaces"`
ProjectDirectory string `name:"p" description:"The project directory" default:"."`
ProjectDirectory string `name:"p" description:"The project directory. Must contain a source file with application.New" default:"."`
BasePath string `name:"base" description:"The base package path" default:"."`
UseBaseName bool `name:"n" description:"Place the base package bindings inside a folder with the base package name"`
OutputDirectory string `name:"d" description:"The output directory" default:"assets/bindings"`
ModelsFilename string `name:"m" description:"The filename for the models file, excluding the extension" default:"models"`
TS bool `name:"ts" description:"Generate Typescript bindings"`
Expand Down
17 changes: 17 additions & 0 deletions v3/internal/parser/bindings_test.go
Expand Up @@ -312,6 +312,21 @@ func TestGenerateBindings(t *testing.T) {
},
},
},
{
name: "app_outside_main",
dir: "testdata/app_outside_main/app",
want: map[string]map[string]bool{
"app": {
"GreetService": true,
},
"services": {
"OtherService": true,
},
"github.com/wailsapp/wails/v3/internal/parser/testdata/app_outside_main/other": {
"OtherService": true,
},
},
},
}

type Test struct {
Expand Down Expand Up @@ -366,6 +381,8 @@ func TestGenerateBindings(t *testing.T) {
OutputDirectory: "frontend/bindings",
ProjectDirectory: absDir,
UseBundledRuntime: tt.useBundledRuntime,
BasePath: ".",
UseBaseName: true,
}

project, err := ParseProjectAndPkgs(options)
Expand Down
16 changes: 13 additions & 3 deletions v3/internal/parser/models_test.go
Expand Up @@ -131,8 +131,8 @@ func TestGenerateModels(t *testing.T) {
name: "multiple_packages",
dir: "testdata/multiple_packages",
want: map[string]bool{
"github.com-google-uuid": true,
"runtime-debug": true,
"github.com/google/uuid": true,
"runtime/debug": true,
"other": true,
"other/other": true,
},
Expand All @@ -151,6 +151,14 @@ func TestGenerateModels(t *testing.T) {
"main": true,
},
},
{
name: "app_outside_main",
dir: "testdata/app_outside_main/app",
want: map[string]bool{
"app": true,
"models": true,
},
},
}

type Test struct {
Expand Down Expand Up @@ -196,6 +204,8 @@ func TestGenerateModels(t *testing.T) {
ModelsFilename: "models",
OutputDirectory: "frontend/bindings",
ProjectDirectory: absDir,
BasePath: ".",
UseBaseName: true,
}

project, err := ParseProjectAndPkgs(options)
Expand All @@ -210,7 +220,7 @@ func TestGenerateModels(t *testing.T) {
t.Fatalf("GenerateModels() error = %v", err)
}

// Ceck if models are missing
// Check if models are missing
for pkgDir := range tt.want {
if _, ok := allModels[pkgDir]; !ok {
t.Errorf("GenerateModels() missing model = %v", pkgDir)
Expand Down
78 changes: 54 additions & 24 deletions v3/internal/parser/parser.go
Expand Up @@ -12,6 +12,7 @@ import (
"strings"
"time"

"github.com/pterm/pterm"
"github.com/samber/lo"
"github.com/wailsapp/wails/v3/internal/flags"
"github.com/wailsapp/wails/v3/internal/hash"
Expand Down Expand Up @@ -166,7 +167,7 @@ type Service struct {
Methods []*BoundMethod
}

func ParseMethods(service *types.TypeName, main *packages.Package) (methods []*BoundMethod) {
func ParseMethods(service *types.TypeName) (methods []*BoundMethod) {
if named, ok := service.Type().(*types.Named); ok {
for i := 0; i < named.NumMethods(); i++ {
fn := named.Method(i)
Expand All @@ -178,7 +179,7 @@ func ParseMethods(service *types.TypeName, main *packages.Package) (methods []*B
// use "main" as package path if service is inside main package,
// because reflect.Type.PkgPath() == "main"
// https://github.com/golang/go/issues/8559
if packagePath == main.Types.Path() {
if service.Pkg().Name() == "main" {
packagePath = "main"
}

Expand Down Expand Up @@ -241,7 +242,7 @@ func ParsePackages(project *Project) ([]*Package, error) {
}

// add services to packages
services, err := ParseServices(project.main)
services, err := ParseServices(project.pPkgs)
if err != nil {
return nil, err
}
Expand All @@ -261,11 +262,11 @@ func ParsePackages(project *Project) ([]*Package, error) {
result := lo.Values(requiredPackages)

// load documentation for each package
for tPkg, pkg := range requiredPackages {
if tPkg == project.main.Types {
for _, pPkg := range project.pPkgs {
if pkg, ok := requiredPackages[pPkg.Types]; ok {
files := make(map[string]*ast.File)
for i, file := range project.main.Syntax {
files[project.main.CompiledGoFiles[i]] = file
for i, file := range pPkg.Syntax {
files[pPkg.CompiledGoFiles[i]] = file
}
pkg.doc = NewDoc(pkg.Path(), &ast.Package{
Files: files,
Expand Down Expand Up @@ -343,10 +344,12 @@ type Stats struct {
}

type Project struct {
pkgs []*Package
main *packages.Package
options *flags.GenerateBindingsOptions
Stats Stats
pkgs []*Package
pPkgs []*packages.Package
options *flags.GenerateBindingsOptions
Stats Stats
basePath string
baseName string

marshaler *types.Interface
textMarshaler *types.Interface
Expand Down Expand Up @@ -404,19 +407,47 @@ func ParseProject(options *flags.GenerateBindingsOptions) (*Project, error) {
return nil, err
}

mainIndex := slices.IndexFunc(pPkgs, func(pkg *packages.Package) bool { return pkg.Name == "main" })
if mainIndex == -1 {
return nil, errors.New("application.New() must be inside main package")
// retrive base of package paths
baseIndex := -1
basePath := options.BasePath
if basePath == "." || basePath == "./" {
baseIndex = slices.IndexFunc(pPkgs, func(pkg *packages.Package) bool {
absDir, _ := filepath.Abs(options.ProjectDirectory)

if pkg.PkgPath == options.ProjectDirectory || pkg.PkgPath == absDir {
return true
}
if len(pkg.CompiledGoFiles) > 0 && filepath.Dir(pkg.CompiledGoFiles[0]) == absDir {
return true
}
return false
})
if baseIndex == -1 {
return nil, fmt.Errorf("package not found: %s", options.ProjectDirectory)
}
basePath = pPkgs[baseIndex].PkgPath
}

// retrive base name
baseName := ""
if options.UseBaseName {
if baseIndex != -1 {
baseName = pPkgs[baseIndex].Types.Name()
} else {
pterm.Warning.Printfln("base name not found: UseBaseName can only be used with BasePath=\".\"")
}
}

return &Project{
main: pPkgs[mainIndex],
pPkgs: pPkgs,
options: options,
marshaler: marshaler,
textMarshaler: textMarshaler,
Stats: Stats{
StartTime: startTime,
},
basePath: basePath,
baseName: baseName,
}, nil
}

Expand Down Expand Up @@ -499,35 +530,34 @@ func GenerateBindingsAndModels(options *flags.GenerateBindingsOptions) (*Project
return p, nil
}

func ParseServices(main *packages.Package) (services []*Service, err error) {
found, err := FindServices([]*packages.Package{main})
func ParseServices(pkgs []*packages.Package) (services []*Service, err error) {
found, err := FindServices(pkgs)
if err != nil {
return
}

for _, service := range found {
services = append(services, &Service{
TypeName: service,
Methods: ParseMethods(service, main),
Methods: ParseMethods(service),
})
}
return
}

func (p *Project) PackageDir(pkg *types.Package) string {
root := p.main.Types.Path()
if pkg.Path() == root {
return "main"
if p.baseName != "" && pkg.Path() == p.basePath {
return p.baseName
}

if strings.HasPrefix(pkg.Path(), root) {
path, err := filepath.Rel(root, pkg.Path())
if strings.HasPrefix(pkg.Path(), p.basePath) {
path, err := filepath.Rel(p.basePath, pkg.Path())
if err != nil {
panic(err)
}
return filepath.ToSlash(path)
}
return strings.ReplaceAll(pkg.Path(), "/", "-")
return pkg.Path()
}

func (p *Project) RelativePackageDir(base *types.Package, target *types.Package) string {
Expand Down

0 comments on commit ae10e75

Please sign in to comment.