Skip to content

Commit

Permalink
cue/load: add initial module.cue schema
Browse files Browse the repository at this point in the history
This adds the module.cue file format definition and verifies against it
when loading the configuration. We only add the existing single `module`
field for now.

I've added some tests that show the errors resulting from a bad module.cue
file look reasonable, which necessitated reshuffling the existing
test data around a bit.

Signed-off-by: Roger Peppe <rogpeppe@gmail.com>
Change-Id: I7339b96df9c195eeb02fda5197e790d15a6aad1d
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/549008
Unity-Result: CUEcueckoo <cueckoo@cuelang.org>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
  • Loading branch information
rogpeppe committed Feb 8, 2023
1 parent ce37b63 commit b2087b9
Show file tree
Hide file tree
Showing 29 changed files with 229 additions and 134 deletions.
62 changes: 7 additions & 55 deletions cue/load/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,11 @@ import (
"path/filepath"
"strings"

"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/errors"
"cuelang.org/go/cue/parser"
"cuelang.org/go/cue/token"
"cuelang.org/go/internal"
"cuelang.org/go/internal/core/runtime"
)

const (
Expand Down Expand Up @@ -143,6 +140,12 @@ type Config struct {
// the module field of an existing cue.mod file.
Module string

// modFile holds the contents of the module file, or nil
// if no module file was present. If non-nil, then
// after calling Config.complete, modFile.Module will be
// equal to Module.
modFile *modFile

// Package defines the name of the package to be loaded. If this is not set,
// the package must be uniquely defined from its context. Special values:
// _ load files without a package
Expand Down Expand Up @@ -518,7 +521,7 @@ func (c Config) complete() (cfg *Config, err error) {
} else if !filepath.IsAbs(c.ModuleRoot) {
c.ModuleRoot = filepath.Join(c.Dir, c.ModuleRoot)
}
if err := c.completeModule(); err != nil {
if err := c.loadModule(); err != nil {
return nil, err
}
c.loader = &loader{
Expand All @@ -536,57 +539,6 @@ func (c Config) complete() (cfg *Config, err error) {
return &c, nil
}

// completeModule fills out c.Module if it's empty or checks it for
// consistency with the module file otherwise.
func (c *Config) completeModule() error {
// TODO: also make this work if run from outside the module?
mod := filepath.Join(c.ModuleRoot, modDir)
info, cerr := c.fileSystem.stat(mod)
if cerr != nil {
return nil
}
// TODO remove support for legacy non-directory module.cue file
// by returning an error if info.IsDir is false.
if info.IsDir() {
mod = filepath.Join(mod, moduleFile)
}
f, cerr := c.fileSystem.openFile(mod)
if cerr != nil {
return nil
}
defer f.Close()

// TODO: move to full build again
file, err := parser.ParseFile("load", f)
if err != nil {
return errors.Wrapf(err, token.NoPos, "invalid cue.mod file")
}
// TODO disallow non-data-mode CUE.

ctx := (*cue.Context)(runtime.New())
v := ctx.BuildFile(file)
if err := v.Validate(); err != nil {
return errors.Wrapf(err, token.NoPos, "invalid cue.mod file")
}
prefix := v.LookupPath(cue.MakePath(cue.Str("module")))
if prefix.Err() != nil {
// TODO check better for not-found?
return nil
}
name, err := prefix.String()
if err != nil {
return err
}
if c.Module == "" {
c.Module = name
return nil
}
if c.Module == name {
return nil
}
return errors.Newf(prefix.Pos(), "inconsistent modules: got %q, want %q", name, c.Module)
}

func (c Config) isRoot(dir string) bool {
fs := &c.fileSystem
// Note: cue.mod used to be a file. We still allow both to match.
Expand Down
19 changes: 14 additions & 5 deletions cue/load/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,21 @@ package load

import (
"os"
"path/filepath"
"reflect"
"testing"

"cuelang.org/go/cue/build"
"cuelang.org/go/cue/token"
)

const testdata = "./testdata/"
func testMod(dir string) string {
cwd, err := os.Getwd()
if err != nil {
panic(err)
}
return filepath.Join(cwd, "testdata", dir)
}

func getInst(pkg, cwd string) (*build.Instance, error) {
c, _ := (&Config{Dir: cwd}).complete()
Expand All @@ -50,17 +57,19 @@ func TestEmptyImport(t *testing.T) {
}

func TestEmptyFolderImport(t *testing.T) {
_, err := getInst(".", testdata+"empty")
path := filepath.Join(testMod("testmod"), "empty")
_, err := getInst(".", path)
if _, ok := err.(*NoFilesError); !ok {
t.Fatal(`Import("testdata/empty") did not return NoCUEError.`)
t.Fatalf(`Import(%q) did not return NoCUEError.`, path)
}
}

func TestMultiplePackageImport(t *testing.T) {
_, err := getInst(".", testdata+"multi")
path := filepath.Join(testMod("testmod"), "multi")
_, err := getInst(".", path)
mpe, ok := err.(*MultiplePackageError)
if !ok {
t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`)
t.Fatalf(`Import(%q) did not return MultiplePackageError.`, path)
}
mpe.Dir = ""
want := &MultiplePackageError{
Expand Down
Loading

0 comments on commit b2087b9

Please sign in to comment.