Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: remove unused external libs and buildengine.project #1820

Merged
merged 1 commit into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 11 additions & 48 deletions buildengine/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"time"

"google.golang.org/protobuf/proto"
Expand All @@ -16,57 +15,47 @@ import (
"github.com/TBD54566975/ftl/internal/errors"
"github.com/TBD54566975/ftl/internal/flock"
"github.com/TBD54566975/ftl/internal/log"
"github.com/TBD54566975/ftl/internal/slices"
)

const BuildLockTimeout = time.Minute

// Build a project in the given directory given the schema and project config.
//
// For a module, this will build the module. For an external library, this will build stubs for imported modules.
// Build a module in the given directory given the schema and module config.
//
// A lock file is used to ensure that only one build is running at a time.
func Build(ctx context.Context, sch *schema.Schema, project Project, filesTransaction ModifyFilesTransaction) error {
switch project := project.(type) {
case Module:
return buildModule(ctx, sch, project, filesTransaction)
case ExternalLibrary:
return buildExternalLibrary(ctx, sch, project)
default:
panic(fmt.Sprintf("unsupported project type: %T", project))
}
func Build(ctx context.Context, sch *schema.Schema, module Module, filesTransaction ModifyFilesTransaction) error {
return buildModule(ctx, sch, module, filesTransaction)
}

func buildModule(ctx context.Context, sch *schema.Schema, module Module, filesTransaction ModifyFilesTransaction) error {
release, err := flock.Acquire(ctx, filepath.Join(module.Dir, ".ftl.lock"), BuildLockTimeout)
release, err := flock.Acquire(ctx, filepath.Join(module.Config.Dir, ".ftl.lock"), BuildLockTimeout)
if err != nil {
return err
}
defer release() //nolint:errcheck
logger := log.FromContext(ctx).Scope(module.Module)
logger := log.FromContext(ctx).Scope(module.Config.Module)
ctx = log.ContextWithLogger(ctx, logger)

// clear the deploy directory before extracting schema
if err := os.RemoveAll(module.AbsDeployDir()); err != nil {
if err := os.RemoveAll(module.Config.AbsDeployDir()); err != nil {
return fmt.Errorf("failed to clear errors: %w", err)
}

logger.Infof("Building module")
switch module.Language {
switch module.Config.Language {
case "go":
err = buildGoModule(ctx, sch, module, filesTransaction)
case "kotlin":
err = buildKotlinModule(ctx, sch, module)
default:
return fmt.Errorf("unknown language %q", module.Language)
return fmt.Errorf("unknown language %q", module.Config.Language)
}

var errs []error
if err != nil {
errs = append(errs, err)
}
// read runtime-specific build errors from the build directory
errorList, err := loadProtoErrors(module.ModuleConfig)
errorList, err := loadProtoErrors(module.Config)
if err != nil {
return fmt.Errorf("failed to read build errors for module: %w", err)
}
Expand All @@ -82,34 +71,8 @@ func buildModule(ctx context.Context, sch *schema.Schema, module Module, filesTr
return nil
}

func buildExternalLibrary(ctx context.Context, sch *schema.Schema, lib ExternalLibrary) error {
logger := log.FromContext(ctx).Scope(filepath.Base(lib.Dir))
ctx = log.ContextWithLogger(ctx, logger)

imported := slices.Map(sch.Modules, func(m *schema.Module) string {
return m.Name
})
logger.Debugf("Generating stubs [%s] for %v", strings.Join(imported, ", "), lib)

switch lib.Language {
case "go":
if err := buildGoLibrary(ctx, sch, lib); err != nil {
return err
}
case "kotlin":
if err := buildKotlinLibrary(ctx, sch, lib); err != nil {
return err
}
default:
return fmt.Errorf("unknown language %q for library %q", lib.Language, lib.Config().Key)
}

logger.Infof("Generated stubs [%s] for %v", strings.Join(imported, ", "), lib)
return nil
}

func loadProtoErrors(module moduleconfig.ModuleConfig) (*schema.ErrorList, error) {
f := filepath.Join(module.AbsDeployDir(), module.Errors)
func loadProtoErrors(config moduleconfig.ModuleConfig) (*schema.ErrorList, error) {
f := filepath.Join(config.AbsDeployDir(), config.Errors)
if _, err := os.Stat(f); errors.Is(err, os.ErrNotExist) {
return &schema.ErrorList{Errors: make([]*schema.Error, 0)}, nil
}
Expand Down
11 changes: 2 additions & 9 deletions buildengine/build_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,8 @@ import (
)

func buildGoModule(ctx context.Context, sch *schema.Schema, module Module, transaction ModifyFilesTransaction) error {
if err := compile.Build(ctx, module.Dir, sch, transaction); err != nil {
return fmt.Errorf("failed to build module %q: %w", module.Config().Key, err)
}
return nil
}

func buildGoLibrary(ctx context.Context, sch *schema.Schema, lib ExternalLibrary) error {
if err := compile.GenerateStubsForExternalLibrary(ctx, lib.Dir, sch); err != nil {
return fmt.Errorf("failed to generate stubs for library %q: %w", lib.Config().Key, err)
if err := compile.Build(ctx, module.Config.Dir, sch, transaction); err != nil {
return fmt.Errorf("failed to build module %q: %w", module.Config.Module, err)
}
return nil
}
12 changes: 6 additions & 6 deletions buildengine/build_go_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func init() {
}
`
bctx := buildContext{
moduleDir: "testdata/projects/another",
moduleDir: "testdata/another",
buildDir: "_ftl",
sch: sch,
}
Expand All @@ -197,7 +197,7 @@ func TestGoBuildClearsBuildDir(t *testing.T) {
},
}
bctx := buildContext{
moduleDir: "testdata/projects/another",
moduleDir: "testdata/another",
buildDir: "_ftl",
sch: sch,
}
Expand Down Expand Up @@ -255,7 +255,7 @@ func Call(context.Context, Req) (Resp, error) {
}
`
bctx := buildContext{
moduleDir: "testdata/projects/another",
moduleDir: "testdata/another",
buildDir: "_ftl",
sch: sch,
}
Expand All @@ -269,7 +269,7 @@ func TestExternalType(t *testing.T) {
t.SkipNow()
}
bctx := buildContext{
moduleDir: "testdata/projects/external",
moduleDir: "testdata/external",
buildDir: "_ftl",
sch: &schema.Schema{},
}
Expand Down Expand Up @@ -301,7 +301,7 @@ func TestGoModVersion(t *testing.T) {
},
}
bctx := buildContext{
moduleDir: "testdata/projects/highgoversion",
moduleDir: "testdata/highgoversion",
buildDir: "_ftl",
sch: sch,
}
Expand Down Expand Up @@ -344,7 +344,7 @@ func TestGeneratedTypeRegistry(t *testing.T) {
expected, err := os.ReadFile("testdata/type_registry_main.go")
assert.NoError(t, err)
bctx := buildContext{
moduleDir: "testdata/projects/other",
moduleDir: "testdata/other",
buildDir: "_ftl",
sch: sch,
}
Expand Down
48 changes: 18 additions & 30 deletions buildengine/build_kotlin.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,14 @@ import (
)

type externalModuleContext struct {
project Project
module Module
*schema.Schema
}

func (e externalModuleContext) ExternalModules() []*schema.Module {
name := ""
if module, ok := e.project.(Module); ok {
name = module.Module
}
modules := make([]*schema.Module, 0, len(e.Modules))
for _, module := range e.Modules {
if module.Name == name {
if module.Name == e.module.Config.Module {
continue
}
modules = append(modules, module)
Expand All @@ -44,34 +40,27 @@ func (e externalModuleContext) ExternalModules() []*schema.Module {

func buildKotlinModule(ctx context.Context, sch *schema.Schema, module Module) error {
logger := log.FromContext(ctx)
if err := SetPOMProperties(ctx, module.Dir); err != nil {
return fmt.Errorf("unable to update ftl.version in %s: %w", module.Dir, err)
if err := SetPOMProperties(ctx, module.Config.Dir); err != nil {
return fmt.Errorf("unable to update ftl.version in %s: %w", module.Config.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 := generateExternalModules(ctx, module, sch); err != nil {
return fmt.Errorf("unable to generate external modules for %s: %w", module.Config.Module, err)
}

if err := prepareFTLRoot(module); err != nil {
return fmt.Errorf("unable to prepare FTL root for %s: %w", module.Module, err)
return fmt.Errorf("unable to prepare FTL root for %s: %w", module.Config.Module, err)
}

logger.Debugf("Using build command '%s'", module.Build)
err := exec.Command(ctx, log.Debug, module.Dir, "bash", "-c", module.Build).RunBuffered(ctx)
logger.Debugf("Using build command '%s'", module.Config.Build)
err := exec.Command(ctx, log.Debug, module.Config.Dir, "bash", "-c", module.Config.Build).RunBuffered(ctx)
if err != nil {
return fmt.Errorf("failed to build module %q: %w", module.Module, err)
return fmt.Errorf("failed to build module %q: %w", module.Config.Module, err)
}

return nil
}

func buildKotlinLibrary(ctx context.Context, sch *schema.Schema, lib ExternalLibrary) error {
if err := generateExternalModules(ctx, &lib, sch); err != nil {
return fmt.Errorf("unable to generate external modules for %q: %w", lib.Config().Key, err)
}
return nil
}

// SetPOMProperties updates the ftl.version properties in the
// pom.xml file in the given base directory.
func SetPOMProperties(ctx context.Context, baseDir string) error {
Expand Down Expand Up @@ -104,7 +93,7 @@ func SetPOMProperties(ctx context.Context, baseDir string) error {
}

func prepareFTLRoot(module Module) error {
buildDir := module.AbsDeployDir()
buildDir := module.Config.AbsDeployDir()
if err := os.MkdirAll(buildDir, 0700); err != nil {
return err
}
Expand All @@ -118,7 +107,7 @@ SchemaExtractorRuleSet:

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)
return fmt.Errorf("unable to configure detekt for %s: %w", module.Config.Module, err)
}

mainFilePath := filepath.Join(buildDir, "main")
Expand All @@ -127,23 +116,22 @@ SchemaExtractorRuleSet:
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 fmt.Errorf("unable to configure main executable for %s: %w", module.Config.Module, err)
}
return nil
}

func generateExternalModules(ctx context.Context, project Project, sch *schema.Schema) error {
func generateExternalModules(ctx context.Context, module Module, sch *schema.Schema) error {
logger := log.FromContext(ctx)
funcs := maps.Clone(scaffoldFuncs)
config := project.Config()

// Wipe the modules directory to ensure we don't have any stale modules.
_ = os.RemoveAll(filepath.Join(config.Dir, "target", "generated-sources", "ftl"))
_ = os.RemoveAll(filepath.Join(module.Config.Dir, "target", "generated-sources", "ftl"))

logger.Debugf("Generating external modules")
return internal.ScaffoldZip(kotlinruntime.ExternalModuleTemplates(), config.Dir, externalModuleContext{
project: project,
Schema: sch,
return internal.ScaffoldZip(kotlinruntime.ExternalModuleTemplates(), module.Config.Dir, externalModuleContext{
module: module,
Schema: sch,
}, scaffolder.Exclude("^go.mod$"), scaffolder.Functions(funcs))
}

Expand Down
16 changes: 8 additions & 8 deletions buildengine/build_kotlin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ package ftl.test

`
bctx := buildContext{
moduleDir: "testdata/projects/echokotlin",
moduleDir: "testdata/echokotlin",
buildDir: "target",
sch: sch,
}
Expand All @@ -40,7 +40,7 @@ func TestKotlinBuildClearsBuildDir(t *testing.T) {
},
}
bctx := buildContext{
moduleDir: "testdata/projects/echokotlin",
moduleDir: "testdata/echokotlin",
buildDir: "target",
sch: sch,
}
Expand Down Expand Up @@ -165,7 +165,7 @@ data class TestResponse(

`
bctx := buildContext{
moduleDir: "testdata/projects/echokotlin",
moduleDir: "testdata/echokotlin",
buildDir: "target",
sch: sch,
}
Expand Down Expand Up @@ -227,7 +227,7 @@ fun testVerb(context: Context, req: Request): ftl.builtin.Empty = throw
NotImplementedError("Verb stubs should not be called directly, instead use context.call(::testVerb, ...)")
`
bctx := buildContext{
moduleDir: "testdata/projects/echokotlin",
moduleDir: "testdata/echokotlin",
buildDir: "target",
sch: sch,
}
Expand Down Expand Up @@ -281,7 +281,7 @@ data class HttpResponse<Body, Error>(
class Empty
`
bctx := buildContext{
moduleDir: "testdata/projects/echokotlin",
moduleDir: "testdata/echokotlin",
buildDir: "target",
sch: sch,
}
Expand Down Expand Up @@ -326,7 +326,7 @@ fun emptyVerb(context: Context, req: ftl.builtin.Empty): ftl.builtin.Empty = thr
NotImplementedError("Verb stubs should not be called directly, instead use context.call(::emptyVerb, ...)")
`
bctx := buildContext{
moduleDir: "testdata/projects/echokotlin",
moduleDir: "testdata/echokotlin",
buildDir: "target",
sch: sch,
}
Expand Down Expand Up @@ -407,7 +407,7 @@ fun nothing(context: Context): Unit = throw
NotImplementedError("Verb stubs should not be called directly, instead use context.callEmpty(::nothing, ...)")
`
bctx := buildContext{
moduleDir: "testdata/projects/echokotlin",
moduleDir: "testdata/echokotlin",
buildDir: "target",
sch: sch,
}
Expand All @@ -421,7 +421,7 @@ func TestKotlinExternalType(t *testing.T) {
t.SkipNow()
}
bctx := buildContext{
moduleDir: "testdata/projects/externalkotlin",
moduleDir: "testdata/externalkotlin",
buildDir: "target",
sch: &schema.Schema{},
}
Expand Down
10 changes: 5 additions & 5 deletions buildengine/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ type DeployClient interface {

// Deploy a module to the FTL controller with the given number of replicas. Optionally wait for the deployment to become ready.
func Deploy(ctx context.Context, module Module, replicas int32, waitForDeployOnline bool, client DeployClient) error {
logger := log.FromContext(ctx).Scope(module.Module)
logger := log.FromContext(ctx).Scope(module.Config.Module)
ctx = log.ContextWithLogger(ctx, logger)
logger.Infof("Deploying module")

deployDir := module.AbsDeployDir()
files, err := findFiles(deployDir, module.Deploy)
deployDir := module.Config.AbsDeployDir()
files, err := findFiles(deployDir, module.Config.Deploy)
if err != nil {
logger.Errorf(err, "failed to find files in %s", deployDir)
return err
Expand All @@ -57,9 +57,9 @@ func Deploy(ctx context.Context, module Module, replicas int32, waitForDeployOnl
return err
}

moduleSchema, err := loadProtoSchema(deployDir, module.ModuleConfig, replicas)
moduleSchema, err := loadProtoSchema(deployDir, module.Config, replicas)
if err != nil {
return fmt.Errorf("failed to load protobuf schema from %q: %w", module.Schema, err)
return fmt.Errorf("failed to load protobuf schema from %q: %w", module.Config.Schema, err)
}

logger.Debugf("Uploading %d/%d files", len(gadResp.Msg.MissingDigests), len(files))
Expand Down
Loading
Loading