Skip to content

Commit 8f8fe96

Browse files
authored
mains: pass FS nils for Files() DSL; mark Files-only services as HTTP (fixes #223) (#224)
* Fix testing plugin to generate correct package-qualified result types This fixes issue #206 where the testing plugin was generating invalid Go syntax for method return types. The problem occurred when the result type was an array or slice - the template was incorrectly placing the pointer operator before the package qualifier and array brackets. For example, a method returning []*AccessControl would generate: func GetAccessControl(...) (*bff.[]*AccessControl, error) This is syntactically invalid. The correct syntax should be: func GetAccessControl(...) ([]*bff.AccessControl, error) The fix: - Added PkgResultRef field to clientMethodData to store the properly package-qualified result type reference - Use Goa's GoFullTypeRef method to generate the package-qualified type reference, which correctly handles arrays, maps, primitives, and user types - Updated the client_methods template to use PkgResultRef instead of manually constructing the type reference This leverages Goa's existing codegen infrastructure which properly handles all type cases including: - Pointer types: *Result -> *pkg.Result - Array/slice types: []*Result -> []*pkg.Result - Map types: map[K]*Result -> map[K]*pkg.Result - Nested types: []map[K]*Result -> []map[K]*pkg.Result Fixes #206 * mains: append http.FileSystem args for Files() DSL; detect HasHTTP for file servers (fixes #223)
1 parent 272743b commit 8f8fe96

File tree

4 files changed

+99
-7
lines changed

4 files changed

+99
-7
lines changed

mains/generate.go

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ type srvInfo struct {
3434
HasHTTP bool
3535
HasGRPC bool
3636
ServerName string
37+
// FSCounts maps service name to the number of HTTP file servers.
38+
FSCounts map[string]int
3739
}
3840

3941
// svcT provides template data for each service imported by a server.
@@ -50,6 +52,9 @@ type svcT struct {
5052
HasWebSocket bool
5153
HasHTTP bool
5254
HasGRPC bool
55+
// FileServerNils is used by the template to emit one trailing
56+
// nil argument per HTTP file server in the service.
57+
FileServerNils []int
5358
}
5459

5560
// Register the plugin for the example phase.
@@ -110,15 +115,26 @@ func generateExample(genpkg string, roots []eval.Root, files []*codegen.File) ([
110115
}
111116
if len(httpSvcs) == 0 { continue }
112117
var svcs []*service.Data
113-
for _, sd := range httpSvcs { if sd != nil && sd.Service != nil { svcs = append(svcs, sd.Service) } }
118+
fsCounts := map[string]int{}
119+
for _, sd := range httpSvcs {
120+
if sd == nil || sd.Service == nil {
121+
continue
122+
}
123+
svcs = append(svcs, sd.Service)
124+
if sd.FileServers != nil {
125+
fsCounts[sd.Service.Name] = len(sd.FileServers)
126+
}
127+
}
114128
hasWS := httpcodegen.NeedDialer(httpSvcs)
115129
apipkg := apiPkgAlias(genpkg, roots)
116130
if info, ok := srvMap[dir]; ok {
117131
info.HasWS = hasWS
118132
info.HasHTTP = true
119133
if info.APIPkg == "" { info.APIPkg = apipkg }
134+
if info.FSCounts == nil { info.FSCounts = map[string]int{} }
135+
for k, v := range fsCounts { info.FSCounts[k] = v }
120136
} else {
121-
srvMap[dir] = &srvInfo{Dir: dir, APIPkg: apipkg, Services: svcs, HasWS: hasWS, HasHTTP: true}
137+
srvMap[dir] = &srvInfo{Dir: dir, APIPkg: apipkg, Services: svcs, HasWS: hasWS, HasHTTP: true, FSCounts: fsCounts}
122138
}
123139
}
124140
// Detect gRPC servers from grpc.go files
@@ -228,6 +244,12 @@ func generateExample(genpkg string, roots []eval.Root, files []*codegen.File) ([
228244
hasAnyWS = true
229245
}
230246

247+
// Determine file server count: prefer extracted counts from example
248+
// HTTP files, fallback to design counts when missing.
249+
fsn, ok := info.FSCounts[sd.Name]
250+
if !ok {
251+
fsn = httpFileServerCounts(roots)[sd.Name]
252+
}
231253
svcsData = append(svcsData, svcT{
232254
Name: sd.Name,
233255
StructName: sd.StructName,
@@ -241,6 +263,7 @@ func generateExample(genpkg string, roots []eval.Root, files []*codegen.File) ([
241263
HasWebSocket: hws,
242264
HasHTTP: hasHTTP,
243265
HasGRPC: hasGRPC,
266+
FileServerNils: func(n int) []int { if n <= 0 { return nil }; s := make([]int, n); for i := range s { s[i] = i }; return s }(fsn),
244267
})
245268
}
246269

@@ -354,7 +377,7 @@ func httpServicesByName(roots []eval.Root) map[string]bool {
354377
continue
355378
}
356379
for _, svc := range root.API.HTTP.Services {
357-
if len(svc.HTTPEndpoints) > 0 {
380+
if len(svc.HTTPEndpoints) > 0 || len(svc.FileServers) > 0 {
358381
hasHTTP[svc.Name()] = true
359382
}
360383
}
@@ -378,3 +401,22 @@ func grpcServicesByName(roots []eval.Root) map[string]bool {
378401
}
379402
return hasGRPC
380403
}
404+
405+
// httpFileServerCounts returns a map from service name to the number of
406+
// HTTP Files() endpoints defined for that service.
407+
func httpFileServerCounts(roots []eval.Root) map[string]int {
408+
counts := map[string]int{}
409+
for _, r := range roots {
410+
root, ok := r.(*expr.RootExpr)
411+
if !ok || root.API == nil || root.API.HTTP == nil {
412+
continue
413+
}
414+
for _, svc := range root.API.HTTP.Services {
415+
if svc == nil {
416+
continue
417+
}
418+
counts[svc.Name()] = len(svc.FileServers)
419+
}
420+
}
421+
return counts
422+
}

mains/generate_test.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package mains
22

33
import (
4+
"bytes"
5+
"regexp"
46
"testing"
57

68
"github.com/stretchr/testify/assert"
79
"github.com/stretchr/testify/require"
8-
"bytes"
910
"goa.design/goa/v3/codegen"
1011
"goa.design/goa/v3/codegen/example"
1112
"goa.design/goa/v3/codegen/service"
@@ -94,3 +95,36 @@ func TestWebSocketMainIncludesUpgrader(t *testing.T) {
9495
assert.Contains(t, code, "github.com/gorilla/websocket")
9596
assert.Contains(t, code, "websocket.Upgrader")
9697
}
98+
99+
func TestMainsAddsFileServerNils(t *testing.T) {
100+
root := codegen.RunDSL(t, testdata.FileServerServiceDSL)
101+
svcs := service.NewServicesData(root)
102+
httpSvcs := httpcodegen.NewServicesData(svcs, root.API.HTTP)
103+
files := append(example.ServerFiles("gen", root, svcs), httpcodegen.ExampleServerFiles("gen", httpSvcs)...)
104+
105+
out, err := Generate("gen", []eval.Root{root}, files)
106+
require.NoError(t, err)
107+
108+
// Expect relocated main under services/static/cmd/static/main.go
109+
var mainFile *codegen.File
110+
for _, f := range out {
111+
if f.Path == "services/static/cmd/static/main.go" {
112+
mainFile = f
113+
break
114+
}
115+
}
116+
require.NotNil(t, mainFile)
117+
118+
// Render the mains section and look for exactly 2 (errhandler, formatter)
119+
// + 3 (file servers) nil arguments at the end of the New(...) call.
120+
sections := mainFile.Section("mains-main")
121+
require.Greater(t, len(sections), 0)
122+
var buf bytes.Buffer
123+
require.NoError(t, sections[0].Write(&buf))
124+
code := buf.String()
125+
126+
// Match a New(...) call that ends with five consecutive `, nil` args
127+
// (2 standard + 3 file servers)
128+
re := regexp.MustCompile(`New\([\s\S]*,\s*nil(?:,\s*nil){4}\)`) // total 5 nils
129+
assert.Regexp(t, re, code)
130+
}

mains/templates/main.go.tpl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ func main() {
119119
{{- if .HasHTTP }}
120120
// {{ .Name }} HTTP server
121121
{{- if .HasWebSocket }}
122-
{{ .SrvVar }} := {{ .GenHTTPPkg }}.New({{ .EpVar }}, mux, goahttp.RequestDecoder, goahttp.ResponseEncoder, nil, nil, upgrader, nil)
122+
{{ .SrvVar }} := {{ .GenHTTPPkg }}.New({{ .EpVar }}, mux, goahttp.RequestDecoder, goahttp.ResponseEncoder, nil, nil, upgrader, nil{{- range .FileServerNils }}, nil{{- end }})
123123
{{- else }}
124-
{{ .SrvVar }} := {{ .GenHTTPPkg }}.New({{ .EpVar }}, mux, goahttp.RequestDecoder, goahttp.ResponseEncoder, nil, nil)
124+
{{ .SrvVar }} := {{ .GenHTTPPkg }}.New({{ .EpVar }}, mux, goahttp.RequestDecoder, goahttp.ResponseEncoder, nil, nil{{- range .FileServerNils }}, nil{{- end }})
125125
{{- end }}
126126
{{ .GenHTTPPkg }}.Mount(mux, {{ .SrvVar }})
127127
for _, m := range {{ .SrvVar }}.Mounts {
@@ -234,4 +234,3 @@ func main() {
234234
wg.Wait()
235235
log.Printf(ctx, "exited")
236236
}
237-

mains/testdata/dsls.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,20 @@ var WebSocketServiceDSL = func() {
6363
})
6464
})
6565
}
66+
67+
// Single service with only Files() endpoints; used to validate mains adds the
68+
// correct number of http.FileSystem arguments to the HTTP server constructor.
69+
var FileServerServiceDSL = func() {
70+
API("fsapi", func() {
71+
Server("edge", func() {
72+
Services("static")
73+
Host("dev", func() { URI("http://localhost:8080") })
74+
})
75+
})
76+
Service("static", func() {
77+
HTTP(func() { Path("/") })
78+
Files("/f1.json", "/assets/f1.json")
79+
Files("/f2.json", "/assets/f2.json")
80+
Files("/f3.json", "/assets/f3.json")
81+
})
82+
}

0 commit comments

Comments
 (0)