7
7
"path"
8
8
"path/filepath"
9
9
stdreflect "reflect"
10
+ "regexp"
10
11
"runtime"
11
12
"slices"
12
13
"strconv"
@@ -39,8 +40,14 @@ import (
39
40
"github.com/block/ftl/internal/watch"
40
41
)
41
42
42
- var ftlTypesFilename = "types.ftl.go"
43
- var ftlQueriesFilename = "queries.ftl.go"
43
+ var (
44
+ ftlTypesFilename = "types.ftl.go"
45
+ ftlQueriesFilename = "queries.ftl.go"
46
+ // Searches for paths beginning with ../../../
47
+ // Matches the previous character as well to avoid matching the middle deeper backtrack paths, and because
48
+ // regex package does not support negative lookbehind assertions
49
+ pathFromMainToModuleRegex = regexp .MustCompile (`(^|[^/])\.\./\.\./\.\./` )
50
+ )
44
51
45
52
type MainWorkContext struct {
46
53
GoVersion string
@@ -634,16 +641,27 @@ func compile(ctx context.Context, mainDir string, buildEnv []string, devMode boo
634
641
buildEnv = slices .Clone (buildEnv )
635
642
buildEnv = append (buildEnv , "GODEBUG=http2client=0" )
636
643
err := exec .CommandWithEnv (ctx , log .Debug , mainDir , buildEnv , "go" , args ... ).RunStderrError (ctx )
637
- if err = = nil {
638
- return nil
644
+ if err ! = nil {
645
+ return buildErrsFromCompilerErr ( err . Error ())
639
646
}
647
+ return nil
648
+ }
649
+
650
+ // buildErrsFromCompilerErr converts a compiler error to a list of builderrors by trying to parse
651
+ // the error text and extract multiple errors with file, line and column information
652
+ func buildErrsFromCompilerErr (input string ) []builderrors.Error {
640
653
errs := []builderrors.Error {}
641
- lines := strings .Split (err . Error () , "\n " )
642
- for i := 1 ; i < len (lines ); {
643
- if strings .HasPrefix (lines [i ], "\t " ) {
654
+ lines := strings .Split (input , "\n " )
655
+ for i := 0 ; i < len (lines ); {
656
+ if i > 0 && strings .HasPrefix (lines [i ], "\t " ) {
644
657
lines [i - 1 ] = lines [i - 1 ] + ": " + strings .TrimSpace (lines [i ])
645
658
lines = append (lines [:i ], lines [i + 1 :]... )
646
659
} else {
660
+ lines [i ] = strings .TrimSpace (lines [i ])
661
+ if len (lines [i ]) == 0 {
662
+ lines = append (lines [:i ], lines [i + 1 :]... )
663
+ continue
664
+ }
647
665
i ++
648
666
}
649
667
}
@@ -652,7 +670,8 @@ func compile(ctx context.Context, mainDir string, buildEnv []string, devMode boo
652
670
continue
653
671
}
654
672
// ../../../example.go:11:59: undefined: lorem ipsum
655
- components := strings .SplitN (line , ":" , 4 )
673
+ line = pathFromMainToModuleRegex .ReplaceAllString (line , "$1" )
674
+ components := islices .Map (strings .SplitN (line , ":" , 4 ), strings .TrimSpace )
656
675
if len (components ) != 4 {
657
676
errs = append (errs , builderrors.Error {
658
677
Type : builderrors .COMPILER ,
@@ -661,7 +680,8 @@ func compile(ctx context.Context, mainDir string, buildEnv []string, devMode boo
661
680
})
662
681
continue
663
682
}
664
- path , _ := strings .CutPrefix (components [0 ], "../../../" )
683
+
684
+ path := components [0 ]
665
685
hasPos := true
666
686
line , err := strconv .Atoi (components [1 ])
667
687
if err != nil {
0 commit comments