Skip to content

Commit b4583de

Browse files
committed
internal/cueexperiment: parse CUE_EXPERIMENT
This allows code the cue command to enable experimentation with new features, and modules in particular to start with. In the future, this API might be adapted to allow enabling experimental features in the Go API too, but for now it's firmly oriented towards the top level cue command. Signed-off-by: Roger Peppe <[email protected]> Change-Id: I76d5c9343bd791ae0ff9ef39fdf7af9dec5c2d8f Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1168930 Reviewed-by: Daniel Martí <[email protected]> Reviewed-by: Paul Jolly <[email protected]> TryBot-Result: CUEcueckoo <[email protected]>
1 parent b951b07 commit b4583de

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed

cmd/cue/cmd/root.go

+5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"cuelang.org/go/cue/interpreter/wasm"
3030
"cuelang.org/go/cue/stats"
3131
"cuelang.org/go/internal/core/adt"
32+
"cuelang.org/go/internal/cueexperiment"
3233
"cuelang.org/go/internal/encoding"
3334
"cuelang.org/go/internal/filetypes"
3435
)
@@ -84,6 +85,10 @@ func mkRunE(c *Command, f runFunction) func(*cobra.Command, []string) error {
8485

8586
statsEnc := statsEncoder(c)
8687

88+
if err := cueexperiment.Init(); err != nil {
89+
return err
90+
}
91+
8792
err := f(c, args)
8893

8994
if statsEnc != nil {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
env CUE_EXPERIMENT=xxx
2+
! exec cue eval something
3+
stderr 'unknown CUE_EXPERIMENT xxx'

internal/cueexperiment/exp.go

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package cueexperiment
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"reflect"
7+
"strings"
8+
)
9+
10+
// Flags holds the set of CUE_EXPERIMENT flags. It is initialized
11+
// by Init.
12+
var Flags struct {
13+
Modules bool
14+
}
15+
16+
// Init initializes Flags. Note: this isn't named "init" because we
17+
// don't always want it to be called (for example we don't want it to be
18+
// called when running "cue help"), and also because we want the failure
19+
// mode to be one of error not panic, which would be the only option if
20+
// it was a top level init function
21+
func Init() error {
22+
exp := os.Getenv("CUE_EXPERIMENT")
23+
if exp == "" {
24+
return nil
25+
}
26+
names := make(map[string]int)
27+
fv := reflect.ValueOf(&Flags).Elem()
28+
ft := fv.Type()
29+
for i := 0; i < ft.NumField(); i++ {
30+
names[strings.ToLower(ft.Field(i).Name)] = i
31+
}
32+
for _, uexp := range strings.Split(exp, ",") {
33+
index, ok := names[uexp]
34+
if !ok {
35+
return fmt.Errorf("unknown CUE_EXPERIMENT %s", uexp)
36+
}
37+
fv.Field(index).SetBool(true)
38+
}
39+
return nil
40+
}

internal/cueexperiment/exp_test.go

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package cueexperiment
2+
3+
import (
4+
"testing"
5+
6+
"github.com/go-quicktest/qt"
7+
)
8+
9+
var tests = []struct {
10+
testName string
11+
cueExperiment string
12+
flagVal *bool
13+
want bool
14+
wantError string
15+
}{{
16+
testName: "Empty",
17+
cueExperiment: "",
18+
flagVal: &Flags.Modules,
19+
want: false,
20+
}, {
21+
testName: "Unknown",
22+
cueExperiment: "foo",
23+
flagVal: &Flags.Modules,
24+
wantError: "unknown CUE_EXPERIMENT foo",
25+
}, {
26+
testName: "Set",
27+
cueExperiment: "modules",
28+
flagVal: &Flags.Modules,
29+
want: true,
30+
}, {
31+
testName: "SetTwice",
32+
cueExperiment: "modules,modules",
33+
flagVal: &Flags.Modules,
34+
want: true,
35+
}, {
36+
testName: "SetWithUnknown",
37+
cueExperiment: "modules,other",
38+
flagVal: &Flags.Modules,
39+
wantError: "unknown CUE_EXPERIMENT other",
40+
}}
41+
42+
func TestInit(t *testing.T) {
43+
for _, test := range tests {
44+
t.Run(test.testName, func(t *testing.T) {
45+
setZero(&Flags)
46+
t.Setenv("CUE_EXPERIMENT", test.cueExperiment)
47+
err := Init()
48+
if test.wantError != "" {
49+
qt.Assert(t, qt.ErrorMatches(err, test.wantError))
50+
return
51+
}
52+
qt.Assert(t, qt.IsNil(err))
53+
qt.Assert(t, qt.Equals(*test.flagVal, test.want))
54+
})
55+
}
56+
}
57+
58+
func setZero[T any](x *T) {
59+
*x = *new(T)
60+
}

0 commit comments

Comments
 (0)