goscript 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cmd/goscript/cmd-compile.go +7 -0
- package/cmd/goscript/cmd_compile_test.go +83 -0
- package/compiler/compile-request.go +3 -0
- package/compiler/compiler-cache.go +828 -0
- package/compiler/compiler-cache_test.go +705 -0
- package/compiler/config.go +2 -0
- package/compiler/index.test.ts +26 -1
- package/compiler/index.ts +5 -0
- package/compiler/lowered-program.go +31 -20
- package/compiler/lowering.go +349 -93
- package/compiler/lowering_bench_test.go +1 -0
- package/compiler/override-facts.go +309 -8
- package/compiler/override-parity-verifier.go +45 -1
- package/compiler/override-parity-verifier_test.go +100 -0
- package/compiler/override-registry_test.go +1 -0
- package/compiler/package-graph.go +40 -12
- package/compiler/package-graph_test.go +29 -0
- package/compiler/runtime-contract.go +8 -0
- package/compiler/service.go +98 -11
- package/compiler/skeleton_test.go +110 -14
- package/compiler/typescript-emitter.go +120 -23
- package/dist/compiler/index.d.ts +2 -0
- package/dist/compiler/index.js +3 -0
- package/dist/compiler/index.js.map +1 -1
- package/dist/gs/builtin/builtin.d.ts +24 -33
- package/dist/gs/builtin/builtin.js +54 -61
- package/dist/gs/builtin/builtin.js.map +1 -1
- package/dist/gs/builtin/hostio.d.ts +1 -0
- package/dist/gs/builtin/hostio.js +1 -1
- package/dist/gs/builtin/hostio.js.map +1 -1
- package/dist/gs/builtin/index.d.ts +1 -0
- package/dist/gs/builtin/index.js +1 -0
- package/dist/gs/builtin/index.js.map +1 -1
- package/dist/gs/builtin/panic.d.ts +18 -0
- package/dist/gs/builtin/panic.js +98 -0
- package/dist/gs/builtin/panic.js.map +1 -0
- package/dist/gs/builtin/slice.d.ts +10 -0
- package/dist/gs/builtin/slice.js +110 -53
- package/dist/gs/builtin/slice.js.map +1 -1
- package/dist/gs/builtin/type.js +15 -3
- package/dist/gs/builtin/type.js.map +1 -1
- package/dist/gs/builtin/varRef.d.ts +1 -1
- package/dist/gs/builtin/varRef.js +3 -2
- package/dist/gs/builtin/varRef.js.map +1 -1
- package/dist/gs/bytes/bytes.gs.js +51 -38
- package/dist/gs/bytes/bytes.gs.js.map +1 -1
- package/dist/gs/bytes/reader.gs.d.ts +1 -1
- package/dist/gs/bytes/reader.gs.js +6 -7
- package/dist/gs/bytes/reader.gs.js.map +1 -1
- package/dist/gs/cmp/index.d.ts +1 -1
- package/dist/gs/cmp/index.js +43 -10
- package/dist/gs/cmp/index.js.map +1 -1
- package/dist/gs/context/context.d.ts +2 -2
- package/dist/gs/context/context.js +1 -1
- package/dist/gs/context/context.js.map +1 -1
- package/dist/gs/embed/index.js +1 -1
- package/dist/gs/embed/index.js.map +1 -1
- package/dist/gs/encoding/binary/index.js +201 -8
- package/dist/gs/encoding/binary/index.js.map +1 -1
- package/dist/gs/encoding/json/index.d.ts +5 -0
- package/dist/gs/encoding/json/index.js +388 -25
- package/dist/gs/encoding/json/index.js.map +1 -1
- package/dist/gs/errors/errors.js +17 -24
- package/dist/gs/errors/errors.js.map +1 -1
- package/dist/gs/fmt/fmt.js +129 -35
- package/dist/gs/fmt/fmt.js.map +1 -1
- package/dist/gs/golang.org/x/crypto/cryptobyte/index.js +1 -1
- package/dist/gs/golang.org/x/crypto/cryptobyte/index.js.map +1 -1
- package/dist/gs/internal/bytealg/index.js +43 -8
- package/dist/gs/internal/bytealg/index.js.map +1 -1
- package/dist/gs/internal/byteorder/index.d.ts +2 -2
- package/dist/gs/internal/byteorder/index.js +2 -2
- package/dist/gs/internal/byteorder/index.js.map +1 -1
- package/dist/gs/io/fs/format.js +2 -2
- package/dist/gs/io/fs/format.js.map +1 -1
- package/dist/gs/io/fs/fs.d.ts +1 -1
- package/dist/gs/io/fs/fs.js +1 -1
- package/dist/gs/io/fs/fs.js.map +1 -1
- package/dist/gs/io/io.d.ts +21 -21
- package/dist/gs/io/io.js +49 -50
- package/dist/gs/io/io.js.map +1 -1
- package/dist/gs/math/bits/index.js +26 -8
- package/dist/gs/math/bits/index.js.map +1 -1
- package/dist/gs/math/copysign.gs.js +10 -17
- package/dist/gs/math/copysign.gs.js.map +1 -1
- package/dist/gs/math/pow.gs.js +5 -0
- package/dist/gs/math/pow.gs.js.map +1 -1
- package/dist/gs/math/signbit.gs.js +6 -2
- package/dist/gs/math/signbit.gs.js.map +1 -1
- package/dist/gs/mime/index.js +1 -0
- package/dist/gs/mime/index.js.map +1 -1
- package/dist/gs/net/http/index.d.ts +6 -6
- package/dist/gs/net/http/index.js +507 -43
- package/dist/gs/net/http/index.js.map +1 -1
- package/dist/gs/os/stat.gs.d.ts +2 -2
- package/dist/gs/os/types.gs.d.ts +1 -1
- package/dist/gs/os/types.gs.js +1 -1
- package/dist/gs/os/types.gs.js.map +1 -1
- package/dist/gs/os/types_js.gs.d.ts +1 -1
- package/dist/gs/os/types_js.gs.js +7 -7
- package/dist/gs/os/types_js.gs.js.map +1 -1
- package/dist/gs/os/types_unix.gs.d.ts +1 -1
- package/dist/gs/os/types_unix.gs.js +1 -1
- package/dist/gs/os/types_unix.gs.js.map +1 -1
- package/dist/gs/os/zero_copy_posix.gs.d.ts +1 -1
- package/dist/gs/os/zero_copy_posix.gs.js +1 -1
- package/dist/gs/os/zero_copy_posix.gs.js.map +1 -1
- package/dist/gs/path/filepath/match.js +8 -4
- package/dist/gs/path/filepath/match.js.map +1 -1
- package/dist/gs/path/filepath/path.js +216 -42
- package/dist/gs/path/filepath/path.js.map +1 -1
- package/dist/gs/path/match.js +6 -3
- package/dist/gs/path/match.js.map +1 -1
- package/dist/gs/reflect/type.d.ts +5 -4
- package/dist/gs/reflect/type.js +29 -11
- package/dist/gs/reflect/type.js.map +1 -1
- package/dist/gs/slices/slices.js +11 -11
- package/dist/gs/slices/slices.js.map +1 -1
- package/dist/gs/strconv/atof.gs.js +156 -43
- package/dist/gs/strconv/atof.gs.js.map +1 -1
- package/dist/gs/strconv/atoi.gs.d.ts +3 -2
- package/dist/gs/strconv/atoi.gs.js +86 -67
- package/dist/gs/strconv/atoi.gs.js.map +1 -1
- package/dist/gs/strconv/ftoa.gs.js +73 -3
- package/dist/gs/strconv/ftoa.gs.js.map +1 -1
- package/dist/gs/strconv/itoa.gs.d.ts +4 -4
- package/dist/gs/strconv/itoa.gs.js +5 -4
- package/dist/gs/strconv/itoa.gs.js.map +1 -1
- package/dist/gs/strconv/quote.gs.d.ts +1 -1
- package/dist/gs/strconv/quote.gs.js +311 -103
- package/dist/gs/strconv/quote.gs.js.map +1 -1
- package/dist/gs/strings/reader.d.ts +1 -1
- package/dist/gs/strings/reader.js +8 -8
- package/dist/gs/strings/reader.js.map +1 -1
- package/dist/gs/strings/strings.js +87 -61
- package/dist/gs/strings/strings.js.map +1 -1
- package/dist/gs/sync/atomic/doc_64.gs.d.ts +14 -14
- package/dist/gs/sync/atomic/doc_64.gs.js +10 -10
- package/dist/gs/sync/atomic/doc_64.gs.js.map +1 -1
- package/dist/gs/sync/atomic/type.gs.d.ts +22 -22
- package/dist/gs/sync/atomic/type.gs.js +4 -4
- package/dist/gs/sync/atomic/type.gs.js.map +1 -1
- package/dist/gs/sync/sync.js +50 -12
- package/dist/gs/sync/sync.js.map +1 -1
- package/dist/gs/syscall/fs.d.ts +6 -6
- package/dist/gs/syscall/fs.js +1 -1
- package/dist/gs/syscall/fs.js.map +1 -1
- package/dist/gs/time/time.d.ts +18 -18
- package/dist/gs/time/time.js +58 -55
- package/dist/gs/time/time.js.map +1 -1
- package/dist/gs/unicode/tables.d.ts +11 -0
- package/dist/gs/unicode/tables.js +635 -0
- package/dist/gs/unicode/tables.js.map +1 -0
- package/dist/gs/unicode/unicode.d.ts +58 -38
- package/dist/gs/unicode/unicode.js +362 -278
- package/dist/gs/unicode/unicode.js.map +1 -1
- package/go.sum +13 -0
- package/gs/builtin/builtin.ts +83 -93
- package/gs/builtin/hostio.ts +1 -1
- package/gs/builtin/index.ts +1 -0
- package/gs/builtin/panic.test.ts +189 -0
- package/gs/builtin/panic.ts +107 -0
- package/gs/builtin/runtime-contract.test.ts +5 -5
- package/gs/builtin/slice.test.ts +23 -0
- package/gs/builtin/slice.ts +133 -95
- package/gs/builtin/type.ts +16 -3
- package/gs/builtin/varRef.ts +4 -2
- package/gs/builtin/wide-int.test.ts +41 -0
- package/gs/bytes/bytes.gs.ts +54 -41
- package/gs/bytes/bytes.test.ts +18 -1
- package/gs/bytes/reader.gs.ts +7 -8
- package/gs/cmp/index.test.ts +55 -0
- package/gs/cmp/index.ts +45 -9
- package/gs/context/context.ts +3 -3
- package/gs/embed/index.ts +2 -2
- package/gs/encoding/binary/index.test.ts +104 -0
- package/gs/encoding/binary/index.ts +259 -11
- package/gs/encoding/json/index.test.ts +107 -0
- package/gs/encoding/json/index.ts +400 -29
- package/gs/errors/errors.test.ts +44 -1
- package/gs/errors/errors.ts +15 -31
- package/gs/fmt/fmt.test.ts +70 -2
- package/gs/fmt/fmt.ts +128 -34
- package/gs/golang.org/x/crypto/cryptobyte/index.ts +1 -1
- package/gs/internal/bytealg/index.test.ts +26 -1
- package/gs/internal/bytealg/index.ts +44 -8
- package/gs/internal/byteorder/index.ts +6 -4
- package/gs/io/fs/format.ts +2 -2
- package/gs/io/fs/fs.ts +2 -2
- package/gs/io/fs/stat.test.ts +2 -2
- package/gs/io/fs/sub.test.ts +2 -2
- package/gs/io/fs/walk.test.ts +2 -2
- package/gs/io/io.test.ts +47 -5
- package/gs/io/io.ts +73 -73
- package/gs/io/limit.test.ts +103 -0
- package/gs/math/bits/index.test.ts +128 -0
- package/gs/math/bits/index.ts +26 -8
- package/gs/math/copysign.gs.test.ts +3 -1
- package/gs/math/copysign.gs.ts +10 -22
- package/gs/math/pow.gs.test.ts +4 -5
- package/gs/math/pow.gs.ts +5 -0
- package/gs/math/signbit.gs.test.ts +2 -1
- package/gs/math/signbit.gs.ts +6 -3
- package/gs/mime/index.ts +1 -0
- package/gs/net/http/index.test.ts +683 -2
- package/gs/net/http/index.ts +598 -57
- package/gs/net/http/meta.json +3 -0
- package/gs/os/stat.gs.ts +2 -2
- package/gs/os/types.gs.ts +2 -2
- package/gs/os/types_js.gs.ts +9 -9
- package/gs/os/types_unix.gs.ts +2 -2
- package/gs/os/zero_copy_posix.gs.ts +2 -2
- package/gs/path/filepath/match.test.ts +16 -0
- package/gs/path/filepath/match.ts +8 -4
- package/gs/path/filepath/path.test.ts +91 -9
- package/gs/path/filepath/path.ts +223 -49
- package/gs/path/match.test.ts +32 -0
- package/gs/path/match.ts +6 -3
- package/gs/reflect/deepequal.test.ts +1 -1
- package/gs/reflect/field.test.ts +1 -1
- package/gs/reflect/function-types.test.ts +6 -6
- package/gs/reflect/sliceat.test.ts +13 -13
- package/gs/reflect/structof.test.ts +4 -4
- package/gs/reflect/type.ts +34 -14
- package/gs/reflect/typefor.test.ts +5 -5
- package/gs/runtime/pprof/index.test.ts +20 -0
- package/gs/runtime/trace/index.test.ts +3 -0
- package/gs/slices/slices.test.ts +31 -0
- package/gs/slices/slices.ts +11 -11
- package/gs/strconv/append.test.ts +99 -0
- package/gs/strconv/atof.gs.ts +156 -42
- package/gs/strconv/atof.test.ts +45 -0
- package/gs/strconv/atoi.gs.ts +87 -69
- package/gs/strconv/atoi.test.ts +49 -0
- package/gs/strconv/ftoa.gs.ts +85 -10
- package/gs/strconv/ftoa.test.ts +43 -0
- package/gs/strconv/itoa.gs.ts +10 -9
- package/gs/strconv/quote.gs.ts +335 -108
- package/gs/strconv/quote.test.ts +111 -0
- package/gs/strings/reader.test.ts +10 -10
- package/gs/strings/reader.ts +9 -9
- package/gs/strings/strings.test.ts +18 -5
- package/gs/strings/strings.ts +81 -68
- package/gs/sync/atomic/doc_64.gs.ts +24 -24
- package/gs/sync/atomic/doc_64.test.ts +5 -5
- package/gs/sync/atomic/type.gs.ts +28 -28
- package/gs/sync/sync.test.ts +109 -1
- package/gs/sync/sync.ts +46 -12
- package/gs/syscall/fs.ts +8 -8
- package/gs/syscall/net.test.ts +1 -1
- package/gs/time/parse.test.ts +45 -0
- package/gs/time/time.test.ts +46 -23
- package/gs/time/time.ts +69 -66
- package/gs/unicode/gen.go +198 -0
- package/gs/unicode/tables.ts +646 -0
- package/gs/unicode/unicode.test.ts +69 -0
- package/gs/unicode/unicode.ts +396 -312
- package/package.json +1 -1
- package/dist/gs/github.com/aperturerobotics/util/conc/index.d.ts +0 -20
- package/dist/gs/github.com/aperturerobotics/util/conc/index.js +0 -134
- package/dist/gs/github.com/aperturerobotics/util/conc/index.js.map +0 -1
- package/gs/github.com/aperturerobotics/util/conc/index.test.ts +0 -30
- package/gs/github.com/aperturerobotics/util/conc/index.ts +0 -172
- package/gs/github.com/aperturerobotics/util/conc/meta.json +0 -9
|
@@ -0,0 +1,705 @@
|
|
|
1
|
+
package compiler
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"context"
|
|
5
|
+
"os"
|
|
6
|
+
"path/filepath"
|
|
7
|
+
"strings"
|
|
8
|
+
"sync"
|
|
9
|
+
"testing"
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
func TestCompileRequestCarriesCacheRoot(t *testing.T) {
|
|
13
|
+
req := NewCompileRequestOwner().NewRequest(Config{
|
|
14
|
+
Dir: ".",
|
|
15
|
+
OutputPath: "out",
|
|
16
|
+
CacheRoot: "cache-root",
|
|
17
|
+
}, []string{"."})
|
|
18
|
+
if req.CacheRoot != "cache-root" {
|
|
19
|
+
t.Fatalf("CacheRoot = %q, want cache-root", req.CacheRoot)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
func TestCompilePackagesCacheDisabledCreatesNoCacheRoot(t *testing.T) {
|
|
24
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
25
|
+
"go.mod": "module example.test/cachedefault\n\ngo 1.25.3\n",
|
|
26
|
+
"main.go": "package cachedefault\nconst Value = 1\n",
|
|
27
|
+
})
|
|
28
|
+
outputDir := filepath.Join(t.TempDir(), "out")
|
|
29
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
30
|
+
comp, err := NewCompiler(&Config{
|
|
31
|
+
Dir: moduleDir,
|
|
32
|
+
OutputPath: outputDir,
|
|
33
|
+
CacheRoot: "",
|
|
34
|
+
}, nil, nil)
|
|
35
|
+
if err != nil {
|
|
36
|
+
t.Fatal(err)
|
|
37
|
+
}
|
|
38
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err != nil {
|
|
39
|
+
t.Fatal(err)
|
|
40
|
+
}
|
|
41
|
+
if _, err := os.Stat(cacheRoot); !os.IsNotExist(err) {
|
|
42
|
+
t.Fatalf("disabled cache root stat err = %v, want not exist", err)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func TestCompilePackagesCacheReplaysOutput(t *testing.T) {
|
|
47
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
48
|
+
"go.mod": "module example.test/cachereplay\n\ngo 1.25.3\n",
|
|
49
|
+
"main.go": "package cachereplay\nconst Value = 1\n",
|
|
50
|
+
})
|
|
51
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
52
|
+
firstOut := filepath.Join(t.TempDir(), "first")
|
|
53
|
+
result := compileCacheFixture(t, moduleDir, firstOut, cacheRoot)
|
|
54
|
+
if len(result.CompiledPackages) != 1 || result.CompiledPackages[0] != "example.test/cachereplay" {
|
|
55
|
+
t.Fatalf("compiled packages = %#v", result.CompiledPackages)
|
|
56
|
+
}
|
|
57
|
+
manifest := firstCacheManifestPath(t, cacheRoot)
|
|
58
|
+
if manifest == "" {
|
|
59
|
+
t.Fatal("cache manifest not written")
|
|
60
|
+
}
|
|
61
|
+
firstManifestCount := countCacheManifests(t, cacheRoot)
|
|
62
|
+
|
|
63
|
+
secondOut := filepath.Join(t.TempDir(), "second")
|
|
64
|
+
second := compileCacheFixture(t, moduleDir, secondOut, cacheRoot)
|
|
65
|
+
if len(second.CompiledPackages) != 1 || second.CompiledPackages[0] != "example.test/cachereplay" {
|
|
66
|
+
t.Fatalf("cached compiled packages = %#v", second.CompiledPackages)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
first := readOutputFile(t, firstOut, "example.test/cachereplay", "main.gs.ts")
|
|
70
|
+
replayed := readOutputFile(t, secondOut, "example.test/cachereplay", "main.gs.ts")
|
|
71
|
+
if first != replayed {
|
|
72
|
+
t.Fatalf("cache replay output changed:\nfirst:\n%s\nsecond:\n%s", first, replayed)
|
|
73
|
+
}
|
|
74
|
+
if got := countCacheManifests(t, cacheRoot); got != firstManifestCount {
|
|
75
|
+
t.Fatalf("cache manifests after replay = %d, want %d", got, firstManifestCount)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
func TestCompilePackagesCacheReplaysEquivalentMultiPackageOutput(t *testing.T) {
|
|
80
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
81
|
+
"go.mod": "module example.test/cacheequiv\n\ngo 1.25.3\n",
|
|
82
|
+
"version.txt": "1.2.3\n",
|
|
83
|
+
"main.go": strings.Join([]string{
|
|
84
|
+
"package cacheequiv",
|
|
85
|
+
"import (",
|
|
86
|
+
" _ \"embed\"",
|
|
87
|
+
" \"example.test/cacheequiv/dep\"",
|
|
88
|
+
" _ \"example.test/cacheequiv/side\"",
|
|
89
|
+
")",
|
|
90
|
+
"//go:embed version.txt",
|
|
91
|
+
"var Version string",
|
|
92
|
+
"const Value = dep.Value",
|
|
93
|
+
"",
|
|
94
|
+
}, "\n"),
|
|
95
|
+
"foo.pb.go": "package cacheequiv\ntype Foo struct{}\n",
|
|
96
|
+
"foo.pb.ts": "export const Foo = \"first\";\n",
|
|
97
|
+
"dep/dep.go": strings.Join([]string{
|
|
98
|
+
"package dep",
|
|
99
|
+
"const Value = 3",
|
|
100
|
+
"",
|
|
101
|
+
}, "\n"),
|
|
102
|
+
"side/side.go": strings.Join([]string{
|
|
103
|
+
"package side",
|
|
104
|
+
"func init() {}",
|
|
105
|
+
"",
|
|
106
|
+
}, "\n"),
|
|
107
|
+
})
|
|
108
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
109
|
+
outputRoot := filepath.Join(t.TempDir(), "out")
|
|
110
|
+
compileCacheFixtureConfig(t, Config{
|
|
111
|
+
AllDependencies: true,
|
|
112
|
+
ProtobufTypeScriptBinding: true,
|
|
113
|
+
}, moduleDir, outputRoot, cacheRoot)
|
|
114
|
+
firstSnapshot := outputTreeSnapshot(t, outputRoot)
|
|
115
|
+
firstManifestCount := countCacheManifests(t, cacheRoot)
|
|
116
|
+
|
|
117
|
+
if err := os.RemoveAll(outputRoot); err != nil {
|
|
118
|
+
t.Fatal(err)
|
|
119
|
+
}
|
|
120
|
+
compileCacheFixtureConfig(t, Config{
|
|
121
|
+
AllDependencies: true,
|
|
122
|
+
ProtobufTypeScriptBinding: true,
|
|
123
|
+
}, moduleDir, outputRoot, cacheRoot)
|
|
124
|
+
secondSnapshot := outputTreeSnapshot(t, outputRoot)
|
|
125
|
+
if firstSnapshot != secondSnapshot {
|
|
126
|
+
t.Fatalf("cache replay output differs:\nfirst:\n%s\nsecond:\n%s", firstSnapshot, secondSnapshot)
|
|
127
|
+
}
|
|
128
|
+
if got := countCacheManifests(t, cacheRoot); got != firstManifestCount {
|
|
129
|
+
t.Fatalf("cache manifests after multi-package replay = %d, want %d", got, firstManifestCount)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
func TestCompilePackagesCacheInvalidatesSourceChange(t *testing.T) {
|
|
134
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
135
|
+
"go.mod": "module example.test/cacheinvalidate\n\ngo 1.25.3\n",
|
|
136
|
+
"main.go": "package cacheinvalidate\nconst Value = 1\n",
|
|
137
|
+
})
|
|
138
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
139
|
+
firstOut := filepath.Join(t.TempDir(), "first")
|
|
140
|
+
compileCacheFixture(t, moduleDir, firstOut, cacheRoot)
|
|
141
|
+
|
|
142
|
+
if err := os.WriteFile(filepath.Join(moduleDir, "main.go"), []byte("package cacheinvalidate\nconst Value = 2\n"), 0o644); err != nil {
|
|
143
|
+
t.Fatal(err)
|
|
144
|
+
}
|
|
145
|
+
secondOut := filepath.Join(t.TempDir(), "second")
|
|
146
|
+
compileCacheFixture(t, moduleDir, secondOut, cacheRoot)
|
|
147
|
+
text := readOutputFile(t, secondOut, "example.test/cacheinvalidate", "main.gs.ts")
|
|
148
|
+
if !strings.Contains(text, "Value: number = 2") {
|
|
149
|
+
t.Fatalf("source change was not reflected in output:\n%s", text)
|
|
150
|
+
}
|
|
151
|
+
if countCacheManifests(t, cacheRoot) < 2 {
|
|
152
|
+
t.Fatal("source change did not create a distinct cache entry")
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
func TestCompilePackagesCacheRequestedModeValidatesImportsBeforeReplay(t *testing.T) {
|
|
157
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
158
|
+
"go.mod": "module example.test/cacherequestedimports\n\ngo 1.25.3\n",
|
|
159
|
+
"main.go": strings.Join([]string{
|
|
160
|
+
"package cacherequestedimports",
|
|
161
|
+
"import \"example.test/cacherequestedimports/dep\"",
|
|
162
|
+
"const Value = dep.Value",
|
|
163
|
+
"",
|
|
164
|
+
}, "\n"),
|
|
165
|
+
"dep/dep.go": strings.Join([]string{
|
|
166
|
+
"package dep",
|
|
167
|
+
"const Value = 1",
|
|
168
|
+
"",
|
|
169
|
+
}, "\n"),
|
|
170
|
+
})
|
|
171
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
172
|
+
compileCacheFixture(t, moduleDir, filepath.Join(t.TempDir(), "first"), cacheRoot)
|
|
173
|
+
firstManifestCount := countCacheManifests(t, cacheRoot)
|
|
174
|
+
|
|
175
|
+
if err := os.WriteFile(filepath.Join(moduleDir, "dep", "dep.go"), []byte("package dep\nconst Other = 1\n"), 0o644); err != nil {
|
|
176
|
+
t.Fatal(err)
|
|
177
|
+
}
|
|
178
|
+
comp, err := NewCompiler(&Config{
|
|
179
|
+
Dir: moduleDir,
|
|
180
|
+
OutputPath: filepath.Join(t.TempDir(), "second"),
|
|
181
|
+
CacheRoot: cacheRoot,
|
|
182
|
+
}, nil, nil)
|
|
183
|
+
if err != nil {
|
|
184
|
+
t.Fatal(err)
|
|
185
|
+
}
|
|
186
|
+
if _, err := comp.CompilePackages(context.Background(), "."); err == nil {
|
|
187
|
+
t.Fatal("requested-mode cache replay skipped imported package type validation")
|
|
188
|
+
}
|
|
189
|
+
if got := countCacheManifests(t, cacheRoot); got != firstManifestCount {
|
|
190
|
+
t.Fatalf("invalid imported package wrote cache manifests: got %d want %d", got, firstManifestCount)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
func TestCompilePackagesCacheInvalidatesEmbedFileChange(t *testing.T) {
|
|
195
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
196
|
+
"go.mod": "module example.test/cacheembed\n\ngo 1.25.3\n",
|
|
197
|
+
"version.txt": "1.2.3\n",
|
|
198
|
+
"main.go": strings.Join([]string{
|
|
199
|
+
"package cacheembed",
|
|
200
|
+
"import _ \"embed\"",
|
|
201
|
+
"//go:embed version.txt",
|
|
202
|
+
"var Version string",
|
|
203
|
+
"",
|
|
204
|
+
}, "\n"),
|
|
205
|
+
})
|
|
206
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
207
|
+
firstOut := filepath.Join(t.TempDir(), "first")
|
|
208
|
+
compileCacheFixtureConfig(t, Config{AllDependencies: true}, moduleDir, firstOut, cacheRoot)
|
|
209
|
+
|
|
210
|
+
if err := os.WriteFile(filepath.Join(moduleDir, "version.txt"), []byte("2.0.0\n"), 0o644); err != nil {
|
|
211
|
+
t.Fatal(err)
|
|
212
|
+
}
|
|
213
|
+
secondOut := filepath.Join(t.TempDir(), "second")
|
|
214
|
+
compileCacheFixtureConfig(t, Config{AllDependencies: true}, moduleDir, secondOut, cacheRoot)
|
|
215
|
+
text := readOutputFile(t, secondOut, "example.test/cacheembed", "main.gs.ts")
|
|
216
|
+
if !strings.Contains(text, `Version: string = "2.0.0\n"`) {
|
|
217
|
+
t.Fatalf("embed file change was not reflected in output:\n%s", text)
|
|
218
|
+
}
|
|
219
|
+
if countCacheManifests(t, cacheRoot) < 2 {
|
|
220
|
+
t.Fatal("embed file change did not create a distinct cache entry")
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
func TestCompilePackagesCacheInvalidatesProtobufBindingFileChange(t *testing.T) {
|
|
225
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
226
|
+
"go.mod": "module example.test/cachepb\n\ngo 1.25.3\n",
|
|
227
|
+
"foo.pb.go": `package cachepb
|
|
228
|
+
|
|
229
|
+
type Foo struct{}
|
|
230
|
+
`,
|
|
231
|
+
"foo.pb.ts": `export const Foo = "first";
|
|
232
|
+
`,
|
|
233
|
+
})
|
|
234
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
235
|
+
outputRoot := filepath.Join(t.TempDir(), "out")
|
|
236
|
+
compileCacheFixtureConfig(t, Config{ProtobufTypeScriptBinding: true}, moduleDir, outputRoot, cacheRoot)
|
|
237
|
+
|
|
238
|
+
if err := os.WriteFile(filepath.Join(moduleDir, "foo.pb.ts"), []byte(`export const Bar = "second";
|
|
239
|
+
`), 0o644); err != nil {
|
|
240
|
+
t.Fatal(err)
|
|
241
|
+
}
|
|
242
|
+
if err := os.RemoveAll(outputRoot); err != nil {
|
|
243
|
+
t.Fatal(err)
|
|
244
|
+
}
|
|
245
|
+
compileCacheFixtureConfig(t, Config{ProtobufTypeScriptBinding: true}, moduleDir, outputRoot, cacheRoot)
|
|
246
|
+
text := readOutputFile(t, outputRoot, "example.test/cachepb", "foo.pb.ts")
|
|
247
|
+
if strings.Contains(text, "__protobufTypeScriptMessage = __protobuf_ts.Foo") {
|
|
248
|
+
t.Fatalf("protobuf binding change was not reflected in output:\n%s", text)
|
|
249
|
+
}
|
|
250
|
+
if countCacheManifests(t, cacheRoot) < 2 {
|
|
251
|
+
t.Fatal("protobuf binding change did not create a distinct cache entry")
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
func TestCompilerCacheKeyInvalidatesRequestAndModuleInputs(t *testing.T) {
|
|
256
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
257
|
+
"go.mod": "module example.test/cachekey\n\ngo 1.25.3\n",
|
|
258
|
+
"main.go": "package cachekey\nconst Value = 1\n",
|
|
259
|
+
})
|
|
260
|
+
baseReq := &CompileRequest{
|
|
261
|
+
Patterns: []string{"."},
|
|
262
|
+
Dir: moduleDir,
|
|
263
|
+
OutputPath: filepath.Join(t.TempDir(), "out"),
|
|
264
|
+
CacheRoot: filepath.Join(t.TempDir(), "cache"),
|
|
265
|
+
DependencyMode: DependencyModeRequested,
|
|
266
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
267
|
+
}
|
|
268
|
+
graph := singleNodeCacheGraph(moduleDir, "example.test/cachekey")
|
|
269
|
+
baseKey := generatedCacheKey(t, baseReq, graph)
|
|
270
|
+
|
|
271
|
+
cases := []struct {
|
|
272
|
+
name string
|
|
273
|
+
edit func(*CompileRequest)
|
|
274
|
+
}{
|
|
275
|
+
{name: "build flags", edit: func(req *CompileRequest) { req.BuildFlags = []string{"tags=cachetest"} }},
|
|
276
|
+
{name: "package blocklist", edit: func(req *CompileRequest) { req.PackageBlocklist = []string{"example.test/blocked"} }},
|
|
277
|
+
{name: "dependency mode", edit: func(req *CompileRequest) { req.DependencyMode = DependencyModeAll }},
|
|
278
|
+
{name: "runtime mode", edit: func(req *CompileRequest) { req.RuntimeEmissionMode = RuntimeEmissionModeReference }},
|
|
279
|
+
{name: "test variants", edit: func(req *CompileRequest) { req.Tests = true }},
|
|
280
|
+
}
|
|
281
|
+
for _, tc := range cases {
|
|
282
|
+
t.Run(tc.name, func(t *testing.T) {
|
|
283
|
+
req := *baseReq
|
|
284
|
+
tc.edit(&req)
|
|
285
|
+
if key := generatedCacheKey(t, &req, graph); key == baseKey {
|
|
286
|
+
t.Fatalf("%s did not change generated package key", tc.name)
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if err := os.WriteFile(filepath.Join(moduleDir, "go.mod"), []byte("module example.test/cachekey\n\ngo 1.25.3\n\nrequire example.test/dep v0.0.0\n"), 0o644); err != nil {
|
|
292
|
+
t.Fatal(err)
|
|
293
|
+
}
|
|
294
|
+
if key := generatedCacheKey(t, baseReq, graph); key == baseKey {
|
|
295
|
+
t.Fatal("module file change did not change generated package key")
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
func TestCompilerCacheKeyTracksOverridesAndProtobufOutputRelation(t *testing.T) {
|
|
300
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
301
|
+
"go.mod": "module example.test/cachekeypb\n\ngo 1.25.3\n",
|
|
302
|
+
"foo.pb.go": "package cachekeypb\ntype Foo struct{}\n",
|
|
303
|
+
"foo.pb.ts": "export const Foo = \"first\";\n",
|
|
304
|
+
})
|
|
305
|
+
req := &CompileRequest{
|
|
306
|
+
Patterns: []string{"."},
|
|
307
|
+
Dir: moduleDir,
|
|
308
|
+
OutputPath: filepath.Join(t.TempDir(), "out-a"),
|
|
309
|
+
CacheRoot: filepath.Join(t.TempDir(), "cache"),
|
|
310
|
+
DependencyMode: DependencyModeRequested,
|
|
311
|
+
RuntimeEmissionMode: RuntimeEmissionModeEmit,
|
|
312
|
+
ProtobufTypeScriptBinding: true,
|
|
313
|
+
}
|
|
314
|
+
graph := singleNodeCacheGraph(moduleDir, "example.test/cachekeypb")
|
|
315
|
+
graph.Nodes[0].CompiledGoFiles = []string{filepath.Join(moduleDir, "foo.pb.go")}
|
|
316
|
+
graph.Nodes[0].GoFiles = graph.Nodes[0].CompiledGoFiles
|
|
317
|
+
baseKey := generatedCacheKey(t, req, graph)
|
|
318
|
+
|
|
319
|
+
outputReq := *req
|
|
320
|
+
outputReq.OutputPath = filepath.Join(t.TempDir(), "out-b")
|
|
321
|
+
if key := generatedCacheKey(t, &outputReq, graph); key == baseKey {
|
|
322
|
+
t.Fatal("protobuf output root relation did not change generated package key")
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
plan := &overrideCopyPlan{packages: []overrideCopyPackage{{
|
|
326
|
+
path: "example.test/cachekeypb",
|
|
327
|
+
files: []overrideCopyFile{{path: "example.test/cachekeypb/index.ts", data: []byte("first")}},
|
|
328
|
+
}}}
|
|
329
|
+
changedPlan := &overrideCopyPlan{packages: []overrideCopyPackage{{
|
|
330
|
+
path: "example.test/cachekeypb",
|
|
331
|
+
files: []overrideCopyFile{{path: "example.test/cachekeypb/index.ts", data: []byte("second")}},
|
|
332
|
+
}}}
|
|
333
|
+
baseOverrideKey := copiedCacheKey(t, req, graph, plan)
|
|
334
|
+
if key := copiedCacheKey(t, req, graph, changedPlan); key == baseOverrideKey {
|
|
335
|
+
t.Fatal("override file content did not change copied package key")
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
func TestCompilerCacheFastReplayRequiresTypedGraphForStrictParity(t *testing.T) {
|
|
340
|
+
graph := &PackageGraph{
|
|
341
|
+
Nodes: []*PackageGraphNode{{
|
|
342
|
+
PkgPath: "example.test/override",
|
|
343
|
+
OverrideCandidate: true,
|
|
344
|
+
}},
|
|
345
|
+
}
|
|
346
|
+
if overrideParityRequiresTypedGraph(graph, &OverrideFacts{packages: map[string]overridePackageFacts{
|
|
347
|
+
"example.test/override": {
|
|
348
|
+
parity: overrideParityLedger{
|
|
349
|
+
Strict: true,
|
|
350
|
+
Symbols: map[string]overrideParityEntry{"Value": {Status: overrideParityStatusReal}},
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
}}) {
|
|
354
|
+
return
|
|
355
|
+
}
|
|
356
|
+
t.Fatal("strict override parity did not require a typed graph")
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
func TestCompilerCacheFastReplayAllowsUntypedOverrideMetadata(t *testing.T) {
|
|
360
|
+
graph := &PackageGraph{
|
|
361
|
+
Nodes: []*PackageGraphNode{{
|
|
362
|
+
PkgPath: "context",
|
|
363
|
+
OverrideCandidate: true,
|
|
364
|
+
}},
|
|
365
|
+
}
|
|
366
|
+
if overrideParityRequiresTypedGraph(graph, &OverrideFacts{packages: map[string]overridePackageFacts{
|
|
367
|
+
"context": {metadata: newOverrideMetadata()},
|
|
368
|
+
}}) {
|
|
369
|
+
t.Fatal("metadata-only override required a typed graph")
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
func TestCompilePackagesCacheCorruptionFallsBackToFreshCompile(t *testing.T) {
|
|
374
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
375
|
+
"go.mod": "module example.test/cachecorrupt\n\ngo 1.25.3\n",
|
|
376
|
+
"main.go": "package cachecorrupt\nconst Value = 1\n",
|
|
377
|
+
})
|
|
378
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
379
|
+
firstOut := filepath.Join(t.TempDir(), "first")
|
|
380
|
+
compileCacheFixture(t, moduleDir, firstOut, cacheRoot)
|
|
381
|
+
|
|
382
|
+
blob := firstCacheBlobPath(t, cacheRoot)
|
|
383
|
+
if blob == "" {
|
|
384
|
+
t.Fatal("cache blob not written")
|
|
385
|
+
}
|
|
386
|
+
if err := os.WriteFile(blob, []byte("corrupt"), 0o644); err != nil {
|
|
387
|
+
t.Fatal(err)
|
|
388
|
+
}
|
|
389
|
+
secondOut := filepath.Join(t.TempDir(), "second")
|
|
390
|
+
compileCacheFixture(t, moduleDir, secondOut, cacheRoot)
|
|
391
|
+
text := readOutputFile(t, secondOut, "example.test/cachecorrupt", "main.gs.ts")
|
|
392
|
+
if !strings.Contains(text, "Value: number = 1") {
|
|
393
|
+
t.Fatalf("fresh fallback output missing value:\n%s", text)
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
func TestCompilePackagesCacheInvalidManifestEntriesFallBackToFreshCompile(t *testing.T) {
|
|
398
|
+
cases := []struct {
|
|
399
|
+
name string
|
|
400
|
+
tamper func(*testing.T, string)
|
|
401
|
+
}{
|
|
402
|
+
{
|
|
403
|
+
name: "missing blob",
|
|
404
|
+
tamper: func(t *testing.T, cacheRoot string) {
|
|
405
|
+
t.Helper()
|
|
406
|
+
if err := os.Remove(firstCacheBlobPath(t, cacheRoot)); err != nil {
|
|
407
|
+
t.Fatal(err)
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
name: "bad key",
|
|
413
|
+
tamper: func(t *testing.T, cacheRoot string) {
|
|
414
|
+
t.Helper()
|
|
415
|
+
manifest := firstCacheManifestPath(t, cacheRoot)
|
|
416
|
+
data, err := os.ReadFile(manifest)
|
|
417
|
+
if err != nil {
|
|
418
|
+
t.Fatal(err)
|
|
419
|
+
}
|
|
420
|
+
data = []byte(strings.Replace(string(data), `"key": "`, `"key": "bad`, 1))
|
|
421
|
+
if err := os.WriteFile(manifest, data, 0o644); err != nil {
|
|
422
|
+
t.Fatal(err)
|
|
423
|
+
}
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
{
|
|
427
|
+
name: "unsupported schema",
|
|
428
|
+
tamper: func(t *testing.T, cacheRoot string) {
|
|
429
|
+
t.Helper()
|
|
430
|
+
manifest := firstCacheManifestPath(t, cacheRoot)
|
|
431
|
+
data, err := os.ReadFile(manifest)
|
|
432
|
+
if err != nil {
|
|
433
|
+
t.Fatal(err)
|
|
434
|
+
}
|
|
435
|
+
data = []byte(strings.Replace(string(data), compilerCacheSchema, "unsupported-schema", 1))
|
|
436
|
+
if err := os.WriteFile(manifest, data, 0o644); err != nil {
|
|
437
|
+
t.Fatal(err)
|
|
438
|
+
}
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
name: "incomplete entry",
|
|
443
|
+
tamper: func(t *testing.T, cacheRoot string) {
|
|
444
|
+
t.Helper()
|
|
445
|
+
if err := os.Remove(filepath.Join(filepath.Dir(firstCacheManifestPath(t, cacheRoot)), "complete")); err != nil {
|
|
446
|
+
t.Fatal(err)
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
for _, tc := range cases {
|
|
453
|
+
t.Run(tc.name, func(t *testing.T) {
|
|
454
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
455
|
+
"go.mod": "module example.test/cacheinvalidmanifest\n\ngo 1.25.3\n",
|
|
456
|
+
"main.go": "package cacheinvalidmanifest\nconst Value = 1\n",
|
|
457
|
+
})
|
|
458
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
459
|
+
compileCacheFixture(t, moduleDir, filepath.Join(t.TempDir(), "first"), cacheRoot)
|
|
460
|
+
tc.tamper(t, cacheRoot)
|
|
461
|
+
|
|
462
|
+
secondOut := filepath.Join(t.TempDir(), "second")
|
|
463
|
+
compileCacheFixture(t, moduleDir, secondOut, cacheRoot)
|
|
464
|
+
text := readOutputFile(t, secondOut, "example.test/cacheinvalidmanifest", "main.gs.ts")
|
|
465
|
+
if !strings.Contains(text, "Value: number = 1") {
|
|
466
|
+
t.Fatalf("fresh fallback output missing value:\n%s", text)
|
|
467
|
+
}
|
|
468
|
+
})
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
func TestCompilerCacheGoEmbedFilesTreatsQuestionAsPattern(t *testing.T) {
|
|
473
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
474
|
+
"go.mod": "module example.test/cacheembedpattern\n\ngo 1.25.3\n",
|
|
475
|
+
"a.txt": "one\n",
|
|
476
|
+
})
|
|
477
|
+
files, err := compilerCacheGoEmbedFiles(moduleDir, "?.txt")
|
|
478
|
+
if err != nil {
|
|
479
|
+
t.Fatal(err)
|
|
480
|
+
}
|
|
481
|
+
if len(files) != 1 || !strings.HasSuffix(files[0], string(filepath.Separator)+"a.txt") {
|
|
482
|
+
t.Fatalf("embed pattern files = %#v, want a.txt", files)
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
func TestCompilePackagesCacheConcurrentWritersConverge(t *testing.T) {
|
|
487
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
488
|
+
"go.mod": "module example.test/cacheconcurrent\n\ngo 1.25.3\n",
|
|
489
|
+
"main.go": "package cacheconcurrent\nconst Value = 1\n",
|
|
490
|
+
})
|
|
491
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
492
|
+
outputRoots := make([]string, 4)
|
|
493
|
+
for idx := range outputRoots {
|
|
494
|
+
outputRoots[idx] = filepath.Join(t.TempDir(), "out")
|
|
495
|
+
}
|
|
496
|
+
var wg sync.WaitGroup
|
|
497
|
+
errs := make(chan error, 4)
|
|
498
|
+
for idx := range 4 {
|
|
499
|
+
wg.Add(1)
|
|
500
|
+
go func(idx int) {
|
|
501
|
+
defer wg.Done()
|
|
502
|
+
comp, err := NewCompiler(&Config{
|
|
503
|
+
Dir: moduleDir,
|
|
504
|
+
OutputPath: outputRoots[idx],
|
|
505
|
+
CacheRoot: cacheRoot,
|
|
506
|
+
}, nil, nil)
|
|
507
|
+
if err != nil {
|
|
508
|
+
errs <- err
|
|
509
|
+
return
|
|
510
|
+
}
|
|
511
|
+
_, err = comp.CompilePackages(context.Background(), ".")
|
|
512
|
+
errs <- err
|
|
513
|
+
}(idx)
|
|
514
|
+
}
|
|
515
|
+
wg.Wait()
|
|
516
|
+
close(errs)
|
|
517
|
+
for err := range errs {
|
|
518
|
+
if err != nil {
|
|
519
|
+
t.Fatal(err)
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if count := countCacheManifests(t, cacheRoot); count == 0 {
|
|
523
|
+
t.Fatal("concurrent writers did not leave any complete cache manifests")
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
func TestCompilePackagesCacheUnsafeManifestPathFallsBackToFreshCompile(t *testing.T) {
|
|
528
|
+
moduleDir := writePackageGraphFixture(t, map[string]string{
|
|
529
|
+
"go.mod": "module example.test/cacheunsafe\n\ngo 1.25.3\n",
|
|
530
|
+
"main.go": "package cacheunsafe\nconst Value = 1\n",
|
|
531
|
+
})
|
|
532
|
+
cacheRoot := filepath.Join(t.TempDir(), "cache")
|
|
533
|
+
compileCacheFixture(t, moduleDir, filepath.Join(t.TempDir(), "first"), cacheRoot)
|
|
534
|
+
|
|
535
|
+
manifest := firstCacheManifestPath(t, cacheRoot)
|
|
536
|
+
data, err := os.ReadFile(manifest)
|
|
537
|
+
if err != nil {
|
|
538
|
+
t.Fatal(err)
|
|
539
|
+
}
|
|
540
|
+
data = []byte(strings.Replace(string(data), "@goscript/example.test/cacheunsafe/main.gs.ts", "../escape.ts", 1))
|
|
541
|
+
if err := os.WriteFile(manifest, data, 0o644); err != nil {
|
|
542
|
+
t.Fatal(err)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
secondOut := filepath.Join(t.TempDir(), "second")
|
|
546
|
+
compileCacheFixture(t, moduleDir, secondOut, cacheRoot)
|
|
547
|
+
if _, err := os.Stat(filepath.Join(secondOut, "..", "escape.ts")); !os.IsNotExist(err) {
|
|
548
|
+
t.Fatalf("unsafe replay path stat err = %v, want not exist", err)
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
func singleNodeCacheGraph(moduleDir, importPath string) *PackageGraph {
|
|
553
|
+
file := filepath.Join(moduleDir, "main.go")
|
|
554
|
+
node := &PackageGraphNode{
|
|
555
|
+
ID: importPath,
|
|
556
|
+
PkgPath: importPath,
|
|
557
|
+
Name: filepath.Base(importPath),
|
|
558
|
+
ModulePath: importPath,
|
|
559
|
+
ModuleDir: moduleDir,
|
|
560
|
+
GoFiles: []string{file},
|
|
561
|
+
CompiledGoFiles: []string{file},
|
|
562
|
+
Requested: true,
|
|
563
|
+
}
|
|
564
|
+
return &PackageGraph{
|
|
565
|
+
RequestedPatterns: []string{"."},
|
|
566
|
+
RequestedPackagePaths: []string{importPath},
|
|
567
|
+
Nodes: []*PackageGraphNode{node},
|
|
568
|
+
NodesByPackagePath: map[string]*PackageGraphNode{importPath: node},
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
func generatedCacheKey(t *testing.T, req *CompileRequest, graph *PackageGraph) string {
|
|
573
|
+
t.Helper()
|
|
574
|
+
entries := NewCompilerCacheOwner().Entries(req, graph, nil)
|
|
575
|
+
if len(entries) == 0 {
|
|
576
|
+
t.Fatal("no cache entries")
|
|
577
|
+
}
|
|
578
|
+
return entries[0].key
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
func copiedCacheKey(t *testing.T, req *CompileRequest, graph *PackageGraph, plan *overrideCopyPlan) string {
|
|
582
|
+
t.Helper()
|
|
583
|
+
entries := NewCompilerCacheOwner().Entries(req, graph, plan)
|
|
584
|
+
for _, entry := range entries {
|
|
585
|
+
if entry.kind == compilerCacheEntryCopied {
|
|
586
|
+
return entry.key
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
t.Fatal("no copied cache entry")
|
|
590
|
+
return ""
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
func compileCacheFixture(t *testing.T, moduleDir, outputDir, cacheRoot string) *CompilationResult {
|
|
594
|
+
t.Helper()
|
|
595
|
+
return compileCacheFixtureConfig(t, Config{}, moduleDir, outputDir, cacheRoot)
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
func compileCacheFixtureConfig(t *testing.T, config Config, moduleDir, outputDir, cacheRoot string) *CompilationResult {
|
|
599
|
+
t.Helper()
|
|
600
|
+
config.Dir = moduleDir
|
|
601
|
+
config.OutputPath = outputDir
|
|
602
|
+
config.CacheRoot = cacheRoot
|
|
603
|
+
comp, err := NewCompiler(&config, nil, nil)
|
|
604
|
+
if err != nil {
|
|
605
|
+
t.Fatal(err)
|
|
606
|
+
}
|
|
607
|
+
result, err := comp.CompilePackages(context.Background(), ".")
|
|
608
|
+
if err != nil {
|
|
609
|
+
t.Fatal(err)
|
|
610
|
+
}
|
|
611
|
+
return result
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
func readOutputFile(t *testing.T, outputRoot, importPath, name string) string {
|
|
615
|
+
t.Helper()
|
|
616
|
+
data, err := os.ReadFile(filepath.Join(outputRoot, "@goscript", filepath.FromSlash(importPath), name))
|
|
617
|
+
if err != nil {
|
|
618
|
+
t.Fatal(err)
|
|
619
|
+
}
|
|
620
|
+
return string(data)
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
func outputTreeSnapshot(t *testing.T, root string) string {
|
|
624
|
+
t.Helper()
|
|
625
|
+
var snapshot strings.Builder
|
|
626
|
+
err := filepath.WalkDir(root, func(path string, entry os.DirEntry, err error) error {
|
|
627
|
+
if err != nil {
|
|
628
|
+
return err
|
|
629
|
+
}
|
|
630
|
+
if entry.IsDir() {
|
|
631
|
+
return nil
|
|
632
|
+
}
|
|
633
|
+
rel, err := filepath.Rel(root, path)
|
|
634
|
+
if err != nil {
|
|
635
|
+
return err
|
|
636
|
+
}
|
|
637
|
+
data, err := os.ReadFile(path)
|
|
638
|
+
if err != nil {
|
|
639
|
+
return err
|
|
640
|
+
}
|
|
641
|
+
snapshot.WriteString(filepath.ToSlash(rel))
|
|
642
|
+
snapshot.WriteByte('\n')
|
|
643
|
+
snapshot.Write(data)
|
|
644
|
+
snapshot.WriteByte('\n')
|
|
645
|
+
return nil
|
|
646
|
+
})
|
|
647
|
+
if err != nil {
|
|
648
|
+
t.Fatal(err)
|
|
649
|
+
}
|
|
650
|
+
return snapshot.String()
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
func firstCacheManifestPath(t *testing.T, cacheRoot string) string {
|
|
654
|
+
t.Helper()
|
|
655
|
+
var found string
|
|
656
|
+
err := filepath.WalkDir(cacheRoot, func(path string, entry os.DirEntry, err error) error {
|
|
657
|
+
if err != nil || found != "" {
|
|
658
|
+
return err
|
|
659
|
+
}
|
|
660
|
+
if !entry.IsDir() && entry.Name() == "manifest.json" {
|
|
661
|
+
found = path
|
|
662
|
+
}
|
|
663
|
+
return nil
|
|
664
|
+
})
|
|
665
|
+
if err != nil {
|
|
666
|
+
t.Fatal(err)
|
|
667
|
+
}
|
|
668
|
+
return found
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
func firstCacheBlobPath(t *testing.T, cacheRoot string) string {
|
|
672
|
+
t.Helper()
|
|
673
|
+
var found string
|
|
674
|
+
err := filepath.WalkDir(filepath.Join(cacheRoot, compilerCacheSchema, "blobs"), func(path string, entry os.DirEntry, err error) error {
|
|
675
|
+
if err != nil || found != "" {
|
|
676
|
+
return err
|
|
677
|
+
}
|
|
678
|
+
if !entry.IsDir() {
|
|
679
|
+
found = path
|
|
680
|
+
}
|
|
681
|
+
return nil
|
|
682
|
+
})
|
|
683
|
+
if err != nil {
|
|
684
|
+
t.Fatal(err)
|
|
685
|
+
}
|
|
686
|
+
return found
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
func countCacheManifests(t *testing.T, cacheRoot string) int {
|
|
690
|
+
t.Helper()
|
|
691
|
+
count := 0
|
|
692
|
+
err := filepath.WalkDir(cacheRoot, func(path string, entry os.DirEntry, err error) error {
|
|
693
|
+
if err != nil {
|
|
694
|
+
return err
|
|
695
|
+
}
|
|
696
|
+
if !entry.IsDir() && entry.Name() == "manifest.json" {
|
|
697
|
+
count++
|
|
698
|
+
}
|
|
699
|
+
return nil
|
|
700
|
+
})
|
|
701
|
+
if err != nil {
|
|
702
|
+
t.Fatal(err)
|
|
703
|
+
}
|
|
704
|
+
return count
|
|
705
|
+
}
|