diff --git a/Bitfile b/Bitfile index 779b49fb6f..65623631a9 100644 --- a/Bitfile +++ b/Bitfile @@ -96,6 +96,10 @@ kotlin-runtime/scaffolding.zip: kotlin-runtime/scaffolding/**/* cd kotlin-runtime/scaffolding build: zip -q --symlinks -r ../scaffolding.zip . +kotlin-runtime/external-module-template.zip: kotlin-runtime/external-module-template/**/* + cd kotlin-runtime/external-module-template + build: zip -q --symlinks -r ../external-module-template.zip . + %{SCHEMA_OUT}: %{SCHEMA_IN} build: ftl-schema > %{OUT} diff --git a/buildengine/build_kotlin.go b/buildengine/build_kotlin.go index e7c8f25e2e..b15d488ca5 100644 --- a/buildengine/build_kotlin.go +++ b/buildengine/build_kotlin.go @@ -3,24 +3,59 @@ package buildengine import ( "context" "fmt" + sets "github.com/deckarep/golang-set/v2" "os" "path/filepath" - - "github.com/beevik/etree" + "reflect" + "sort" + "strings" "github.com/TBD54566975/ftl" "github.com/TBD54566975/ftl/backend/schema" + "github.com/TBD54566975/ftl/backend/schema/strcase" + "github.com/TBD54566975/ftl/internal" "github.com/TBD54566975/ftl/internal/exec" "github.com/TBD54566975/ftl/internal/log" + kotlinruntime "github.com/TBD54566975/ftl/kotlin-runtime" + "github.com/TBD54566975/scaffolder" + "github.com/beevik/etree" + "golang.org/x/exp/maps" ) -func buildKotlin(ctx context.Context, _ *schema.Schema, module Module) error { - logger := log.FromContext(ctx) +type externalModuleContext struct { + module Module + *schema.Schema +} + +func (e externalModuleContext) ExternalModules() []*schema.Module { + depsSet := make(map[string]struct{}) + for _, dep := range e.module.Dependencies { + depsSet[dep] = struct{}{} + } + modules := make([]*schema.Module, 0) + for _, module := range e.Modules { + if _, exists := depsSet[module.Name]; exists || module.Name == "builtin" { + modules = append(modules, module) + } + } + return modules +} + +func buildKotlin(ctx context.Context, sch *schema.Schema, module Module) error { + logger := log.FromContext(ctx) if err := SetPOMProperties(ctx, filepath.Join(module.Dir, "..")); err != nil { return fmt.Errorf("unable to update ftl.version in %s: %w", module.Dir, err) } + if err := generateExternalModules(ctx, module, sch); err != nil { + return fmt.Errorf("unable to generate external modules for %s: %w", module.Module, err) + } + + if err := prepareFTLRoot(module); err != nil { + return fmt.Errorf("unable to prepare FTL root for %s: %w", module.Module, err) + } + logger.Debugf("Using build command '%s'", module.Build) err := exec.Command(ctx, log.Debug, module.Dir, "bash", "-c", module.Build).RunBuffered(ctx) if err != nil { @@ -72,3 +107,180 @@ func SetPOMProperties(ctx context.Context, baseDir string) error { return tree.WriteToFile(pomFile) } + +func prepareFTLRoot(module Module) error { + buildDir := filepath.Join(module.Dir, "target") + if err := os.MkdirAll(buildDir, 0700); err != nil { + return err + } + + fileContent := fmt.Sprintf(` +SchemaExtractorRuleSet: + ExtractSchemaRule: + active: true + output: %s +`, buildDir) + + detektYmlPath := filepath.Join(buildDir, "detekt.yml") + if err := os.WriteFile(detektYmlPath, []byte(fileContent), 0600); err != nil { + return fmt.Errorf("unable to configure detekt for %s: %w", module.Module, err) + } + + mainFilePath := filepath.Join(buildDir, "main") + + mainFile := `#!/bin/bash +exec java -cp "classes:$(cat classpath.txt)" xyz.block.ftl.main.MainKt +` + if err := os.WriteFile(mainFilePath, []byte(mainFile), 0700); err != nil { //nolint:gosec + return fmt.Errorf("unable to configure main executable for %s: %w", module.Module, err) + } + return nil +} + +func generateExternalModules(ctx context.Context, module Module, sch *schema.Schema) error { + logger := log.FromContext(ctx) + config := module.ModuleConfig + funcs := maps.Clone(scaffoldFuncs) + + // Wipe the modules directory to ensure we don't have any stale modules. + _ = os.RemoveAll(filepath.Join(config.Dir, "target", "generated-sources", "ftl")) + + logger.Debugf("Generating external modules") + return internal.ScaffoldZip(kotlinruntime.ExternalModuleTemplates(), config.Dir, externalModuleContext{ + module: module, + Schema: sch, + }, scaffolder.Functions(funcs)) +} + +var scaffoldFuncs = scaffolder.FuncMap{ + "snake": strcase.ToLowerSnake, + "screamingSnake": strcase.ToUpperSnake, + "camel": strcase.ToUpperCamel, + "lowerCamel": strcase.ToLowerCamel, + "kebab": strcase.ToLowerKebab, + "screamingKebab": strcase.ToUpperKebab, + "upper": strings.ToUpper, + "lower": strings.ToLower, + "title": strings.Title, + "typename": schema.TypeName, + "comment": func(s []string) string { + if len(s) == 0 { + return "" + } + var sb strings.Builder + sb.WriteString("/**\n") + for _, line := range s { + sb.WriteString(" * ") + sb.WriteString(line) + sb.WriteString("\n") + } + sb.WriteString(" */\n") + return sb.String() + }, + "type": genType, + "is": func(kind string, t schema.Node) bool { + return reflect.Indirect(reflect.ValueOf(t)).Type().Name() == kind + }, + "imports": func(m *schema.Module) []string { + imports := sets.NewSet[string]() + _ = schema.Visit(m, func(n schema.Node, next func() error) error { + switch n := n.(type) { + case *schema.DataRef: + decl := m.Resolve(schema.Ref{ + Module: n.Module, + Name: n.Name, + }) + if decl != nil { + if data, ok := decl.Decl.(*schema.Data); ok { + if len(data.Fields) == 0 { + imports.Add("ftl.builtin.Empty") + break + } + } + } + + if n.Module == "" { + break + } + + imports.Add("ftl." + n.Module + "." + n.Name) + + for _, tp := range n.TypeParameters { + tpRef, err := schema.ParseDataRef(tp.String()) + if err != nil { + return err + } + if tpRef.Module != "" && tpRef.Module != m.Name { + imports.Add("ftl." + tpRef.Module + "." + tpRef.Name) + } + } + case *schema.Verb: + imports.Append("xyz.block.ftl.Context", "xyz.block.ftl.Ignore", "xyz.block.ftl.Verb") + + case *schema.Time: + imports.Add("java.time.OffsetDateTime") + + default: + } + return next() + }) + importsList := imports.ToSlice() + sort.Strings(importsList) + return importsList + }, +} + +func genType(module *schema.Module, t schema.Type) string { + switch t := t.(type) { + case *schema.DataRef: + decl := module.Resolve(schema.Ref{ + Module: t.Module, + Name: t.Name, + }) + if decl != nil { + if data, ok := decl.Decl.(*schema.Data); ok { + if len(data.Fields) == 0 { + return "Empty" + } + } + } + + desc := t.Name + if len(t.TypeParameters) > 0 { + desc += "<" + for i, tp := range t.TypeParameters { + if i != 0 { + desc += ", " + } + desc += genType(module, tp) + } + desc += ">" + } + return desc + + case *schema.Time: + return "OffsetDateTime" + + case *schema.Array: + return "List<" + genType(module, t.Element) + ">" + + case *schema.Map: + return "Map<" + genType(module, t.Key) + ", " + genType(module, t.Value) + ">" + + case *schema.Optional: + return genType(module, t.Type) + "? = null" + + case *schema.Bytes: + return "ByteArray" + + case *schema.Bool: + return "Boolean" + + case *schema.Int: + return "Long" + + case *schema.Float, *schema.String, *schema.Any, *schema.Unit: + return t.String() + } + panic(fmt.Sprintf("unsupported type %T", t)) +} diff --git a/buildengine/build_kotlin_test.go b/buildengine/build_kotlin_test.go new file mode 100644 index 0000000000..68b1bf0abd --- /dev/null +++ b/buildengine/build_kotlin_test.go @@ -0,0 +1,269 @@ +package buildengine + +import ( + "context" + "os" + "path/filepath" + "testing" + + "github.com/TBD54566975/ftl/backend/schema" + "github.com/TBD54566975/ftl/internal/log" + "github.com/alecthomas/assert/v2" +) + +func TestGenerateBasicModule(t *testing.T) { + sch := &schema.Schema{ + Modules: []*schema.Module{{Name: "test"}}, + } + expected := `// Code generated by FTL. DO NOT EDIT. +package ftl.test + +` + assertExpectedSchema(t, sch, "test/Test.kt", expected) +} + +func TestGenerateAllTypes(t *testing.T) { + sch := &schema.Schema{ + Modules: []*schema.Module{ + { + Name: "test", + Comments: []string{"Module comments"}, + Decls: []schema.Decl{ + &schema.Data{ + Name: "ParamTestData", + TypeParameters: []*schema.TypeParameter{{Name: "T"}}, + Fields: []*schema.Field{ + {Name: "t", Type: &schema.DataRef{Name: "T"}}, + }, + }, + &schema.Data{ + Name: "TestResponse", + Comments: []string{"Response comments"}, + Fields: []*schema.Field{ + {Name: "int", Type: &schema.Int{}}, + {Name: "float", Type: &schema.Float{}}, + {Name: "string", Type: &schema.String{}}, + {Name: "bytes", Type: &schema.Bytes{}}, + {Name: "bool", Type: &schema.Bool{}}, + {Name: "time", Type: &schema.Time{}}, + {Name: "optional", Type: &schema.Optional{ + Type: &schema.String{}, + }}, + {Name: "array", Type: &schema.Array{ + Element: &schema.String{}, + }}, + {Name: "nestedArray", Type: &schema.Array{ + Element: &schema.Array{Element: &schema.String{}}}, + }, + {Name: "dataRefArray", Type: &schema.Array{ + Element: &schema.DataRef{Name: "TestRequest", Module: "test"}, + }}, + {Name: "map", Type: &schema.Map{ + Key: &schema.String{}, + Value: &schema.Int{}, + }}, + {Name: "nestedMap", Type: &schema.Map{ + Key: &schema.String{}, + Value: &schema.Map{Key: &schema.String{}, Value: &schema.Int{}}, + }}, + {Name: "dataRef", Type: &schema.DataRef{Name: "TestRequest"}}, + {Name: "externalDataRef", Type: &schema.DataRef{Name: "TestRequest", Module: "other"}}, + {Name: "any", Type: &schema.Any{}}, + {Name: "parameterizedDataRef", Type: &schema.DataRef{ + Name: "ParamTestData", + TypeParameters: []schema.Type{&schema.DataRef{Name: "T"}}, + }, + }, + {Name: "withAlias", Type: &schema.String{}, JSONAlias: "a"}, + {Name: "unit", Type: &schema.Unit{}}, + }, + }, + }, + }, + }, + } + + expected := `// Code generated by FTL. DO NOT EDIT. +/** + * Module comments + */ +package ftl.test + +import ftl.other.TestRequest +import ftl.test.TestRequest +import java.time.OffsetDateTime + +data class ParamTestData( + val t: T, +) + +/** + * Response comments + */ +data class TestResponse( + val int: Long, + val float: Float, + val string: String, + val bytes: ByteArray, + val bool: Boolean, + val time: OffsetDateTime, + val optional: String? = null, + val array: List, + val nestedArray: List>, + val dataRefArray: List, + val map: Map, + val nestedMap: Map>, + val dataRef: TestRequest, + val externalDataRef: TestRequest, + val any: Any, + val parameterizedDataRef: ParamTestData, + val withAlias: String, + val unit: Unit, +) + +` + assertExpectedSchema(t, sch, "test/Test.kt", expected) +} + +func TestGenerateAllVerbs(t *testing.T) { + sch := &schema.Schema{ + Modules: []*schema.Module{ + { + Name: "test", + Comments: []string{"Module comments"}, + Decls: []schema.Decl{ + &schema.Data{ + Name: "Request", + Fields: []*schema.Field{ + {Name: "data", Type: &schema.Int{}}, + }, + }, + &schema.Verb{ + Name: "TestVerb", + Comments: []string{"TestVerb comments"}, + Request: &schema.DataRef{Name: "Request"}, + Response: &schema.DataRef{Name: "Empty", Module: "builtin"}, + }, + }, + }, + }, + } + + expected := `// Code generated by FTL. DO NOT EDIT. +/** + * Module comments + */ +package ftl.test + +import ftl.builtin.Empty +import xyz.block.ftl.Context +import xyz.block.ftl.Ignore +import xyz.block.ftl.Verb + +data class Request( + val data: Long, +) + +/** + * TestVerb comments + */ +@Verb +@Ignore +fun testVerb(context: Context, req: Request): Empty = throw + NotImplementedError("Verb stubs should not be called directly, instead use context.call(::testVerb, ...)") +` + assertExpectedSchema(t, sch, "test/Test.kt", expected) +} + +func TestGenerateBuiltins(t *testing.T) { + sch := &schema.Schema{ + Modules: []*schema.Module{ + schema.Builtins(), + }, + } + expected := `// Code generated by FTL. DO NOT EDIT. +/** + * Built-in types for FTL. + */ +package ftl.builtin + +/** + * HTTP request structure used for HTTP ingress verbs. + */ +data class HttpRequest( + val method: String, + val path: String, + val pathParameters: Map, + val query: Map>, + val headers: Map>, + val body: Body, +) + +/** + * HTTP response structure used for HTTP ingress verbs. + */ +data class HttpResponse( + val status: Long, + val headers: Map>, + val body: Body? = null, + val error: Error? = null, +) + +class Empty +` + assertExpectedSchema(t, sch, "builtin/Builtin.kt", expected) +} + +func TestGenerateEmptyDataRefs(t *testing.T) { + sch := &schema.Schema{ + Modules: []*schema.Module{ + { + Name: "test", + Decls: []schema.Decl{ + &schema.Data{Name: "EmptyRequest"}, + &schema.Data{Name: "EmptyResponse"}, + &schema.Verb{ + Name: "EmptyVerb", + Request: &schema.DataRef{Name: "EmptyRequest"}, + Response: &schema.DataRef{Name: "EmptyResponse"}, + }, + }, + }, + }, + } + + expected := `// Code generated by FTL. DO NOT EDIT. +package ftl.test + +import ftl.builtin.Empty +import xyz.block.ftl.Context +import xyz.block.ftl.Ignore +import xyz.block.ftl.Verb + +@Verb +@Ignore +fun emptyVerb(context: Context, req: Empty): Empty = throw + NotImplementedError("Verb stubs should not be called directly, instead use context.call(::emptyVerb, ...)") +` + assertExpectedSchema(t, sch, "test/Test.kt", expected) +} + +func assertExpectedSchema(t *testing.T, sch *schema.Schema, outputPath string, expectedContent string) { + t.Helper() + ctx := log.ContextWithLogger(context.Background(), log.Configure(os.Stderr, log.Config{})) + module, err := LoadModule(ctx, "testdata/modules/echokotlin") + assert.NoError(t, err) + + err = generateExternalModules(ctx, module, sch) + assert.NoError(t, err) + + target := filepath.Join("testdata/modules/echokotlin", "target") + output := filepath.Join(target, "generated-sources", "ftl", outputPath) + + fileContent, err := os.ReadFile(output) + assert.NoError(t, err) + assert.Equal(t, expectedContent, string(fileContent)) + + err = os.RemoveAll(target) + assert.NoError(t, err, "Error removing target directory") +} diff --git a/buildengine/discover_test.go b/buildengine/discover_test.go index 55c2aedbee..77af400c35 100644 --- a/buildengine/discover_test.go +++ b/buildengine/discover_test.go @@ -35,6 +35,26 @@ func TestDiscoverModules(t *testing.T) { Schema: "schema.pb", Watch: []string{"**/*.go", "go.mod", "go.sum"}, }, + { + Dir: "testdata/modules/echokotlin", + Language: "kotlin", + Realm: "home", + Module: "echo", + Build: "mvn -B compile", + Deploy: []string{ + "main", + "classes", + "dependency", + "classpath.txt", + }, + DeployDir: "target", + Schema: "schema.pb", + Watch: []string{ + "pom.xml", + "src/**", + "target/generated-sources", + }, + }, { Dir: "testdata/modules/other", Language: "go", diff --git a/buildengine/testdata/modules/echokotlin/ftl.toml b/buildengine/testdata/modules/echokotlin/ftl.toml new file mode 100644 index 0000000000..700b9d8833 --- /dev/null +++ b/buildengine/testdata/modules/echokotlin/ftl.toml @@ -0,0 +1,2 @@ +module = "echo" +language = "kotlin" diff --git a/buildengine/testdata/modules/echokotlin/src/main/kotlin/ftl/echo/Echo.kt b/buildengine/testdata/modules/echokotlin/src/main/kotlin/ftl/echo/Echo.kt new file mode 100644 index 0000000000..aa3fc31de5 --- /dev/null +++ b/buildengine/testdata/modules/echokotlin/src/main/kotlin/ftl/echo/Echo.kt @@ -0,0 +1,14 @@ +package ftl.echo2 + +import ftl.test.TestResponse +import xyz.block.ftl.Context +import xyz.block.ftl.Method +import xyz.block.ftl.Verb + +data class EchoRequest(val name: String? = "anonymous") +data class EchoResponse(val message: String) + +@Verb +fun echo(context: Context, req: EchoRequest): EchoResponse { + return EchoResponse(message = "Hello, ${req.name}!") +} diff --git a/examples/kotlin/ftl-module-echo/pom.xml b/examples/kotlin/ftl-module-echo/pom.xml index dbcaf401c0..d107548c27 100644 --- a/examples/kotlin/ftl-module-echo/pom.xml +++ b/examples/kotlin/ftl-module-echo/pom.xml @@ -26,11 +26,6 @@ org.apache.maven.plugins maven-dependency-plugin - - - org.codehaus.mojo - exec-maven-plugin - org.codehaus.mojo diff --git a/examples/kotlin/ftl-module-time/pom.xml b/examples/kotlin/ftl-module-time/pom.xml index 612c71a6ee..05d4e2356d 100644 --- a/examples/kotlin/ftl-module-time/pom.xml +++ b/examples/kotlin/ftl-module-time/pom.xml @@ -26,11 +26,6 @@ org.apache.maven.plugins maven-dependency-plugin - - - org.codehaus.mojo - exec-maven-plugin - org.codehaus.mojo diff --git a/examples/kotlin/pom.xml b/examples/kotlin/pom.xml index 89d5473b2a..812e162f79 100644 --- a/examples/kotlin/pom.xml +++ b/examples/kotlin/pom.xml @@ -78,23 +78,6 @@ maven-dependency-plugin 3.2.0 - - - initialize - - copy - - - - - xyz.block - ftl-generator - ${ftl.version} - ftl-generator.jar - - - - copy-dependencies diff --git a/kotlin-runtime/devel.go b/kotlin-runtime/devel.go index 59b817dabb..2692073383 100644 --- a/kotlin-runtime/devel.go +++ b/kotlin-runtime/devel.go @@ -10,3 +10,8 @@ import ( // Files is the FTL Kotlin runtime scaffolding files. func Files() *zip.Reader { return internal.ZipRelativeToCaller("scaffolding") } + +// ExternalModuleTemplates are templates for scaffolding external modules in the FTL Kotlin runtime. +func ExternalModuleTemplates() *zip.Reader { + return internal.ZipRelativeToCaller("external-module-template") +} diff --git a/kotlin-runtime/external-module-template/target.tmpl/generated-sources/ftl/{{ range .ExternalModules }}{{ push .Name . }}{{ end }}/{{ .Name | camel }}.kt b/kotlin-runtime/external-module-template/target.tmpl/generated-sources/ftl/{{ range .ExternalModules }}{{ push .Name . }}{{ end }}/{{ .Name | camel }}.kt new file mode 100644 index 0000000000..b06012e27c --- /dev/null +++ b/kotlin-runtime/external-module-template/target.tmpl/generated-sources/ftl/{{ range .ExternalModules }}{{ push .Name . }}{{ end }}/{{ .Name | camel }}.kt @@ -0,0 +1,34 @@ +{{- $moduleName := .Name -}} +// Code generated by FTL. DO NOT EDIT. +{{.Comments|comment -}} +package ftl.{{.Name}} +{{- $imports := (.|imports) -}} +{{- if $imports}} +{{range $import := $imports}} +import {{$import}} +{{- end}}{{end}} +{{range .Decls}} +{{- if is "Data" . -}} +{{- if and (eq $moduleName "builtin") (eq .Name "Empty")}} +{{.Comments|comment -}} +class Empty +{{- else if .Fields}} +{{.Comments|comment -}} +data class {{.Name|title}} +{{- if .TypeParameters}}< +{{- range $i, $tp := .TypeParameters}} +{{- if $i}}, {{end}}{{$tp}} +{{- end -}} +>{{- end}}( + {{- range .Fields}} + val {{.Name}}: {{type $ .Type}}, + {{- end}} +) +{{end}} +{{- else if is "Verb" . }} +{{.Comments|comment -}}@Verb +@Ignore +fun {{.Name|lowerCamel}}(context: Context, req: {{type $ .Request}}): {{type $ .Response}} = throw + NotImplementedError("Verb stubs should not be called directly, instead use context.call(::{{.Name|lowerCamel}}, ...)") +{{- end}} +{{- end}} diff --git a/kotlin-runtime/ftl-runtime/src/main/kotlin/xyz/block/ftl/schemaextractor/ExtractSchemaRule.kt b/kotlin-runtime/ftl-runtime/src/main/kotlin/xyz/block/ftl/schemaextractor/ExtractSchemaRule.kt index 090252797d..9a5a2f3dd0 100644 --- a/kotlin-runtime/ftl-runtime/src/main/kotlin/xyz/block/ftl/schemaextractor/ExtractSchemaRule.kt +++ b/kotlin-runtime/ftl-runtime/src/main/kotlin/xyz/block/ftl/schemaextractor/ExtractSchemaRule.kt @@ -472,6 +472,7 @@ class SchemaExtractor( type.anySuperTypeConstructor { it.getClassFqNameUnsafe().asString() == ByteArray::class.qualifiedName } -> Type(bytes = xyz.block.ftl.v1.schema.Bytes()) + type.anySuperTypeConstructor { it.getClassFqNameUnsafe().asString() == builtIns.list.fqNameSafe.asString() } -> Type( @@ -558,7 +559,15 @@ class SchemaExtractor( } private fun KtDeclaration.comments(): List { - return this.docComment?.text?.trim()?.let { listOf(it) } ?: emptyList() + return this.docComment?.text?.trim()?.let { text -> + text.removePrefix("/*") + .removeSuffix("*/") + .lines() + .map { it.trim().removePrefix("*").trim() } + .filter { it.isNotEmpty() } + .toList() + .ifEmpty { emptyList() } + } ?: emptyList() } private fun KotlinType.isEmptyBuiltin(): Boolean { diff --git a/kotlin-runtime/ftl-runtime/src/test/kotlin/xyz/block/ftl/schemaextractor/ExtractSchemaRuleTest.kt b/kotlin-runtime/ftl-runtime/src/test/kotlin/xyz/block/ftl/schemaextractor/ExtractSchemaRuleTest.kt index afd271c7d6..29810f9740 100644 --- a/kotlin-runtime/ftl-runtime/src/test/kotlin/xyz/block/ftl/schemaextractor/ExtractSchemaRuleTest.kt +++ b/kotlin-runtime/ftl-runtime/src/test/kotlin/xyz/block/ftl/schemaextractor/ExtractSchemaRuleTest.kt @@ -157,9 +157,7 @@ internal class ExtractSchemaRuleTest(private val env: KotlinCoreEnvironment) { ) ), comments = listOf( - """/** - * Request to echo a message. - */""" + """Request to echo a message.""" ), typeParameters = listOf( TypeParameter(name = "T") @@ -190,9 +188,7 @@ internal class ExtractSchemaRuleTest(private val env: KotlinCoreEnvironment) { verb = Verb( name = "echo", comments = listOf( - """/** - * Echoes the given message. - */""" + """Echoes the given message.""" ), request = Type( dataRef = DataRef( diff --git a/kotlin-runtime/release.go b/kotlin-runtime/release.go index 5c61dbefe1..7b98612768 100644 --- a/kotlin-runtime/release.go +++ b/kotlin-runtime/release.go @@ -11,6 +11,9 @@ import ( //go:embed scaffolding.zip var archive []byte +//go:embed external-module-template.zip +var externalModuleTemplate []byte + // Files is the FTL Kotlin runtime scaffolding files. // // scaffolding.zip can be generated by running `bit kotlin-runtime/scaffolding.zip` @@ -22,3 +25,15 @@ func Files() *zip.Reader { } return zr } + +// ExternalModuleTemplates are templates for scaffolding external modules in the FTL Kotlin runtime. +// +// external-module-template.zip can be generated by running `bit kotlin-runtime/external-module-template.zip` +// or indirectly via `bit build/release/ftl`. +func ExternalModuleTemplates() *zip.Reader { + zr, err := zip.NewReader(bytes.NewReader(externalModuleTemplate), int64(len(externalModuleTemplate))) + if err != nil { + panic(err) + } + return zr +} diff --git a/kotlin-runtime/scaffolding/ftl-module-{{ .Name | lower }}/pom.xml b/kotlin-runtime/scaffolding/ftl-module-{{ .Name | lower }}/pom.xml index 5b6c7cafee..2ca07efa39 100644 --- a/kotlin-runtime/scaffolding/ftl-module-{{ .Name | lower }}/pom.xml +++ b/kotlin-runtime/scaffolding/ftl-module-{{ .Name | lower }}/pom.xml @@ -26,11 +26,6 @@ org.apache.maven.plugins maven-dependency-plugin - - - org.codehaus.mojo - exec-maven-plugin - org.codehaus.mojo diff --git a/kotlin-runtime/scaffolding/pom.xml b/kotlin-runtime/scaffolding/pom.xml index f90a62a542..b06a86d9c1 100644 --- a/kotlin-runtime/scaffolding/pom.xml +++ b/kotlin-runtime/scaffolding/pom.xml @@ -79,23 +79,6 @@ maven-dependency-plugin 3.6.1 - - - initialize - - copy - - - - - xyz.block - ftl-generator - ${ftl.version} - ftl-generator.jar - - - - copy-dependencies @@ -133,31 +116,6 @@ - - - org.codehaus.mojo - exec-maven-plugin - 3.2.0 - - - initialize - - exec - - - java - - -jar - target/dependency/ftl-generator.jar - --endpoint=${ftlEndpoint} - --dest=${project.build.directory} - --module=${ftlModuleName} - --module-client-suffix=ModuleClient - - - - - org.codehaus.mojo