diff --git a/docs/content/docs/reference/unittests.md b/docs/content/docs/reference/unittests.md index 8182ece19e..16641a3152 100644 --- a/docs/content/docs/reference/unittests.md +++ b/docs/content/docs/reference/unittests.md @@ -30,7 +30,6 @@ In this default set up, FTL does the following: - prevents access to `ftl.ConfigValue` and `ftl.SecretValue` ([See options](#project-files-configs-and-secrets)) - prevents access to `ftl.Database` ([See options](#databases)) - prevents access to `ftl.MapHandle` ([See options](#maps)) -- prevents calls via `ftl.Call(...)` ([See options](#calls)) - disables all subscribers ([See options](#pubsub)) ## Customization diff --git a/examples/go/echo/echo.go b/examples/go/echo/echo.go index 8f4776749f..a06d353be9 100644 --- a/examples/go/echo/echo.go +++ b/examples/go/echo/echo.go @@ -24,8 +24,8 @@ type EchoResponse struct { // Echo returns a greeting with the current time. // //ftl:verb export -func Echo(ctx context.Context, req EchoRequest) (EchoResponse, error) { - tresp, err := ftl.Call(ctx, time.Time, time.TimeRequest{}) +func Echo(ctx context.Context, req EchoRequest, tc time.TimeClient) (EchoResponse, error) { + tresp, err := tc(ctx, time.TimeRequest{}) if err != nil { return EchoResponse{}, err } diff --git a/examples/go/echo/go.mod b/examples/go/echo/go.mod index 4573b42a5b..11c78c9d74 100644 --- a/examples/go/echo/go.mod +++ b/examples/go/echo/go.mod @@ -13,15 +13,19 @@ require ( github.com/XSAM/otelsql v0.34.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect + github.com/alecthomas/kong v1.2.1 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/alecthomas/types v0.16.0 // indirect github.com/alessio/shellescape v1.4.2 // indirect github.com/benbjohnson/clock v1.3.5 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/danieljoos/wincred v1.2.0 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/hashicorp/cronexpr v1.1.2 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect @@ -36,8 +40,15 @@ require ( github.com/swaggest/refl v1.3.0 // indirect github.com/zalando/go-keyring v0.2.5 // indirect go.opentelemetry.io/otel v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 // indirect go.opentelemetry.io/otel/metric v1.30.0 // indirect + go.opentelemetry.io/otel/sdk v1.30.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect go.opentelemetry.io/otel/trace v1.30.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.uber.org/automaxprocs v1.6.0 // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/mod v0.21.0 // indirect @@ -45,5 +56,8 @@ require ( golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/grpc v1.66.2 // indirect google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/examples/go/echo/go.sum b/examples/go/echo/go.sum index e86889ebc9..0dece39d76 100644 --- a/examples/go/echo/go.sum +++ b/examples/go/echo/go.sum @@ -14,6 +14,8 @@ github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELk github.com/alecthomas/atomic v0.1.0-alpha2/go.mod h1:zD6QGEyw49HIq19caJDc2NMXAy8rNi9ROrxtMXATfyI= github.com/alecthomas/concurrency v0.0.2 h1:Q3kGPtLbleMbH9lHX5OBFvJygfyFw29bXZKBg+IEVuo= github.com/alecthomas/concurrency v0.0.2/go.mod h1:GmuQb/iHX7mbNtPlC/WDzEFxDMB0HYFer2Qda9QTs7w= +github.com/alecthomas/kong v1.2.1 h1:E8jH4Tsgv6wCRX2nGrdPyHDUCSG83WH2qE4XLACD33Q= +github.com/alecthomas/kong v1.2.1/go.mod h1:rKTSFhbdp3Ryefn8x5MOEprnRFQ7nlmMC01GKhehhBM= github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= @@ -28,6 +30,8 @@ github.com/bool64/dev v0.2.35 h1:M17TLsO/pV2J7PYI/gpe3Ua26ETkzZGb+dC06eoMqlk= github.com/bool64/dev v0.2.35/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -66,6 +70,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -110,6 +116,8 @@ github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -143,6 +151,12 @@ github.com/zalando/go-keyring v0.2.5 h1:Bc2HHpjALryKD62ppdEzaFG6VxL6Bc+5v0LYpN8L github.com/zalando/go-keyring v0.2.5/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 h1:WypxHH02KX2poqqbaadmkMYalGyy/vil4HE4PM4nRJc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0/go.mod h1:U79SV99vtvGSEBeeHnpgGJfTsnsdkWLpPN/CcHAzBSI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 h1:m0yTiGDLUvVYaTFbAvCkVYIYcvwKt3G7OLoN77NUs/8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0/go.mod h1:wBQbT4UekBfegL2nx0Xk1vBcnzyBPsIVm9hRG4fYcr4= go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= @@ -151,6 +165,12 @@ go.opentelemetry.io/otel/sdk/metric v1.30.0 h1:QJLT8Pe11jyHBHfSAgYH7kEmT24eX792j go.opentelemetry.io/otel/sdk/metric v1.30.0/go.mod h1:waS6P3YqFNzeP01kuo/MBBYqaoBJl7efRQHOaydhy1Y= go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= @@ -174,6 +194,10 @@ golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/examples/go/echo/types.ftl.go b/examples/go/echo/types.ftl.go index cb0859ff9d..2e56ef86a6 100644 --- a/examples/go/echo/types.ftl.go +++ b/examples/go/echo/types.ftl.go @@ -2,8 +2,12 @@ package echo import ( - "context" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + "context" + + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + "github.com/TBD54566975/ftl/go-runtime/server" + + ftltime "ftl/time" ) type EchoClient func(context.Context, EchoRequest) (EchoResponse, error) @@ -11,7 +15,8 @@ type EchoClient func(context.Context, EchoRequest) (EchoResponse, error) func init() { reflection.Register( reflection.ProvideResourcesForVerb( - Echo, + Echo, + server.VerbClient[ftltime.TimeClient, ftltime.TimeRequest, ftltime.TimeResponse](), ), ) -} +} \ No newline at end of file diff --git a/frontend/cli/testdata/go/echo/echo.go b/frontend/cli/testdata/go/echo/echo.go index 8cbe75cb59..23ab837b30 100644 --- a/frontend/cli/testdata/go/echo/echo.go +++ b/frontend/cli/testdata/go/echo/echo.go @@ -22,8 +22,8 @@ type EchoResponse struct { // Echo returns a greeting with the current time. // //ftl:verb -func Echo(ctx context.Context, req EchoRequest) (EchoResponse, error) { - tresp, err := ftl.Call(ctx, time.Time, time.TimeRequest{}) +func Echo(ctx context.Context, req EchoRequest, tc time.TimeClient) (EchoResponse, error) { + tresp, err := tc(ctx, time.TimeRequest{}) if err != nil { return EchoResponse{}, err } diff --git a/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl b/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl index b920e4e985..7febb945a2 100644 --- a/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl +++ b/go-runtime/compile/build-template/.ftl.tmpl/go/main/main.go.tmpl @@ -29,7 +29,15 @@ func init() { {{.TypeName}}, {{- range .Resources}} {{- with getVerbClient . }} - server.VerbClient[{{.TypeName}}, {{.Request.TypeName}}, {{.Response.TypeName}}](), + {{- if and (eq .Request.TypeName "ftl.Unit") (eq .Response.TypeName "ftl.Unit") }} + server.EmptyClient[{{.TypeName}}](), + {{- else if eq .Request.TypeName "ftl.Unit" }} + server.SourceClient[{{.TypeName}}, {{.Response.TypeName}}](), + {{- else if eq .Response.TypeName "ftl.Unit" }} + server.SinkClient[{{.TypeName}}, {{.Request.TypeName}}](), + {{- else }} + server.VerbClient[{{.TypeName}}, {{.Request.TypeName}}, {{.Response.TypeName}}](), + {{- end -}} {{- end }} {{- end}} ), diff --git a/go-runtime/compile/build.go b/go-runtime/compile/build.go index eb426057a3..305468212e 100644 --- a/go-runtime/compile/build.go +++ b/go-runtime/compile/build.go @@ -776,9 +776,7 @@ func (b *mainModuleContextBuilder) processVerb(verb *schema.Verb) (goVerb, error } calleeNativeName, ok := b.nativeNames[call] if !ok { - // TODO: skip for now because metadata from legacy ftl.Call(...) will not have native name - continue - // return goVerb{}, fmt.Errorf("missing native name for verb client %s", call) + return goVerb{}, fmt.Errorf("missing native name for verb client %s", call) } calleeverb, err := b.getGoVerb(calleeNativeName, callee) if err != nil { diff --git a/go-runtime/compile/external-module-template/.ftl/go/modules/{{ .Module.Name }}/external_module.go.tmpl b/go-runtime/compile/external-module-template/.ftl/go/modules/{{ .Module.Name }}/external_module.go.tmpl index 587b3096dd..a60bb604dd 100644 --- a/go-runtime/compile/external-module-template/.ftl/go/modules/{{ .Module.Name }}/external_module.go.tmpl +++ b/go-runtime/compile/external-module-template/.ftl/go/modules/{{ .Module.Name }}/external_module.go.tmpl @@ -60,32 +60,12 @@ type {{.Name|title}} {{- else if is "Verb" .}} //ftl:verb {{- if and (eq (type $.Module .Request) "ftl.Unit") (eq (type $.Module .Response) "ftl.Unit")}} -func {{.Name|title}}(context.Context) error { - panic("Verb stubs should not be called directly, instead use github.com/TBD54566975/ftl/runtime-go/ftl.CallEmpty()") -} - -//ftl:verb type {{.Name|title}}Client func(context.Context) error {{- else if eq (type $.Module .Request) "ftl.Unit"}} -func {{.Name|title}}(context.Context) ({{type $.Module .Response}}, error) { - panic("Verb stubs should not be called directly, instead use github.com/TBD54566975/ftl/runtime-go/ftl.CallSource()") -} - -//ftl:verb type {{.Name|title}}Client func(context.Context) ({{type $.Module .Response}}, error) {{- else if eq (type $.Module .Response) "ftl.Unit"}} -func {{.Name|title}}(context.Context, {{type $.Module .Request}}) error { - panic("Verb stubs should not be called directly, instead use github.com/TBD54566975/ftl/runtime-go/ftl.CallSink()") -} - -//ftl:verb type {{.Name|title}}Client func(context.Context, {{type $.Module .Request}}) {{- else}} -func {{.Name|title}}(context.Context, {{type $.Module .Request}}) ({{type $.Module .Response}}, error) { - panic("Verb stubs should not be called directly, instead use github.com/TBD54566975/ftl/runtime-go/ftl.Call()") -} - -//ftl:verb type {{.Name|title}}Client func(context.Context, {{type $.Module .Request}}) ({{type $.Module .Response}}, error) {{- end}} {{- end}} diff --git a/go-runtime/compile/testdata/go/echo/echo.go b/go-runtime/compile/testdata/go/echo/echo.go index 233b4850cb..cfdb7a37e7 100644 --- a/go-runtime/compile/testdata/go/echo/echo.go +++ b/go-runtime/compile/testdata/go/echo/echo.go @@ -24,8 +24,8 @@ type EchoResponse struct { // Echo returns a greeting with the current time. // //ftl:verb -func Echo(ctx context.Context, req EchoRequest) (EchoResponse, error) { - tresp, err := ftl.Call(ctx, time.Time, time.TimeRequest{}) +func Echo(ctx context.Context, req EchoRequest, tc time.TimeClient) (EchoResponse, error) { + tresp, err := tc(ctx, time.TimeRequest{}) if err != nil { return EchoResponse{}, err } diff --git a/go-runtime/compile/testdata/go/echo/go.mod b/go-runtime/compile/testdata/go/echo/go.mod index 85848a77c4..15fb20a8b6 100644 --- a/go-runtime/compile/testdata/go/echo/go.mod +++ b/go-runtime/compile/testdata/go/echo/go.mod @@ -13,15 +13,19 @@ require ( github.com/XSAM/otelsql v0.34.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect + github.com/alecthomas/kong v1.2.1 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/alecthomas/types v0.16.0 // indirect github.com/alessio/shellescape v1.4.2 // indirect github.com/benbjohnson/clock v1.3.5 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/danieljoos/wincred v1.2.0 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/hashicorp/cronexpr v1.1.2 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect @@ -36,8 +40,15 @@ require ( github.com/swaggest/refl v1.3.0 // indirect github.com/zalando/go-keyring v0.2.5 // indirect go.opentelemetry.io/otel v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 // indirect go.opentelemetry.io/otel/metric v1.30.0 // indirect + go.opentelemetry.io/otel/sdk v1.30.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect go.opentelemetry.io/otel/trace v1.30.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.uber.org/automaxprocs v1.6.0 // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/mod v0.21.0 // indirect @@ -45,5 +56,8 @@ require ( golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/grpc v1.66.2 // indirect google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/go-runtime/compile/testdata/go/echo/go.sum b/go-runtime/compile/testdata/go/echo/go.sum index e86889ebc9..0dece39d76 100644 --- a/go-runtime/compile/testdata/go/echo/go.sum +++ b/go-runtime/compile/testdata/go/echo/go.sum @@ -14,6 +14,8 @@ github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELk github.com/alecthomas/atomic v0.1.0-alpha2/go.mod h1:zD6QGEyw49HIq19caJDc2NMXAy8rNi9ROrxtMXATfyI= github.com/alecthomas/concurrency v0.0.2 h1:Q3kGPtLbleMbH9lHX5OBFvJygfyFw29bXZKBg+IEVuo= github.com/alecthomas/concurrency v0.0.2/go.mod h1:GmuQb/iHX7mbNtPlC/WDzEFxDMB0HYFer2Qda9QTs7w= +github.com/alecthomas/kong v1.2.1 h1:E8jH4Tsgv6wCRX2nGrdPyHDUCSG83WH2qE4XLACD33Q= +github.com/alecthomas/kong v1.2.1/go.mod h1:rKTSFhbdp3Ryefn8x5MOEprnRFQ7nlmMC01GKhehhBM= github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= @@ -28,6 +30,8 @@ github.com/bool64/dev v0.2.35 h1:M17TLsO/pV2J7PYI/gpe3Ua26ETkzZGb+dC06eoMqlk= github.com/bool64/dev v0.2.35/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -66,6 +70,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -110,6 +116,8 @@ github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -143,6 +151,12 @@ github.com/zalando/go-keyring v0.2.5 h1:Bc2HHpjALryKD62ppdEzaFG6VxL6Bc+5v0LYpN8L github.com/zalando/go-keyring v0.2.5/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 h1:WypxHH02KX2poqqbaadmkMYalGyy/vil4HE4PM4nRJc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0/go.mod h1:U79SV99vtvGSEBeeHnpgGJfTsnsdkWLpPN/CcHAzBSI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 h1:m0yTiGDLUvVYaTFbAvCkVYIYcvwKt3G7OLoN77NUs/8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0/go.mod h1:wBQbT4UekBfegL2nx0Xk1vBcnzyBPsIVm9hRG4fYcr4= go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= @@ -151,6 +165,12 @@ go.opentelemetry.io/otel/sdk/metric v1.30.0 h1:QJLT8Pe11jyHBHfSAgYH7kEmT24eX792j go.opentelemetry.io/otel/sdk/metric v1.30.0/go.mod h1:waS6P3YqFNzeP01kuo/MBBYqaoBJl7efRQHOaydhy1Y= go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= @@ -174,6 +194,10 @@ golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/go-runtime/compile/testdata/go/echo/types.ftl.go b/go-runtime/compile/testdata/go/echo/types.ftl.go index ee524b37ee..2e56ef86a6 100644 --- a/go-runtime/compile/testdata/go/echo/types.ftl.go +++ b/go-runtime/compile/testdata/go/echo/types.ftl.go @@ -1,2 +1,22 @@ // Code generated by FTL. DO NOT EDIT. -package echo \ No newline at end of file +package echo + +import ( + "context" + + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + "github.com/TBD54566975/ftl/go-runtime/server" + + ftltime "ftl/time" +) + +type EchoClient func(context.Context, EchoRequest) (EchoResponse, error) + +func init() { + reflection.Register( + reflection.ProvideResourcesForVerb( + Echo, + server.VerbClient[ftltime.TimeClient, ftltime.TimeRequest, ftltime.TimeResponse](), + ), + ) +} \ No newline at end of file diff --git a/go-runtime/compile/testdata/go/notexportedverb/notexportedverb.go b/go-runtime/compile/testdata/go/notexportedverb/notexportedverb.go index 6111305c4f..a3698df607 100644 --- a/go-runtime/compile/testdata/go/notexportedverb/notexportedverb.go +++ b/go-runtime/compile/testdata/go/notexportedverb/notexportedverb.go @@ -18,8 +18,8 @@ type Response struct { } //ftl:verb -func ShouldFail(ctx context.Context, req Request) (Response, error) { - _, err := ftl.Call(ctx, echo.Echo, echo.EchoRequest{}) +func ShouldFail(ctx context.Context, req Request, ec echo.EchoClient) (Response, error) { + _, err := ec(ctx, echo.EchoRequest{}) if err != nil { return Response{}, err } diff --git a/go-runtime/compile/testdata/go/two/go.mod b/go-runtime/compile/testdata/go/two/go.mod index 57f07b1d2d..332a994b0b 100644 --- a/go-runtime/compile/testdata/go/two/go.mod +++ b/go-runtime/compile/testdata/go/two/go.mod @@ -7,43 +7,13 @@ replace github.com/TBD54566975/ftl => ../../../../.. require github.com/TBD54566975/ftl v0.150.3 require ( - connectrpc.com/connect v1.16.2 // indirect - connectrpc.com/grpcreflect v1.2.0 // indirect - connectrpc.com/otelconnect v0.7.1 // indirect - github.com/XSAM/otelsql v0.34.0 // indirect - github.com/alecthomas/atomic v0.1.0-alpha2 // indirect - github.com/alecthomas/concurrency v0.0.2 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/alecthomas/types v0.16.0 // indirect - github.com/alessio/shellescape v1.4.2 // indirect - github.com/benbjohnson/clock v1.3.5 // indirect - github.com/danieljoos/wincred v1.2.0 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/hashicorp/cronexpr v1.1.2 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect - github.com/jackc/pgx/v5 v5.7.1 // indirect - github.com/jackc/puddle/v2 v2.2.2 // indirect - github.com/jpillora/backoff v1.0.0 // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/multiformats/go-base36 v0.2.0 // indirect - github.com/puzpuzpuz/xsync/v3 v3.4.0 // indirect + github.com/stretchr/testify v1.9.0 // indirect github.com/swaggest/jsonschema-go v0.3.72 // indirect github.com/swaggest/refl v1.3.0 // indirect - github.com/zalando/go-keyring v0.2.5 // indirect - go.opentelemetry.io/otel v1.30.0 // indirect - go.opentelemetry.io/otel/metric v1.30.0 // indirect - go.opentelemetry.io/otel/trace v1.30.0 // indirect - golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect - golang.org/x/mod v0.21.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/go-runtime/compile/testdata/go/two/go.sum b/go-runtime/compile/testdata/go/two/go.sum index e86889ebc9..178a13b8a0 100644 --- a/go-runtime/compile/testdata/go/two/go.sum +++ b/go-runtime/compile/testdata/go/two/go.sum @@ -6,12 +6,8 @@ connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= github.com/TBD54566975/scaffolder v1.1.0 h1:R92zjC4XiS/lGCxJ8Ebn93g8gC0LU9qo06AAKo9cEJE= github.com/TBD54566975/scaffolder v1.1.0/go.mod h1:dRi67GryEhZ5u0XRSiR294SYaqAfnCkZ7u3rmc4W6iI= -github.com/XSAM/otelsql v0.34.0 h1:YdCRKy17Xn0MH717LEwqpVL/a+4nexmSCBrgoycYY6E= -github.com/XSAM/otelsql v0.34.0/go.mod h1:xaE+ybu+kJOYvtDyThbe0VoKWngvKHmNlrM1rOn8f94= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= -github.com/alecthomas/atomic v0.1.0-alpha2/go.mod h1:zD6QGEyw49HIq19caJDc2NMXAy8rNi9ROrxtMXATfyI= github.com/alecthomas/concurrency v0.0.2 h1:Q3kGPtLbleMbH9lHX5OBFvJygfyFw29bXZKBg+IEVuo= github.com/alecthomas/concurrency v0.0.2/go.mod h1:GmuQb/iHX7mbNtPlC/WDzEFxDMB0HYFer2Qda9QTs7w= github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= @@ -30,7 +26,6 @@ github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= @@ -41,7 +36,6 @@ github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxER github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -120,11 +114,6 @@ github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= @@ -145,10 +134,6 @@ go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= -go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= -go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg= -go.opentelemetry.io/otel/sdk/metric v1.30.0 h1:QJLT8Pe11jyHBHfSAgYH7kEmT24eX792jZO1bo4BXkM= -go.opentelemetry.io/otel/sdk/metric v1.30.0/go.mod h1:waS6P3YqFNzeP01kuo/MBBYqaoBJl7efRQHOaydhy1Y= go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= @@ -163,7 +148,6 @@ golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= @@ -176,12 +160,10 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1: google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= diff --git a/go-runtime/compile/testdata/go/two/two.go b/go-runtime/compile/testdata/go/two/two.go index 5c51c927d3..90b2ac6280 100644 --- a/go-runtime/compile/testdata/go/two/two.go +++ b/go-runtime/compile/testdata/go/two/two.go @@ -4,7 +4,6 @@ import ( "context" "ftl/builtin" - "github.com/TBD54566975/ftl/go-runtime/ftl" lib "github.com/TBD54566975/ftl/go-runtime/schema/testdata" ) @@ -61,13 +60,13 @@ func Three(ctx context.Context, req Payload[string]) (Payload[string], error) { } //ftl:verb export -func CallsTwo(ctx context.Context, req Payload[string]) (Payload[string], error) { - return ftl.Call(ctx, Two, req) +func CallsTwo(ctx context.Context, req Payload[string], two TwoClient) (Payload[string], error) { + return two(ctx, req) } //ftl:verb export -func CallsTwoAndThree(ctx context.Context, req Payload[string]) (Payload[string], error) { - err := transitiveVerbCall(ctx, req) +func CallsTwoAndThree(ctx context.Context, req Payload[string], two TwoClient, three ThreeClient) (Payload[string], error) { + err := transitiveVerbCall(ctx, req, two, three) return Payload[string]{}, err } @@ -102,17 +101,17 @@ type TransitiveAliasAlias = lib.NonFTLType type TransitiveAlias lib.NonFTLType -func transitiveVerbCall(ctx context.Context, req Payload[string]) error { - _, err := ftl.Call(ctx, Two, req) +func transitiveVerbCall(ctx context.Context, req Payload[string], two TwoClient, three ThreeClient) error { + _, err := two(ctx, req) if err != nil { return err } - err = superTransitiveVerbCall(ctx, req) + err = superTransitiveVerbCall(ctx, req, three) return err } -func superTransitiveVerbCall(ctx context.Context, req Payload[string]) error { - _, err := ftl.Call(ctx, Three, req) +func superTransitiveVerbCall(ctx context.Context, req Payload[string], three ThreeClient) error { + _, err := three(ctx, req) return err } diff --git a/go-runtime/compile/testdata/go/two/types.ftl.go b/go-runtime/compile/testdata/go/two/types.ftl.go index 6e0ec7c21d..d3a2d07f4e 100644 --- a/go-runtime/compile/testdata/go/two/types.ftl.go +++ b/go-runtime/compile/testdata/go/two/types.ftl.go @@ -1,10 +1,27 @@ // Code generated by FTL. DO NOT EDIT. package two + import ( - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" - lib "github.com/TBD54566975/ftl/go-runtime/schema/testdata" + "context" + + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + lib "github.com/TBD54566975/ftl/go-runtime/schema/testdata" + + ftlbuiltin "ftl/builtin" ) +type CallsTwoClient func(context.Context, Payload[string]) (Payload[string], error) + +type CallsTwoAndThreeClient func(context.Context, Payload[string]) (Payload[string], error) + +type CatchArrayClient func(context.Context, ftlbuiltin.CatchRequest[[]TwoEnum]) error + +type ReturnsUserClient func(context.Context) (UserResponse, error) + +type ThreeClient func(context.Context, Payload[string]) (Payload[string], error) + +type TwoClient func(context.Context, Payload[string]) (Payload[string], error) + func init() { reflection.Register( reflection.SumType[TypeEnum]( @@ -14,12 +31,23 @@ func init() { *new(WithoutDirective), ), reflection.ExternalType(*new(lib.NonFTLType)), - reflection.ExternalType(*new(lib.NonFTLType)), - reflection.ExternalType(*new(lib.NonFTLType)), - reflection.ExternalType(*new(lib.NonFTLType)), - reflection.ExternalType(*new(lib.NonFTLType)), - reflection.ExternalType(*new(lib.NonFTLType)), - reflection.ExternalType(*new(lib.NonFTLType)), - reflection.ExternalType(*new(lib.NonFTLType)), + reflection.ProvideResourcesForVerb( + CallsTwo, + ), + reflection.ProvideResourcesForVerb( + CallsTwoAndThree, + ), + reflection.ProvideResourcesForVerb( + CatchArray, + ), + reflection.ProvideResourcesForVerb( + ReturnsUser, + ), + reflection.ProvideResourcesForVerb( + Three, + ), + reflection.ProvideResourcesForVerb( + Two, + ), ) } \ No newline at end of file diff --git a/go-runtime/compile/testdata/go/undefinedverb/undefinedverb.go b/go-runtime/compile/testdata/go/undefinedverb/undefinedverb.go index 8bb67e9b97..aaba77255b 100644 --- a/go-runtime/compile/testdata/go/undefinedverb/undefinedverb.go +++ b/go-runtime/compile/testdata/go/undefinedverb/undefinedverb.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + "ftl/echo" + "github.com/TBD54566975/ftl/go-runtime/ftl" // Import the FTL SDK. ) @@ -16,8 +18,8 @@ type Response struct { } //ftl:verb -func ShouldFail(ctx context.Context, req Request) (Response, error) { - _, err := ftl.Call(ctx, echo.Undefined, echo.EchoRequest{}) +func ShouldFail(ctx context.Context, req Request, client echo.UndefinedClient) (Response, error) { + _, err := client(ctx, echo.EchoRequest{}) if err != nil { return Response{}, err } diff --git a/go-runtime/ftl/call.go b/go-runtime/ftl/call.go deleted file mode 100644 index cc7c6a8c51..0000000000 --- a/go-runtime/ftl/call.go +++ /dev/null @@ -1,98 +0,0 @@ -package ftl - -import ( - "context" - "fmt" - "reflect" - - "connectrpc.com/connect" - - ftlv1 "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1" - "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/ftlv1connect" - "github.com/TBD54566975/ftl/backend/schema" - "github.com/TBD54566975/ftl/go-runtime/encoding" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" - "github.com/TBD54566975/ftl/internal/modulecontext" - "github.com/TBD54566975/ftl/internal/rpc" -) - -func call[Req, Resp any](ctx context.Context, callee reflection.Ref, req Req, inline Verb[Req, Resp]) (resp Resp, err error) { - moduleCtx := modulecontext.FromContext(ctx).CurrentContext() - override, err := moduleCtx.BehaviorForVerb(schema.Ref{Module: callee.Module, Name: callee.Name}) - if err != nil { - return resp, fmt.Errorf("%s: %w", callee, err) - } - if behavior, ok := override.Get(); ok { - uncheckedResp, err := behavior.Call(ctx, modulecontext.Verb(widenVerb(inline)), req) - if err != nil { - return resp, fmt.Errorf("%s: %w", callee, err) - } - if r, ok := uncheckedResp.(Resp); ok { - return r, nil - } - return resp, fmt.Errorf("%s: overridden verb had invalid response type %T, expected %v", callee, uncheckedResp, reflect.TypeFor[Resp]()) - } - - reqData, err := encoding.Marshal(req) - if err != nil { - return resp, fmt.Errorf("%s: failed to marshal request: %w", callee, err) - } - - client := rpc.ClientFromContext[ftlv1connect.VerbServiceClient](ctx) - cresp, err := client.Call(ctx, connect.NewRequest(&ftlv1.CallRequest{Verb: callee.ToProto(), Body: reqData})) - if err != nil { - return resp, fmt.Errorf("%s: failed to call Verb: %w", callee, err) - } - switch cresp := cresp.Msg.Response.(type) { - case *ftlv1.CallResponse_Error_: - return resp, fmt.Errorf("%s: %s", callee, cresp.Error.Message) - - case *ftlv1.CallResponse_Body: - err = encoding.Unmarshal(cresp.Body, &resp) - if err != nil { - return resp, fmt.Errorf("%s: failed to decode response: %w", callee, err) - } - return resp, nil - - default: - panic(fmt.Sprintf("%s: invalid response type %T", callee, cresp)) - } -} - -// Call a Verb through the FTL Controller. -func Call[Req, Resp any](ctx context.Context, verb Verb[Req, Resp], req Req) (Resp, error) { - return call[Req, Resp](ctx, reflection.FuncRef(verb), req, verb) -} - -// CallSink calls a Sink through the FTL controller. -func CallSink[Req any](ctx context.Context, sink Sink[Req], req Req) error { - _, err := call[Req, Unit](ctx, reflection.FuncRef(sink), req, func(ctx context.Context, req Req) (Unit, error) { - return Unit{}, sink(ctx, req) - }) - return err -} - -// CallSource calls a Source through the FTL controller. -func CallSource[Resp any](ctx context.Context, source Source[Resp]) (Resp, error) { - return call[Unit, Resp](ctx, reflection.FuncRef(source), Unit{}, func(ctx context.Context, req Unit) (Resp, error) { - return source(ctx) - }) -} - -// CallEmpty calls a Verb with no request or response through the FTL controller. -func CallEmpty(ctx context.Context, empty Empty) error { - _, err := call[Unit, Unit](ctx, reflection.FuncRef(empty), Unit{}, func(ctx context.Context, req Unit) (Unit, error) { - return Unit{}, empty(ctx) - }) - return err -} - -func widenVerb[Req, Resp any](verb Verb[Req, Resp]) Verb[any, any] { - return func(ctx context.Context, uncheckedReq any) (any, error) { - req, ok := uncheckedReq.(Req) - if !ok { - return nil, fmt.Errorf("invalid request type %T for %v, expected %v", uncheckedReq, reflection.FuncRef(verb), reflect.TypeFor[Req]()) - } - return verb(ctx, req) - } -} diff --git a/go-runtime/ftl/ftltest/testdata/go/time/go.mod b/go-runtime/ftl/ftltest/testdata/go/time/go.mod index 37712596c5..52ad07341b 100644 --- a/go-runtime/ftl/ftltest/testdata/go/time/go.mod +++ b/go-runtime/ftl/ftltest/testdata/go/time/go.mod @@ -3,3 +3,16 @@ module ftl/time go 1.23.0 replace github.com/TBD54566975/ftl => ./../../../../../.. + +require github.com/TBD54566975/ftl v0.0.0-00010101000000-000000000000 + +require ( + github.com/alecthomas/participle/v2 v2.1.1 // indirect + github.com/alecthomas/types v0.16.0 // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/hashicorp/cronexpr v1.1.2 // indirect + github.com/swaggest/jsonschema-go v0.3.72 // indirect + github.com/swaggest/refl v1.3.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + google.golang.org/protobuf v1.34.2 // indirect +) diff --git a/go-runtime/ftl/ftltest/testdata/go/time/go.sum b/go-runtime/ftl/ftltest/testdata/go/time/go.sum index e69de29bb2..e667a6d60c 100644 --- a/go-runtime/ftl/ftltest/testdata/go/time/go.sum +++ b/go-runtime/ftl/ftltest/testdata/go/time/go.sum @@ -0,0 +1,206 @@ +connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE= +connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc= +connectrpc.com/grpcreflect v1.2.0 h1:Q6og1S7HinmtbEuBvARLNwYmTbhEGRpHDhqrPNlmK+U= +connectrpc.com/grpcreflect v1.2.0/go.mod h1:nwSOKmE8nU5u/CidgHtPYk1PFI3U9ignz7iDMxOYkSY= +connectrpc.com/otelconnect v0.7.1 h1:scO5pOb0i4yUE66CnNrHeK1x51yq0bE0ehPg6WvzXJY= +connectrpc.com/otelconnect v0.7.1/go.mod h1:dh3bFgHBTb2bkqGCeVVOtHJreSns7uu9wwL2Tbz17ms= +github.com/TBD54566975/scaffolder v1.1.0 h1:R92zjC4XiS/lGCxJ8Ebn93g8gC0LU9qo06AAKo9cEJE= +github.com/TBD54566975/scaffolder v1.1.0/go.mod h1:dRi67GryEhZ5u0XRSiR294SYaqAfnCkZ7u3rmc4W6iI= +github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= +github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= +github.com/alecthomas/concurrency v0.0.2 h1:Q3kGPtLbleMbH9lHX5OBFvJygfyFw29bXZKBg+IEVuo= +github.com/alecthomas/concurrency v0.0.2/go.mod h1:GmuQb/iHX7mbNtPlC/WDzEFxDMB0HYFer2Qda9QTs7w= +github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= +github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/alecthomas/types v0.16.0 h1:o9+JSwCRB6DDaWDeR/Mg7v/zh3R+MlknM6DrnDyY7U0= +github.com/alecthomas/types v0.16.0/go.mod h1:Tswm0qQpjpVq8rn70OquRsUtFxbQKub/8TMyYYGI0+k= +github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4uEoM0= +github.com/alessio/shellescape v1.4.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= +github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/bool64/dev v0.2.35 h1:M17TLsO/pV2J7PYI/gpe3Ua26ETkzZGb+dC06eoMqlk= +github.com/bool64/dev v0.2.35/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= +github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= +github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= +github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= +github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= +github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= +github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= +github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= +github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= +github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= +github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= +github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= +github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= +github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/swaggest/assertjson v1.9.0 h1:dKu0BfJkIxv/xe//mkCrK5yZbs79jL7OVf9Ija7o2xQ= +github.com/swaggest/assertjson v1.9.0/go.mod h1:b+ZKX2VRiUjxfUIal0HDN85W0nHPAYUbYH5WkkSsFsU= +github.com/swaggest/jsonschema-go v0.3.72 h1:IHaGlR1bdBUBPfhe4tfacN2TGAPKENEGiNyNzvnVHv4= +github.com/swaggest/jsonschema-go v0.3.72/go.mod h1:OrGyEoVqpfSFJ4Am4V/FQcQ3mlEC1vVeleA+5ggbVW4= +github.com/swaggest/refl v1.3.0 h1:PEUWIku+ZznYfsoyheF97ypSduvMApYyGkYF3nabS0I= +github.com/swaggest/refl v1.3.0/go.mod h1:3Ujvbmh1pfSbDYjC6JGG7nMgPvpG0ehQL4iNonnLNbg= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= +github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/zalando/go-keyring v0.2.5 h1:Bc2HHpjALryKD62ppdEzaFG6VxL6Bc+5v0LYpN8Lba8= +github.com/zalando/go-keyring v0.2.5/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= +go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= +go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= +go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= +go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= +go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= +go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +istio.io/api v1.23.2 h1:FvWi7GC+rWD60/ZFPuulX/h3k+f2Q9qot3dP8CIL8Ss= +istio.io/api v1.23.2/go.mod h1:QPSTGXuIQdnZFEm3myf9NZ5uBMwCdJWUvfj9ZZ+2oBM= +istio.io/client-go v1.23.2 h1:BIt6A+KaUOFin3SzXiDq2Fr/TMBev1+c836R0BfUfhU= +istio.io/client-go v1.23.2/go.mod h1:E08wpMtUulJk2tlWOCUVakjy1bKFxUNm22tM1R1QY0Y= +k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU= +k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI= +k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= +k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0= +k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= +modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM= +modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/go-runtime/ftl/ftltest/testdata/go/time/types.ftl.go b/go-runtime/ftl/ftltest/testdata/go/time/types.ftl.go new file mode 100644 index 0000000000..145db63b6d --- /dev/null +++ b/go-runtime/ftl/ftltest/testdata/go/time/types.ftl.go @@ -0,0 +1,17 @@ +// Code generated by FTL. DO NOT EDIT. +package time + +import ( + "context" + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" +) + +type TimeClient func(context.Context, TimeRequest) (TimeResponse, error) + +func init() { + reflection.Register( + reflection.ProvideResourcesForVerb( + Time, + ), + ) +} diff --git a/go-runtime/ftl/ftltest/testdata/go/verbtypes/verbtypes_test.go b/go-runtime/ftl/ftltest/testdata/go/verbtypes/verbtypes_test.go index 1a9f58b1c5..2644622546 100644 --- a/go-runtime/ftl/ftltest/testdata/go/verbtypes/verbtypes_test.go +++ b/go-runtime/ftl/ftltest/testdata/go/verbtypes/verbtypes_test.go @@ -5,7 +5,6 @@ import ( "fmt" "testing" - "github.com/TBD54566975/ftl/go-runtime/ftl" "github.com/TBD54566975/ftl/go-runtime/ftl/ftltest" "github.com/alecthomas/assert/v2" ) @@ -45,23 +44,6 @@ func TestVerbs(t *testing.T) { err = ftltest.CallEmpty[EmptyClient](ctx) assert.NoError(t, err) assert.Equal(t, knockOnEffects["empty"], "test") - - // TODO: remove after refactor - verbResp, err = ftl.Call(ctx, Verb, Request{Input: "test"}) - assert.NoError(t, err) - assert.Equal(t, Response{Output: "fake: test"}, verbResp) - - sourceResp, err = ftl.CallSource(ctx, Source) - assert.NoError(t, err) - assert.Equal(t, Response{Output: "fake"}, sourceResp) - - err = ftl.CallSink(ctx, Sink, Request{Input: "testsink"}) - assert.NoError(t, err) - assert.Equal(t, knockOnEffects["sink"], "testsink") - - err = ftl.CallEmpty(ctx, Empty) - assert.NoError(t, err) - assert.Equal(t, knockOnEffects["empty"], "test") } func TestContextExtension(t *testing.T) { @@ -114,19 +96,6 @@ func TestVerbErrors(t *testing.T) { err = ftltest.CallEmpty[EmptyClient](ctx) assert.EqualError(t, err, "test harness failed to call verb verbtypes.empty: fake-empty") - - // TODO: remove after refactor - _, err = ftl.Call(ctx, Verb, Request{Input: "test"}) - assert.EqualError(t, err, "verbtypes.verb: fake: test") - - _, err = ftl.CallSource(ctx, Source) - assert.EqualError(t, err, "verbtypes.source: fake-source") - - err = ftl.CallSink(ctx, Sink, Request{Input: "test-sink"}) - assert.EqualError(t, err, "verbtypes.sink: fake: test-sink") - - err = ftl.CallEmpty(ctx, Empty) - assert.EqualError(t, err, "verbtypes.empty: fake-empty") } func TestTransitiveVerbMock(t *testing.T) { diff --git a/go-runtime/ftl/ftltest/testdata/go/wrapped/types.ftl.go b/go-runtime/ftl/ftltest/testdata/go/wrapped/types.ftl.go index 7b93b972ea..0d46705618 100644 --- a/go-runtime/ftl/ftltest/testdata/go/wrapped/types.ftl.go +++ b/go-runtime/ftl/ftltest/testdata/go/wrapped/types.ftl.go @@ -2,9 +2,10 @@ package wrapped import ( - "context" - - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + "context" + ftltime "ftl/time" + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + "github.com/TBD54566975/ftl/go-runtime/server" ) type InnerClient func(context.Context) (WrappedResponse, error) @@ -14,10 +15,12 @@ type OuterClient func(context.Context) (WrappedResponse, error) func init() { reflection.Register( reflection.ProvideResourcesForVerb( - Inner, + Inner, + server.VerbClient[ftltime.TimeClient, ftltime.TimeRequest, ftltime.TimeResponse](), ), reflection.ProvideResourcesForVerb( - Outer, + Outer, + server.SourceClient[InnerClient, WrappedResponse](), ), ) -} \ No newline at end of file +} diff --git a/go-runtime/ftl/ftltest/testdata/go/wrapped/wrapped.go b/go-runtime/ftl/ftltest/testdata/go/wrapped/wrapped.go index c94e54790c..da76da30ee 100644 --- a/go-runtime/ftl/ftltest/testdata/go/wrapped/wrapped.go +++ b/go-runtime/ftl/ftltest/testdata/go/wrapped/wrapped.go @@ -22,13 +22,13 @@ type WrappedResponse struct { } //ftl:verb -func Outer(ctx context.Context) (WrappedResponse, error) { - return ftl.CallSource(ctx, Inner) +func Outer(ctx context.Context, inner InnerClient) (WrappedResponse, error) { + return inner(ctx) } //ftl:verb -func Inner(ctx context.Context) (WrappedResponse, error) { - resp, err := ftl.Call(ctx, time.Time, time.TimeRequest{}) +func Inner(ctx context.Context, tc time.TimeClient) (WrappedResponse, error) { + resp, err := tc(ctx, time.TimeRequest{}) if err != nil { return WrappedResponse{}, err } diff --git a/go-runtime/ftl/ftltest/testdata/go/wrapped/wrapped_test.go b/go-runtime/ftl/ftltest/testdata/go/wrapped/wrapped_test.go index 5dc0efa1f3..f3687aea94 100644 --- a/go-runtime/ftl/ftltest/testdata/go/wrapped/wrapped_test.go +++ b/go-runtime/ftl/ftltest/testdata/go/wrapped/wrapped_test.go @@ -43,7 +43,7 @@ func TestWrappedWithConfigEnvar(t *testing.T) { tt.options..., ) myConfig.Get(ctx) - resp, err := Outer(ctx) + resp, err := ftltest.CallSource[OuterClient, WrappedResponse](ctx) if expected, ok := tt.expectedError.Get(); ok { assert.EqualError(t, err, expected) @@ -76,7 +76,7 @@ func TestWrapped(t *testing.T) { }, configValue: "helloworld", secretValue: "shhhhh", - expectedError: ftl.Some("wrapped.inner: no mock found: provide a mock with ftltest.WhenVerb(Inner, ...) or enable all calls within the module with ftltest.WithCallsAllowedWithinModule()"), + expectedError: ftl.Some("test harness failed to retrieve behavior for verb wrapped.outer: no mock found: provide a mock with ftltest.WhenVerb(Outer, ...) or enable all calls within the module with ftltest.WithCallsAllowedWithinModule()"), }, { name: "AllowCallsWithinModule", @@ -87,7 +87,7 @@ func TestWrapped(t *testing.T) { }, configValue: "helloworld", secretValue: "shhhhh", - expectedError: ftl.Some("wrapped.inner: time.time: no mock found: provide a mock with ftltest.WhenVerb(time.Time, ...)"), + expectedError: ftl.Some("test harness failed to call verb wrapped.outer: wrapped.inner: time.time: no mock found: provide a mock with ftltest.WhenVerb(time.Time, ...)"), }, { name: "WithExternalVerbMock", @@ -131,7 +131,7 @@ func TestWrapped(t *testing.T) { tt.options..., ) myConfig.Get(ctx) - resp, err := Outer(ctx) + resp, err := ftltest.CallSource[OuterClient, WrappedResponse](ctx) if expected, ok := tt.expectedError.Get(); ok { assert.EqualError(t, err, expected) diff --git a/go-runtime/ftl/reflection/verb.go b/go-runtime/ftl/reflection/verb.go index 9ba8ffad95..0014c6cf79 100644 --- a/go-runtime/ftl/reflection/verb.go +++ b/go-runtime/ftl/reflection/verb.go @@ -51,8 +51,6 @@ func (v verbCall) Exec(ctx context.Context, req optional.Option[any]) (optional. args = append(args, reflect.ValueOf(r)) } - // try to call the function, with panic recovery defaulting to the original args - // TODO: remove once ftl.Call(...) is no longer supported tryCall := func(args []reflect.Value) (results []reflect.Value, err error) { defer func() { if r := recover(); r != nil { @@ -65,11 +63,7 @@ func (v verbCall) Exec(ctx context.Context, req optional.Option[any]) (optional. results, err := tryCall(append(args, v.args...)) if err != nil { - // retry with original args if panic occurred - results, err = tryCall(args) - if err != nil { - return optional.None[any](), err - } + return optional.None[any](), err } var resp optional.Option[any] diff --git a/go-runtime/ftl/testdata/go/typeregistry/typeregistry_test.go b/go-runtime/ftl/testdata/go/typeregistry/typeregistry_test.go index 48ebdbf7c7..ab1c617f25 100644 --- a/go-runtime/ftl/testdata/go/typeregistry/typeregistry_test.go +++ b/go-runtime/ftl/testdata/go/typeregistry/typeregistry_test.go @@ -37,7 +37,11 @@ func TestIngress(t *testing.T) { for _, test := range testCases { t.Run(test.Name, func(t *testing.T) { - resp, err := ftl.Call(ctx, Echo, builtin.HttpRequest[EchoRequest, ftl.Unit, ftl.Unit]{ + resp, err := ftltest.Call[ + EchoClient, + builtin.HttpRequest[EchoRequest, ftl.Unit, ftl.Unit], + builtin.HttpResponse[EchoResponse, string], + ](ctx, builtin.HttpRequest[EchoRequest, ftl.Unit, ftl.Unit]{ Body: EchoRequest{Strings: test.Input}, }) assert.NoError(t, err) diff --git a/go-runtime/ftl/testdata/go/typeregistry/types.ftl.go b/go-runtime/ftl/testdata/go/typeregistry/types.ftl.go index fca7d63ded..5be74c5574 100644 --- a/go-runtime/ftl/testdata/go/typeregistry/types.ftl.go +++ b/go-runtime/ftl/testdata/go/typeregistry/types.ftl.go @@ -1,27 +1,27 @@ // Code generated by FTL. DO NOT EDIT. package typeregistry + import ( - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + "context" + + "github.com/TBD54566975/ftl/go-runtime/ftl" + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" - "ftl/typeregistry/subpackage" + ftlbuiltin "ftl/builtin" + ftlsubpackage "ftl/typeregistry/subpackage" ) +type EchoClient func(context.Context, ftlbuiltin.HttpRequest[EchoRequest, ftl.Unit, ftl.Unit]) (ftlbuiltin.HttpResponse[EchoResponse, string], error) + func init() { reflection.Register( - reflection.SumType[subpackage.StringsTypeEnum]( - *new(subpackage.List), - *new(subpackage.Object), - *new(subpackage.Single), - ), - reflection.SumType[subpackage.StringsTypeEnum]( - *new(subpackage.List), - *new(subpackage.Object), - *new(subpackage.Single), + reflection.SumType[ftlsubpackage.StringsTypeEnum]( + *new(ftlsubpackage.List), + *new(ftlsubpackage.Object), + *new(ftlsubpackage.Single), ), - reflection.SumType[subpackage.StringsTypeEnum]( - *new(subpackage.List), - *new(subpackage.Object), - *new(subpackage.Single), + reflection.ProvideResourcesForVerb( + Echo, ), ) } \ No newline at end of file diff --git a/go-runtime/schema/call/analyzer.go b/go-runtime/schema/call/analyzer.go index 3974ffe225..74b5518ca2 100644 --- a/go-runtime/schema/call/analyzer.go +++ b/go-runtime/schema/call/analyzer.go @@ -3,19 +3,15 @@ package call import ( "go/ast" "go/types" - "strings" "github.com/TBD54566975/golang-tools/go/analysis" "github.com/TBD54566975/golang-tools/go/analysis/passes/inspect" "github.com/TBD54566975/golang-tools/go/ast/inspector" - "github.com/TBD54566975/ftl/backend/schema" - "github.com/TBD54566975/ftl/backend/schema/strcase" "github.com/TBD54566975/ftl/go-runtime/schema/common" ) const ( - ftlCallFuncPath = "github.com/TBD54566975/ftl/go-runtime/ftl.Call" ftlPkgPath = "github.com/TBD54566975/ftl/go-runtime/ftl" ftlTopicHandleTypeName = "TopicHandle" ) @@ -50,50 +46,12 @@ func Extract(pass *analysis.Pass) (interface{}, error) { if fn == nil { return } - if fn.FullName() == ftlCallFuncPath { - extractVerbCall(pass, parentFuncObj, node) - return - } - common.MarkFunctionCall(pass, parentFuncObj, fn) + common.MarkFunctionCall(pass, parentFuncObj, fn, common.GoPosToSchemaPos(pass.Fset, node.Pos())) } }) return common.NewExtractorResult(pass), nil } -func extractVerbCall(pass *analysis.Pass, parentFuncObj types.Object, node *ast.CallExpr) { - if len(node.Args) != 3 { - common.Errorf(pass, node, "call must have exactly three arguments") - return - } - ref := parseVerbRef(pass, node.Args[1]) - if ref == nil { - if sel, ok := node.Args[1].(*ast.SelectorExpr); ok { - common.Errorf(pass, node.Args[1], "call first argument must be a function but is an unresolved "+ - "reference to %s.%s, does it need to be exported?", sel.X, sel.Sel) - } - common.Errorf(pass, node.Args[1], "call first argument must be a function in an ftl module, does "+ - "it need to be exported?") - return - } - common.MarkVerbCall(pass, parentFuncObj, ref) -} - -func parseVerbRef(pass *analysis.Pass, node ast.Expr) *schema.Ref { - _, verbFn := common.Deref[*types.Func](pass, node) - if verbFn == nil { - return nil - } - moduleName, err := common.FtlModuleFromGoPackage(verbFn.Pkg().Path()) - if err != nil { - return nil - } - return &schema.Ref{ - Pos: common.GoPosToSchemaPos(pass.Fset, node.Pos()), - Module: moduleName, - Name: strcase.ToLowerCamel(verbFn.Name()), - } -} - // validateCallExpr validates all function calls // checks if the function call is: // - a direct verb call to an external module @@ -137,11 +95,4 @@ func validateCallExpr(pass *analysis.Pass, node *ast.CallExpr) { } return } - - if lhsIsExternal && strings.HasPrefix(lhsPkgPath, "ftl/") { - if sig, ok := pass.TypesInfo.TypeOf(selExpr.Sel).(*types.Signature); ok && sig.Recv() == nil { - // can not call functions in external modules directly - common.Errorf(pass, node, "can not call verbs in other modules directly: use ftl.Call(…) instead") - } - } } diff --git a/go-runtime/schema/common/fact.go b/go-runtime/schema/common/fact.go index cc43b05674..40d0eaff25 100644 --- a/go-runtime/schema/common/fact.go +++ b/go-runtime/schema/common/fact.go @@ -106,6 +106,8 @@ func (*ExternalType) schemaFactValue() {} type FunctionCall struct { // The function being called. Callee types.Object + // Position where the call takes place. + Position schema.Position } func (*FunctionCall) schemaFactValue() {} @@ -176,16 +178,9 @@ func MarkMaybeTypeEnum(pass *analysis.Pass, obj types.Object, enum *schema.Enum) } // MarkFunctionCall marks the given object as having an outbound function call. -func MarkFunctionCall(pass *analysis.Pass, obj types.Object, callee types.Object) { +func MarkFunctionCall(pass *analysis.Pass, obj types.Object, callee types.Object, pos schema.Position) { fact := newFact(pass, obj) - fact.Add(&FunctionCall{Callee: callee}) - pass.ExportObjectFact(obj, fact) -} - -// MarkVerbCall marks the given object as having a call to an FTL verb. -func MarkVerbCall(pass *analysis.Pass, obj types.Object, verbRef *schema.Ref) { - fact := newFact(pass, obj) - fact.Add(&VerbCall{VerbRef: verbRef}) + fact.Add(&FunctionCall{Callee: callee, Position: pos}) pass.ExportObjectFact(obj, fact) } diff --git a/go-runtime/schema/extract.go b/go-runtime/schema/extract.go index c3b6811d4d..a6a1c8e2a1 100644 --- a/go-runtime/schema/extract.go +++ b/go-runtime/schema/extract.go @@ -3,10 +3,9 @@ package schema import ( "fmt" "go/types" - "slices" - "strings" "time" + "github.com/TBD54566975/ftl/backend/schema/strcase" "github.com/TBD54566975/golang-tools/go/analysis" "github.com/TBD54566975/golang-tools/go/analysis/passes/inspect" checker "github.com/TBD54566975/golang-tools/go/analysis/programmaticchecker" @@ -142,8 +141,8 @@ type combinedData struct { errs []*schema.Error nativeNames NativeNames - functionCalls map[types.Object]sets.Set[types.Object] - verbCalls map[types.Object]sets.Set[*schema.Ref] + functionCalls map[schema.Position]finalize.FunctionCall + verbs map[types.Object]*schema.Verb refResults map[schema.RefKey]refResult extractedDecls map[schema.Decl]types.Object externalTypeAliases sets.Set[*schema.TypeAlias] @@ -156,8 +155,8 @@ func newCombinedData(diagnostics []analysis.SimpleDiagnostic) *combinedData { return &combinedData{ errs: diagnosticsToSchemaErrors(diagnostics), nativeNames: make(NativeNames), - functionCalls: make(map[types.Object]sets.Set[types.Object]), - verbCalls: make(map[types.Object]sets.Set[*schema.Ref]), + functionCalls: make(map[schema.Position]finalize.FunctionCall), + verbs: make(map[types.Object]*schema.Verb), refResults: make(map[schema.RefKey]refResult), extractedDecls: make(map[schema.Decl]types.Object), externalTypeAliases: sets.NewSet[*schema.TypeAlias](), @@ -178,13 +177,13 @@ func (cd *combinedData) update(fr finalize.Result) { copyFailedRefs(cd.refResults, fr.Failed) maps.Copy(cd.nativeNames, fr.NativeNames) maps.Copy(cd.functionCalls, fr.FunctionCalls) - maps.Copy(cd.verbCalls, fr.VerbCalls) } func (cd *combinedData) toResult() Result { cd.module.AddDecls(maps.Keys(cd.extractedDecls)) cd.updateDeclVisibility() cd.propagateTypeErrors() + cd.errorDirectVerbInvocations() schema.SortErrorsByPosition(cd.errs) return Result{ Module: cd.module, @@ -223,17 +222,15 @@ func (cd *combinedData) validateDecl(decl schema.Decl, obj types.Object) { cd.globalUniqueness[decl.GetName()] = tuple.Pair[types.Object, schema.Position]{A: obj, B: decl.Position()} } -func (cd *combinedData) getVerbCalls(obj types.Object) sets.Set[*schema.Ref] { - calls := sets.NewSet[*schema.Ref]() - if cls, ok := cd.verbCalls[obj]; ok { - calls.Append(cls.ToSlice()...) - } - if fnCall, ok := cd.functionCalls[obj]; ok { - for _, calleeObj := range fnCall.ToSlice() { - calls.Append(cd.getVerbCalls(calleeObj).ToSlice()...) +func (cd *combinedData) errorDirectVerbInvocations() { + for pos, fnCall := range cd.functionCalls { + if v, ok := cd.verbs[fnCall.Callee]; ok { + cd.error(schema.Errorf(pos, pos.Column, + "direct verb calls are not allowed; use the provided %sClient instead. "+ + "See https://tbd54566975.github.io/ftl/docs/reference/verbs/#calling-verbs", + strcase.ToUpperCamel(v.Name))) } } - return calls } // updateDeclVisibility traverses the module schema via refs and updates visibility as needed. @@ -379,16 +376,7 @@ func combineAllPackageResults(results map[*analysis.Analyzer][]any, diagnostics cd.nativeNames[d] = common.GetNativeName(obj) } case *schema.Verb: - calls := cd.getVerbCalls(obj).ToSlice() - slices.SortFunc(calls, func(i, j *schema.Ref) int { - if i.Module != j.Module { - return strings.Compare(i.Module, j.Module) - } - return strings.Compare(i.Name, j.Name) - }) - if len(calls) > 0 { - d.Metadata = append(d.Metadata, &schema.MetadataCalls{Calls: calls}) - } + cd.verbs[obj] = d default: } } diff --git a/go-runtime/schema/finalize/analyzer.go b/go-runtime/schema/finalize/analyzer.go index d1e7b5dc23..25bf53a091 100644 --- a/go-runtime/schema/finalize/analyzer.go +++ b/go-runtime/schema/finalize/analyzer.go @@ -6,14 +6,12 @@ import ( "reflect" "strings" - "github.com/TBD54566975/golang-tools/go/analysis" - "github.com/TBD54566975/golang-tools/go/analysis/passes/inspect" - "github.com/TBD54566975/golang-tools/go/ast/inspector" - sets "github.com/deckarep/golang-set/v2" - "github.com/TBD54566975/ftl/backend/schema" "github.com/TBD54566975/ftl/backend/schema/strcase" "github.com/TBD54566975/ftl/go-runtime/schema/common" + "github.com/TBD54566975/golang-tools/go/analysis" + "github.com/TBD54566975/golang-tools/go/analysis/passes/inspect" + "github.com/TBD54566975/golang-tools/go/ast/inspector" ) // Analyzer aggregates the results of all extractors. @@ -37,9 +35,12 @@ type Result struct { // Native names that can't be derived outside of the analysis pass. NativeNames map[schema.Node]string // FunctionCalls contains all function calls; key is the parent function, value is the called functions. - FunctionCalls map[types.Object]sets.Set[types.Object] - // VerbCalls contains all verb calls; key is the parent function, value is the called verbs. - VerbCalls map[types.Object]sets.Set[*schema.Ref] + FunctionCalls map[schema.Position]FunctionCall +} + +type FunctionCall struct { + Caller types.Object + Callee types.Object } func Run(pass *analysis.Pass) (interface{}, error) { @@ -79,39 +80,27 @@ func Run(pass *analysis.Pass) (interface{}, error) { nativeNames[fact.Node] = common.GetNativeName(obj) } } - fnCalls, verbCalls := getCalls(pass) return Result{ ModuleName: moduleName, ModuleComments: extractModuleComments(pass), Extracted: extracted, Failed: failed, NativeNames: nativeNames, - FunctionCalls: fnCalls, - VerbCalls: verbCalls, + FunctionCalls: getFunctionCalls(pass), }, nil } -func getCalls(pass *analysis.Pass) (functionCalls map[types.Object]sets.Set[types.Object], verbCalls map[types.Object]sets.Set[*schema.Ref]) { - fnCalls := make(map[types.Object]sets.Set[types.Object]) - for obj, calls := range common.GetAllFactsOfType[*common.FunctionCall](pass) { +func getFunctionCalls(pass *analysis.Pass) map[schema.Position]FunctionCall { + fnCalls := make(map[schema.Position]FunctionCall) + for caller, calls := range common.GetAllFactsOfType[*common.FunctionCall](pass) { for _, fnCall := range calls { - if fnCalls[obj] == nil { - fnCalls[obj] = sets.NewSet[types.Object]() - } - fnCalls[obj].Add(fnCall.Callee) - } - } - - vCalls := make(map[types.Object]sets.Set[*schema.Ref]) - for obj, calls := range common.GetAllFactsOfType[*common.VerbCall](pass) { - for _, vCall := range calls { - if vCalls[obj] == nil { - vCalls[obj] = sets.NewSet[*schema.Ref]() + fnCalls[fnCall.Position] = FunctionCall{ + Caller: caller, + Callee: fnCall.Callee, } - vCalls[obj].Add(vCall.VerbRef) } } - return fnCalls, vCalls + return fnCalls } func extractModuleComments(pass *analysis.Pass) []string { diff --git a/go-runtime/schema/schema_test.go b/go-runtime/schema/schema_test.go index 65203b3091..c696e54f05 100644 --- a/go-runtime/schema/schema_test.go +++ b/go-runtime/schema/schema_test.go @@ -568,53 +568,46 @@ func TestErrorReporting(t *testing.T) { // failing/failing.go expectedParent := []string{ - `13:13-34: expected string literal for argument at index 0`, - `16:18-18: duplicate config declaration for "failing.FTL_CONFIG_ENDPOINT"; already declared at "37:18"`, - `19:18-18: duplicate secret declaration for "failing.FTL_SECRET_ENDPOINT"; already declared at "38:18"`, - `22:14-14: duplicate database declaration for "failing.testDb"; already declared at "41:14"`, - `25:2-10: unsupported type "error" for field "BadParam"`, - `28:2-17: unsupported type "uint64" for field "AnotherBadParam"`, - `31:3-3: unexpected directive "ftl:export" attached for verb, did you mean to use '//ftl:verb export' instead?`, - `37:40-40: unsupported request type "ftl/failing.Request"`, - `37:50-50: unsupported response type "ftl/failing.Response"`, - `38:16-29: call first argument must be a function but is an unresolved reference to lib.OtherFunc, does it need to be exported?`, - `38:16-29: call first argument must be a function in an ftl module, does it need to be exported?`, - `39:2-46: call must have exactly three arguments`, - `40:16-25: call first argument must be a function in an ftl module, does it need to be exported?`, - `45:45-45: unsupported request type "ftl/failing.Request"`, - `45:54-66: unsupported verb parameter type "Request"; verbs must have the signature func(Context, Request?, Resources...)`, - `45:69-69: unsupported response type "ftl/failing.Response"`, - `50:22-27: first parameter must be of type context.Context but is ftl/failing.Request`, - `50:53-53: unsupported response type "ftl/failing.Response"`, - `55:43-47: second parameter must not be ftl.Unit`, - `55:59-59: unsupported response type "ftl/failing.Response"`, - `60:1-2: first parameter must be context.Context`, - `60:18-18: unsupported response type "ftl/failing.Response"`, - `65:1-2: must have at most two results (, error)`, - `65:45-45: unsupported request type "ftl/failing.Request"`, - `70:1-2: must at least return an error`, - `70:40-40: unsupported request type "ftl/failing.Request"`, - `74:39-39: unsupported request type "ftl/failing.Request"`, - `74:48-48: must return an error but is ftl/failing.Response`, - `79:45-45: unsupported request type "ftl/failing.Request"`, - `79:63-63: must return an error but is string`, - `79:63-63: second result must not be ftl.Unit`, - // `86:1-2: duplicate declaration of "WrongResponse" at 79:6`, TODO: fix this - `90:3-3: unexpected directive "ftl:verb"`, - `99:6-18: "BadValueEnum" is a value enum and cannot be tagged as a variant of type enum "TypeEnum" directly`, - `108:6-35: "BadValueEnumOrderDoesntMatter" is a value enum and cannot be tagged as a variant of type enum "TypeEnum" directly`, - `120:6-6: schema declaration with name "PrivateData" already exists for module "failing"; previously declared at "40:25"`, - `124:21-60: config names must be valid identifiers`, - `130:1-1: schema declaration contains conflicting directives`, - `130:1-26: only one directive expected when directive "ftl:enum" is present, found multiple`, - `152:6-45: enum discriminator "TypeEnum3" cannot contain exported methods`, - `155:6-35: enum discriminator "NoMethodsTypeEnum" must define at least one method`, - `167:3-14: unexpected token "d"`, - `174:2-62: can not publish directly to topics in other modules`, - `175:9-26: can not call verbs in other modules directly: use ftl.Call(…) instead`, - `180:2-12: struct field unexported must be exported by starting with an uppercase letter`, - `184:6-6: unsupported type "ftl/failing/child.BadChildStruct" for field "child"`, - `189:6-6: duplicate data declaration for "failing.Redeclared"; already declared at "27:6"`, + `12:13-34: expected string literal for argument at index 0`, + `15:18-18: duplicate config declaration for "failing.FTL_CONFIG_ENDPOINT"; already declared at "37:18"`, + `18:18-18: duplicate secret declaration for "failing.FTL_SECRET_ENDPOINT"; already declared at "38:18"`, + `21:14-14: duplicate database declaration for "failing.testDb"; already declared at "41:14"`, + `24:2-10: unsupported type "error" for field "BadParam"`, + `27:2-17: unsupported type "uint64" for field "AnotherBadParam"`, + `30:3-3: unexpected directive "ftl:export" attached for verb, did you mean to use '//ftl:verb export' instead?`, + `36:45-45: unsupported request type "ftl/failing.Request"`, + `36:54-66: unsupported verb parameter type "Request"; verbs must have the signature func(Context, Request?, Resources...)`, + `36:69-69: unsupported response type "ftl/failing.Response"`, + `41:22-27: first parameter must be of type context.Context but is ftl/failing.Request`, + `41:53-53: unsupported response type "ftl/failing.Response"`, + `46:43-47: second parameter must not be ftl.Unit`, + `46:59-59: unsupported response type "ftl/failing.Response"`, + `51:1-2: first parameter must be context.Context`, + `51:18-18: unsupported response type "ftl/failing.Response"`, + `56:1-2: must have at most two results (, error)`, + `56:45-45: unsupported request type "ftl/failing.Request"`, + `61:1-2: must at least return an error`, + `61:40-40: unsupported request type "ftl/failing.Request"`, + `65:39-39: unsupported request type "ftl/failing.Request"`, + `65:48-48: must return an error but is ftl/failing.Response`, + `70:45-45: unsupported request type "ftl/failing.Request"`, + `70:63-63: must return an error but is string`, + `70:63-63: second result must not be ftl.Unit`, + `81:3-3: unexpected directive "ftl:verb"`, + `90:6-18: "BadValueEnum" is a value enum and cannot be tagged as a variant of type enum "TypeEnum" directly`, + `99:6-35: "BadValueEnumOrderDoesntMatter" is a value enum and cannot be tagged as a variant of type enum "TypeEnum" directly`, + `111:6-6: schema declaration with name "PrivateData" already exists for module "failing"; previously declared at "40:25"`, + `115:21-60: config names must be valid identifiers`, + `121:1-1: schema declaration contains conflicting directives`, + `121:1-26: only one directive expected when directive "ftl:enum" is present, found multiple`, + `143:6-45: enum discriminator "TypeEnum3" cannot contain exported methods`, + `146:6-35: enum discriminator "NoMethodsTypeEnum" must define at least one method`, + `158:3-14: unexpected token "d"`, + `165:2-62: can not publish directly to topics in other modules`, + `171:2-12: struct field unexported must be exported by starting with an uppercase letter`, + `175:6-6: unsupported type "ftl/failing/child.BadChildStruct" for field "child"`, + `180:6-6: duplicate data declaration for "failing.Redeclared"; already declared at "27:6"`, + `197:9-9: direct verb calls are not allowed; use the provided EmptyClient instead. See https://tbd54566975.github.io/ftl/docs/reference/verbs/#calling-verbs`, } // failing/child/child.go @@ -624,7 +617,7 @@ func TestErrorReporting(t *testing.T) { `14:8-8: unsupported external type "github.com/TBD54566975/ftl/go-runtime/schema/testdata.NonFTLType"; see FTL docs on using external types: tbd54566975.github.io/ftl/docs/reference/externaltypes/`, `19:6-41: declared type github.com/blah.lib.NonFTLType in typemap does not match native type github.com/TBD54566975/ftl/go-runtime/schema/testdata.lib.NonFTLType`, `24:6-6: multiple Go type mappings found for "ftl/failing/child.MultipleMappings"`, - `34:2-13: enum variant "SameVariant" conflicts with existing enum variant of "EnumVariantConflictParent" at "196:2"`, + `34:2-13: enum variant "SameVariant" conflicts with existing enum variant of "EnumVariantConflictParent" at "187:2"`, } assert.Equal(t, expectedParent, actualParent) assert.Equal(t, expectedChild, actualChild) diff --git a/go-runtime/schema/testdata/failing/failing.go b/go-runtime/schema/testdata/failing/failing.go index 231518bcbe..85aabcf0c0 100644 --- a/go-runtime/schema/testdata/failing/failing.go +++ b/go-runtime/schema/testdata/failing/failing.go @@ -3,11 +3,10 @@ package failing import ( "context" - "github.com/TBD54566975/ftl/go-runtime/ftl" - lib "github.com/TBD54566975/ftl/go-runtime/schema/testdata" - "ftl/failing/child" ps "ftl/pubsub" + + "github.com/TBD54566975/ftl/go-runtime/ftl" ) var empty = ftl.Config[string](1) @@ -33,14 +32,6 @@ func WrongDirective(ctx context.Context, req Request) (Response, error) { return Response{}, nil } -//ftl:verb -func BadCalls(ctx context.Context, req Request) (Response, error) { - ftl.Call(ctx, lib.OtherFunc, lib.Request{}) - ftl.Call(ctx, "failing", "failingVerb", req) - ftl.Call(ctx, "failing", req) - return Response{}, nil -} - //ftl:verb func TooManyParams(ctx context.Context, req Request, req2 Request) (Response, error) { return Response{}, nil @@ -195,3 +186,13 @@ type EnumVariantConflictParent int const ( SameVariant EnumVariantConflictParent = iota ) + +//ftl:verb +func Empty(ctx context.Context) error { + return nil +} + +//ftl:verb +func CallsEmptyDirectly(ctx context.Context) error { + return Empty(ctx) +} diff --git a/go-runtime/schema/testdata/named/types.ftl.go b/go-runtime/schema/testdata/named/types.ftl.go index 298e1e499f..0f11de20af 100644 --- a/go-runtime/schema/testdata/named/types.ftl.go +++ b/go-runtime/schema/testdata/named/types.ftl.go @@ -2,12 +2,11 @@ package named import ( - "context" + "context" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" ) - type PingInternalUserClient func(context.Context, InternalUser) error type PingUserClient func(context.Context, User) error diff --git a/go-runtime/schema/testdata/namedext/types.ftl.go b/go-runtime/schema/testdata/namedext/types.ftl.go index 5acca50bbb..d08d78d1db 100644 --- a/go-runtime/schema/testdata/namedext/types.ftl.go +++ b/go-runtime/schema/testdata/namedext/types.ftl.go @@ -1,5 +1,3 @@ // Code generated by FTL. DO NOT EDIT. package namedext - - diff --git a/go-runtime/schema/testdata/one/types.ftl.go b/go-runtime/schema/testdata/one/types.ftl.go index b8db693bc5..d9b4f89d89 100644 --- a/go-runtime/schema/testdata/one/types.ftl.go +++ b/go-runtime/schema/testdata/one/types.ftl.go @@ -2,14 +2,14 @@ package one import ( - "context" - ftlbuiltin "ftl/builtin" - stdtime "time" + "context" + stdtime "time" - "github.com/TBD54566975/ftl/go-runtime/ftl" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" -) + "github.com/TBD54566975/ftl/go-runtime/ftl" + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + ftlbuiltin "ftl/builtin" +) type BatchStringToTimeClient func(context.Context, []string) ([]stdtime.Time, error) diff --git a/go-runtime/schema/testdata/parent/types.ftl.go b/go-runtime/schema/testdata/parent/types.ftl.go index a001758eb2..3347538ddd 100644 --- a/go-runtime/schema/testdata/parent/types.ftl.go +++ b/go-runtime/schema/testdata/parent/types.ftl.go @@ -2,12 +2,12 @@ package parent import ( - "context" - ftlchild "ftl/parent/child" + "context" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" -) + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + ftlchild "ftl/parent/child" +) type ChildVerbClient func(context.Context) (ftlchild.Resp, error) diff --git a/go-runtime/schema/testdata/pubsub/types.ftl.go b/go-runtime/schema/testdata/pubsub/types.ftl.go index ca7e05534f..70b21e348a 100644 --- a/go-runtime/schema/testdata/pubsub/types.ftl.go +++ b/go-runtime/schema/testdata/pubsub/types.ftl.go @@ -2,12 +2,11 @@ package pubsub import ( - "context" + "context" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" ) - type BroadcastClient func(context.Context) error type PayinClient func(context.Context) error diff --git a/go-runtime/schema/testdata/subscriber/types.ftl.go b/go-runtime/schema/testdata/subscriber/types.ftl.go index 132a7d7c28..d6d78540fc 100644 --- a/go-runtime/schema/testdata/subscriber/types.ftl.go +++ b/go-runtime/schema/testdata/subscriber/types.ftl.go @@ -2,12 +2,12 @@ package subscriber import ( - "context" - ftlpubsub "ftl/pubsub" + "context" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" -) + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + ftlpubsub "ftl/pubsub" +) type ConsumesSubscriptionFromExternalTopicClient func(context.Context, ftlpubsub.PayinEvent) error diff --git a/go-runtime/schema/testdata/two/go.mod b/go-runtime/schema/testdata/two/go.mod index db7a94a2e3..3fe552e7cd 100644 --- a/go-runtime/schema/testdata/two/go.mod +++ b/go-runtime/schema/testdata/two/go.mod @@ -16,15 +16,19 @@ require ( github.com/XSAM/otelsql v0.34.0 // indirect github.com/alecthomas/atomic v0.1.0-alpha2 // indirect github.com/alecthomas/concurrency v0.0.2 // indirect + github.com/alecthomas/kong v1.2.1 // indirect github.com/alecthomas/participle/v2 v2.1.1 // indirect github.com/alecthomas/types v0.16.0 // indirect github.com/alessio/shellescape v1.4.2 // indirect github.com/benbjohnson/clock v1.3.5 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/danieljoos/wincred v1.2.0 // indirect github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect github.com/hashicorp/cronexpr v1.1.2 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect @@ -38,8 +42,15 @@ require ( github.com/swaggest/refl v1.3.0 // indirect github.com/zalando/go-keyring v0.2.5 // indirect go.opentelemetry.io/otel v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 // indirect go.opentelemetry.io/otel/metric v1.30.0 // indirect + go.opentelemetry.io/otel/sdk v1.30.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.30.0 // indirect go.opentelemetry.io/otel/trace v1.30.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.uber.org/automaxprocs v1.6.0 // indirect golang.org/x/crypto v0.27.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/mod v0.21.0 // indirect @@ -47,5 +58,8 @@ require ( golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/grpc v1.66.2 // indirect google.golang.org/protobuf v1.34.2 // indirect ) diff --git a/go-runtime/schema/testdata/two/go.sum b/go-runtime/schema/testdata/two/go.sum index e86889ebc9..0dece39d76 100644 --- a/go-runtime/schema/testdata/two/go.sum +++ b/go-runtime/schema/testdata/two/go.sum @@ -14,6 +14,8 @@ github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELk github.com/alecthomas/atomic v0.1.0-alpha2/go.mod h1:zD6QGEyw49HIq19caJDc2NMXAy8rNi9ROrxtMXATfyI= github.com/alecthomas/concurrency v0.0.2 h1:Q3kGPtLbleMbH9lHX5OBFvJygfyFw29bXZKBg+IEVuo= github.com/alecthomas/concurrency v0.0.2/go.mod h1:GmuQb/iHX7mbNtPlC/WDzEFxDMB0HYFer2Qda9QTs7w= +github.com/alecthomas/kong v1.2.1 h1:E8jH4Tsgv6wCRX2nGrdPyHDUCSG83WH2qE4XLACD33Q= +github.com/alecthomas/kong v1.2.1/go.mod h1:rKTSFhbdp3Ryefn8x5MOEprnRFQ7nlmMC01GKhehhBM= github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= @@ -28,6 +30,8 @@ github.com/bool64/dev v0.2.35 h1:M17TLsO/pV2J7PYI/gpe3Ua26ETkzZGb+dC06eoMqlk= github.com/bool64/dev v0.2.35/go.mod h1:iJbh1y/HkunEPhgebWRNcs8wfGq7sjvJ6W5iabL8ACg= github.com/bool64/shared v0.1.5 h1:fp3eUhBsrSjNCQPcSdQqZxxh9bBwrYiZ+zOKFkM0/2E= github.com/bool64/shared v0.1.5/go.mod h1:081yz68YC9jeFB3+Bbmno2RFWvGKv1lPKkMP6MHJlPs= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -66,6 +70,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/cronexpr v1.1.2 h1:wG/ZYIKT+RT3QkOdgYc+xsKWVRgnxJ1OJtjjy84fJ9A= github.com/hashicorp/cronexpr v1.1.2/go.mod h1:P4wA0KBl9C5q2hABiMO7cp6jcIg96CDh1Efb3g1PWA4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= @@ -110,6 +116,8 @@ github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/puzpuzpuz/xsync/v3 v3.4.0 h1:DuVBAdXuGFHv8adVXjWWZ63pJq+NRXOWVXlKDBZ+mJ4= github.com/puzpuzpuz/xsync/v3 v3.4.0/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= @@ -143,6 +151,12 @@ github.com/zalando/go-keyring v0.2.5 h1:Bc2HHpjALryKD62ppdEzaFG6VxL6Bc+5v0LYpN8L github.com/zalando/go-keyring v0.2.5/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0 h1:WypxHH02KX2poqqbaadmkMYalGyy/vil4HE4PM4nRJc= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.30.0/go.mod h1:U79SV99vtvGSEBeeHnpgGJfTsnsdkWLpPN/CcHAzBSI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0 h1:m0yTiGDLUvVYaTFbAvCkVYIYcvwKt3G7OLoN77NUs/8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.30.0/go.mod h1:wBQbT4UekBfegL2nx0Xk1vBcnzyBPsIVm9hRG4fYcr4= go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE= @@ -151,6 +165,12 @@ go.opentelemetry.io/otel/sdk/metric v1.30.0 h1:QJLT8Pe11jyHBHfSAgYH7kEmT24eX792j go.opentelemetry.io/otel/sdk/metric v1.30.0/go.mod h1:waS6P3YqFNzeP01kuo/MBBYqaoBJl7efRQHOaydhy1Y= go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= +go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= @@ -174,6 +194,10 @@ golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo= +google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/go-runtime/schema/testdata/two/two.go b/go-runtime/schema/testdata/two/two.go index 971025389f..1f949568e3 100644 --- a/go-runtime/schema/testdata/two/two.go +++ b/go-runtime/schema/testdata/two/two.go @@ -63,13 +63,13 @@ func Three(ctx context.Context, req Payload[string]) (Payload[string], error) { } //ftl:verb export -func CallsTwo(ctx context.Context, req Payload[string]) (Payload[string], error) { - return ftl.Call(ctx, Two, req) +func CallsTwo(ctx context.Context, req Payload[string], two TwoClient) (Payload[string], error) { + return two(ctx, req) } //ftl:verb export -func CallsTwoAndThree(ctx context.Context, req Payload[string]) (Payload[string], error) { - err := transitiveVerbCall(ctx, req) +func CallsTwoAndThree(ctx context.Context, req Payload[string], two TwoClient, three ThreeClient) (Payload[string], error) { + err := transitiveVerbCall(ctx, req, two, three) return Payload[string]{}, err } @@ -107,17 +107,17 @@ type TransitiveAlias lib.NonFTLType //ftl:typealias type BackoffAlias libbackoff.Backoff -func transitiveVerbCall(ctx context.Context, req Payload[string]) error { - _, err := ftl.Call(ctx, Two, req) +func transitiveVerbCall(ctx context.Context, req Payload[string], two TwoClient, three ThreeClient) error { + _, err := two(ctx, req) if err != nil { return err } - err = superTransitiveVerbCall(ctx, req) + err = superTransitiveVerbCall(ctx, req, three) return err } -func superTransitiveVerbCall(ctx context.Context, req Payload[string]) error { - _, err := ftl.Call(ctx, Three, req) +func superTransitiveVerbCall(ctx context.Context, req Payload[string], three ThreeClient) error { + _, err := three(ctx, req) return err } diff --git a/go-runtime/schema/testdata/two/types.ftl.go b/go-runtime/schema/testdata/two/types.ftl.go index 9e158c5ddc..46dd843f45 100644 --- a/go-runtime/schema/testdata/two/types.ftl.go +++ b/go-runtime/schema/testdata/two/types.ftl.go @@ -2,17 +2,17 @@ package two import ( - "context" + "context" - "github.com/TBD54566975/ftl/go-runtime/ftl" - "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" - "github.com/jpillora/backoff" - lib "github.com/TBD54566975/ftl/go-runtime/schema/testdata" + "github.com/TBD54566975/ftl/go-runtime/ftl" + "github.com/TBD54566975/ftl/go-runtime/ftl/reflection" + "github.com/TBD54566975/ftl/go-runtime/server" + "github.com/jpillora/backoff" + lib "github.com/TBD54566975/ftl/go-runtime/schema/testdata" - ftlbuiltin "ftl/builtin" + ftlbuiltin "ftl/builtin" ) - type CallsTwoClient func(context.Context, Payload[string]) (Payload[string], error) type TwoClient func(context.Context, Payload[string]) (Payload[string], error) @@ -37,12 +37,15 @@ func init() { reflection.ExternalType(*new(lib.NonFTLType)), reflection.ProvideResourcesForVerb( CallsTwo, + server.VerbClient[TwoClient, Payload[string], Payload[string]](), ), reflection.ProvideResourcesForVerb( Two, ), reflection.ProvideResourcesForVerb( CallsTwoAndThree, + server.VerbClient[ThreeClient, Payload[string], Payload[string]](), + server.VerbClient[TwoClient, Payload[string], Payload[string]](), ), reflection.ProvideResourcesForVerb( Three, diff --git a/go-runtime/schema/verb/analyzer.go b/go-runtime/schema/verb/analyzer.go index edca99a7cb..62552469a4 100644 --- a/go-runtime/schema/verb/analyzer.go +++ b/go-runtime/schema/verb/analyzer.go @@ -3,6 +3,7 @@ package verb import ( "go/ast" "go/types" + "slices" "strings" "unicode" @@ -93,7 +94,7 @@ func Extract(pass *analysis.Pass, node *ast.FuncDecl, obj types.Object) optional } verb.Request = reqV verb.Response = resV - + sortMetadata(verb) return optional.Some(verb) } @@ -171,3 +172,16 @@ func getResourceRef(paramObj types.Object, pass *analysis.Pass, param *ast.Field } return dbRef } + +func sortMetadata(verb *schema.Verb) { + for _, md := range verb.Metadata { + if calls, ok := md.(*schema.MetadataCalls); ok { + slices.SortFunc(calls.Calls, func(i, j *schema.Ref) int { + if i.Module != j.Module { + return strings.Compare(i.Module, j.Module) + } + return strings.Compare(i.Name, j.Name) + }) + } + } +} diff --git a/go-runtime/server/server.go b/go-runtime/server/server.go index a13f72fa8b..e035eb8976 100644 --- a/go-runtime/server/server.go +++ b/go-runtime/server/server.go @@ -108,14 +108,14 @@ func HandleEmpty(verb any) Handler { return HandleCall[ftl.Unit, ftl.Unit](verb) } -func VerbClient[Verb, Req, Resp any]() reflection.VerbResource { +func call[Verb, Req, Resp any]() func(ctx context.Context, req Req) (resp Resp, err error) { typ := reflect.TypeFor[Verb]() if typ.Kind() != reflect.Func { panic(fmt.Sprintf("Cannot register %s: expected function, got %s", typ, typ.Kind())) } callee := reflection.TypeRef[Verb]() callee.Name = strings.TrimSuffix(callee.Name, "Client") - fn := func(ctx context.Context, req Req) (resp Resp, err error) { + return func(ctx context.Context, req Req) (resp Resp, err error) { ref := reflection.Ref{Module: callee.Module, Name: callee.Name} moduleCtx := modulecontext.FromContext(ctx).CurrentContext() override, err := moduleCtx.BehaviorForVerb(schema.Ref{Module: ref.Module, Name: ref.Name}) @@ -159,21 +159,45 @@ func VerbClient[Verb, Req, Resp any]() reflection.VerbResource { panic(fmt.Sprintf("%s: invalid response type %T", callee, cresp)) } } +} + +func VerbClient[Verb, Req, Resp any]() reflection.VerbResource { + fnCall := call[Verb, Req, Resp]() return func() reflect.Value { - return reflect.ValueOf(fn) + return reflect.ValueOf(fnCall) } } func SinkClient[Verb, Req any]() reflection.VerbResource { - return VerbClient[Verb, Req, ftl.Unit]() + fnCall := call[Verb, Req, ftl.Unit]() + sink := func(ctx context.Context, req Req) error { + _, err := fnCall(ctx, req) + return err + } + return func() reflect.Value { + return reflect.ValueOf(sink) + } } func SourceClient[Verb, Resp any]() reflection.VerbResource { - return VerbClient[Verb, ftl.Unit, Resp]() + fnCall := call[Verb, ftl.Unit, Resp]() + source := func(ctx context.Context) (Resp, error) { + return fnCall(ctx, ftl.Unit{}) + } + return func() reflect.Value { + return reflect.ValueOf(source) + } } func EmptyClient[Verb any]() reflection.VerbResource { - return VerbClient[Verb, ftl.Unit, ftl.Unit]() + fnCall := call[Verb, ftl.Unit, ftl.Unit]() + source := func(ctx context.Context) error { + _, err := fnCall(ctx, ftl.Unit{}) + return err + } + return func() reflect.Value { + return reflect.ValueOf(source) + } } func Call[Req, Resp any](ref reflection.Ref) func(ctx context.Context, req Req) (resp Resp, err error) { diff --git a/internal/buildengine/stubs_test.go b/internal/buildengine/stubs_test.go index 9f83a886c5..243efcf2c7 100644 --- a/internal/buildengine/stubs_test.go +++ b/internal/buildengine/stubs_test.go @@ -139,11 +139,6 @@ type EchoRequest struct { type EchoResponse struct { } -//ftl:verb -func Echo(context.Context, EchoRequest) (EchoResponse, error) { - panic("Verb stubs should not be called directly, instead use github.com/TBD54566975/ftl/runtime-go/ftl.Call()") -} - //ftl:verb type EchoClient func(context.Context, EchoRequest) (EchoResponse, error) @@ -154,30 +149,15 @@ type SinkReq struct { // // Here is another line for this comment! // -//ftl:verb -func Sink(context.Context, SinkReq) error { - panic("Verb stubs should not be called directly, instead use github.com/TBD54566975/ftl/runtime-go/ftl.CallSink()") -} - //ftl:verb type SinkClient func(context.Context, SinkReq) type SourceResp struct { } -//ftl:verb -func Source(context.Context) (SourceResp, error) { - panic("Verb stubs should not be called directly, instead use github.com/TBD54566975/ftl/runtime-go/ftl.CallSource()") -} - //ftl:verb type SourceClient func(context.Context) (SourceResp, error) -//ftl:verb -func Nothing(context.Context) error { - panic("Verb stubs should not be called directly, instead use github.com/TBD54566975/ftl/runtime-go/ftl.CallEmpty()") -} - //ftl:verb type NothingClient func(context.Context) error @@ -246,11 +226,6 @@ type Resp struct { // This is a verb. // -//ftl:verb -func Call(context.Context, Req) (Resp, error) { - panic("Verb stubs should not be called directly, instead use github.com/TBD54566975/ftl/runtime-go/ftl.Call()") -} - //ftl:verb type CallClient func(context.Context, Req) (Resp, error) `