generated from TBD54566975/tbd-project-template
-
Notifications
You must be signed in to change notification settings - Fork 7
/
build.go
96 lines (80 loc) · 2.75 KB
/
build.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package buildengine
import (
"context"
"fmt"
"os"
"path/filepath"
"time"
"google.golang.org/protobuf/proto"
schemapb "github.com/TBD54566975/ftl/backend/protos/xyz/block/ftl/v1/schema"
"github.com/TBD54566975/ftl/backend/schema"
"github.com/TBD54566975/ftl/common/moduleconfig"
"github.com/TBD54566975/ftl/internal/errors"
"github.com/TBD54566975/ftl/internal/flock"
"github.com/TBD54566975/ftl/internal/log"
)
const BuildLockTimeout = time.Minute
// 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, projectRootDir string, sch *schema.Schema, module Module, filesTransaction ModifyFilesTransaction) error {
return buildModule(ctx, projectRootDir, sch, module, filesTransaction)
}
func buildModule(ctx context.Context, projectRootDir string, sch *schema.Schema, module Module, filesTransaction ModifyFilesTransaction) error {
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.Config.Module)
ctx = log.ContextWithLogger(ctx, logger)
// clear the deploy directory before extracting schema
if err := os.RemoveAll(module.Config.Abs().DeployDir); err != nil {
return fmt.Errorf("failed to clear errors: %w", err)
}
logger.Infof("Building module")
startTime := time.Now()
switch module.Config.Language {
case "go":
err = buildGoModule(ctx, projectRootDir, sch, module, filesTransaction)
case "kotlin":
err = buildKotlinModule(ctx, sch, module)
case "rust":
err = buildRustModule(ctx, sch, module)
default:
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.Config.Abs())
if err != nil {
return fmt.Errorf("failed to read build errors for module: %w", err)
}
schema.SortErrorsByPosition(errorList.Errors)
for _, e := range errorList.Errors {
errs = append(errs, e)
}
if len(errs) > 0 {
return errors.Join(errs...)
}
logger.Infof("Module built (%.2fs)", time.Since(startTime).Seconds())
return nil
}
func loadProtoErrors(config moduleconfig.AbsModuleConfig) (*schema.ErrorList, error) {
if _, err := os.Stat(config.Errors); errors.Is(err, os.ErrNotExist) {
return &schema.ErrorList{Errors: make([]*schema.Error, 0)}, nil
}
content, err := os.ReadFile(config.Errors)
if err != nil {
return nil, err
}
errorspb := &schemapb.ErrorList{}
err = proto.Unmarshal(content, errorspb)
if err != nil {
return nil, err
}
return schema.ErrorListFromProto(errorspb), nil
}